1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
//! VP9 payload format handler
//!
//! This module implements payload format handling for VP9 video according to RFC 8741.
use bytes::{Bytes, BytesMut, Buf, BufMut};
use std::any::Any;
use super::traits::PayloadFormat;
/// VP9 payload header descriptor flags
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Vp9DescriptorFlags {
/// I (picture ID) present
i: bool,
/// P (inter-picture predicted frame) present
p: bool,
/// L (layer indices) present
l: bool,
/// F (flexible mode) present
f: bool,
/// B (start of a frame) present
b: bool,
/// E (end of a frame) present
e: bool,
/// V (scalability structure) present
v: bool,
}
/// VP9 payload format handler
///
/// This implements VP9 payload format according to RFC 8741.
/// VP9 is a video codec developed by Google.
pub struct Vp9PayloadFormat {
/// Clock rate for RTP timestamps (90kHz default for video)
clock_rate: u32,
/// Payload type (dynamic, typically 96-127)
payload_type: u8,
/// Descriptor flags
descriptor_flags: Vp9DescriptorFlags,
/// Maximum frame rate (used for packet size estimation)
max_frame_rate: u32,
/// Average bitrate for packet size estimation
average_bitrate: u32,
}
impl Vp9PayloadFormat {
/// Create a new VP9 payload format handler
pub fn new(payload_type: u8) -> Self {
Self {
// Default clock rate for video is 90kHz
clock_rate: 90000,
payload_type,
descriptor_flags: Vp9DescriptorFlags {
i: true, // Picture ID present
p: false, // Inter-picture predicted frame flag
l: true, // Layer indices present
f: false, // Flexible mode
b: true, // Start of frame
e: true, // End of frame
v: false, // Scalability structure
},
max_frame_rate: 30,
average_bitrate: 1_500_000, // 1.5 Mbps default
}
}
/// Set the picture ID present flag
pub fn with_picture_id(mut self, present: bool) -> Self {
self.descriptor_flags.i = present;
self
}
/// Set the layer indices present flag
pub fn with_layer_indices(mut self, present: bool) -> Self {
self.descriptor_flags.l = present;
self
}
/// Set the flexible mode flag
pub fn with_flexible_mode(mut self, flexible: bool) -> Self {
self.descriptor_flags.f = flexible;
self
}
/// Set the average bitrate for packet size estimation
pub fn with_bitrate(mut self, bitrate: u32) -> Self {
self.average_bitrate = bitrate;
self
}
/// Set the maximum frame rate
pub fn with_frame_rate(mut self, frame_rate: u32) -> Self {
self.max_frame_rate = frame_rate;
self
}
/// Calculate the descriptor size based on configuration
pub fn descriptor_size(&self) -> usize {
let mut size = 1; // First octet (mandatory)
if self.descriptor_flags.i {
size += 1; // Picture ID (7 bits)
// For simplicity, we'll assume extended picture ID (15 bits)
// is used for all picture IDs
size += 1;
}
if self.descriptor_flags.l {
size += 1; // L header
}
if self.descriptor_flags.v {
// Scalability structure
size += 1; // V header
// For simplicity, we'll assume a minimal SS with
// no additional bytes for pattern, layers, etc.
}
size
}
/// Parse a VP9 RTP payload descriptor from a buffer
fn parse_descriptor(buffer: &[u8]) -> Option<(usize, bool, bool)> {
if buffer.is_empty() {
return None;
}
// Parse the first byte (required)
let i = (buffer[0] & 0x80) != 0; // Picture ID present
let p = (buffer[0] & 0x40) != 0; // Reference frame
let l = (buffer[0] & 0x20) != 0; // Layer indices present
let f = (buffer[0] & 0x10) != 0; // Flexible mode
let b = (buffer[0] & 0x08) != 0; // Start of a frame
let e = (buffer[0] & 0x04) != 0; // End of a frame
let v = (buffer[0] & 0x02) != 0; // Scalability structure
let mut offset = 1;
// Picture ID (PID)
if i && buffer.len() > offset {
if (buffer[offset] & 0x80) != 0 {
// 15-bit picture ID
offset += 2;
} else {
// 7-bit picture ID
offset += 1;
}
}
// Layer indices (TID, SID)
if l && buffer.len() > offset {
offset += 1;
}
// Reference indices
if p && buffer.len() > offset {
// Skip reference indices
let refs_p = buffer[offset] & 0x0F;
offset += 1;
// Skip additional bytes for reference indices
offset += refs_p as usize;
}
// Scalability structure
if v && buffer.len() > offset {
// Parse SS header
let pattern_count = (buffer[offset] >> 5) & 0x07;
offset += 1;
// Skip pattern values
offset += pattern_count as usize;
// Check for additional bytes
if buffer.len() > offset {
let layers = buffer[offset] & 0x3F;
offset += 1;
// Skip layer information
offset += 3 * layers as usize;
}
}
Some((offset, b, e))
}
}
impl PayloadFormat for Vp9PayloadFormat {
fn payload_type(&self) -> u8 {
self.payload_type
}
fn clock_rate(&self) -> u32 {
self.clock_rate
}
fn channels(&self) -> u8 {
1 // Video has only one "channel"
}
fn preferred_packet_duration(&self) -> u32 {
// For video, this is the frame duration in milliseconds
let frame_duration = 1000 / self.max_frame_rate;
frame_duration
}
fn packet_size_from_duration(&self, duration_ms: u32) -> usize {
// Estimate based on average bitrate and duration
// For video, packetization often happens based on MTU rather than duration
// but we'll use a simple estimate here
let descriptor_size = self.descriptor_size();
let max_bytes = (self.average_bitrate * duration_ms) / (8 * 1000);
// Add descriptor size to the payload size
(max_bytes as usize) + descriptor_size
}
fn duration_from_packet_size(&self, packet_size: usize) -> u32 {
// This is a rough estimate for video
let descriptor_size = self.descriptor_size();
let payload_size = packet_size.saturating_sub(descriptor_size);
let bits = payload_size as u32 * 8;
(bits * 1000) / self.average_bitrate
}
fn pack(&self, media_data: &[u8], timestamp: u32) -> Bytes {
let descriptor_size = self.descriptor_size();
let mut buffer = BytesMut::with_capacity(descriptor_size + media_data.len());
// Create VP9 RTP payload descriptor (first byte)
let mut first_byte = 0u8;
if self.descriptor_flags.i {
first_byte |= 0x80; // I bit
}
if self.descriptor_flags.p {
first_byte |= 0x40; // P bit
}
if self.descriptor_flags.l {
first_byte |= 0x20; // L bit
}
if self.descriptor_flags.f {
first_byte |= 0x10; // F bit
}
if self.descriptor_flags.b {
first_byte |= 0x08; // B bit
}
if self.descriptor_flags.e {
first_byte |= 0x04; // E bit
}
if self.descriptor_flags.v {
first_byte |= 0x02; // V bit
}
buffer.put_u8(first_byte);
// Picture ID (if present)
if self.descriptor_flags.i {
// Use 15-bit picture ID derived from timestamp
// In a real implementation, this would be managed with a proper counter
let picture_id = (timestamp % 32768) as u16;
buffer.put_u8((picture_id >> 8) as u8 | 0x80); // High bit set for 15-bit ID
buffer.put_u8(picture_id as u8);
}
// Layer indices (if present)
if self.descriptor_flags.l {
// For simplicity, use zero indices
buffer.put_u8(0);
}
// Scalability structure (if present)
if self.descriptor_flags.v {
// For simplicity, add a minimal SS
buffer.put_u8(0);
}
// Add the VP9 payload
buffer.extend_from_slice(media_data);
buffer.freeze()
}
fn unpack(&self, payload: &[u8], _timestamp: u32) -> Bytes {
if payload.is_empty() {
return Bytes::new();
}
// Parse the VP9 payload descriptor
if let Some((offset, _start_of_frame, _end_of_frame)) = Self::parse_descriptor(payload) {
// Extract the actual VP9 payload data (skipping the descriptor)
if offset < payload.len() {
return Bytes::copy_from_slice(&payload[offset..]);
}
}
// Fallback to returning the whole payload if parsing fails
Bytes::copy_from_slice(payload)
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vp9_payload_format() {
// Create a VP9 format with dynamic PT 97
let format = Vp9PayloadFormat::new(97)
.with_picture_id(true)
.with_layer_indices(true)
.with_flexible_mode(false)
.with_bitrate(3_000_000) // 3 Mbps
.with_frame_rate(60);
assert_eq!(format.payload_type(), 97);
assert_eq!(format.clock_rate(), 90000);
assert_eq!(format.channels(), 1);
assert_eq!(format.preferred_packet_duration(), 16); // ~16ms for 60fps
// Clock rate = 90kHz, so 16ms = 1440 samples
assert_eq!(format.samples_from_duration(16), 1440);
// Test packet size calculations
// 16ms of VP9 at 3Mbps = ~6KB + descriptor size
let expected_size = format.packet_size_from_duration(16);
assert_eq!(expected_size, 6004);
// Test packing
let test_data = vec![0u8; 100];
let packed = format.pack(&test_data, 5678);
// Expected size with descriptor
assert_eq!(packed.len(), 100 + format.descriptor_size());
// Test unpacking
let unpacked = format.unpack(&packed, 5678);
assert_eq!(unpacked.len(), 100);
}
#[test]
fn test_vp9_descriptor_parsing() {
// Test basic descriptor
let basic_desc = vec![0x08, 0x01, 0x02, 0x03];
let (offset, is_start, is_end) = Vp9PayloadFormat::parse_descriptor(&basic_desc).unwrap();
assert_eq!(offset, 1);
assert_eq!(is_start, true);
assert_eq!(is_end, false);
// Test descriptor with picture ID and layer indices
let ext_desc = vec![0xA8, 0x81, 0x23, 0x00, 0x01, 0x02, 0x03];
let (offset, is_start, is_end) = Vp9PayloadFormat::parse_descriptor(&ext_desc).unwrap();
assert_eq!(offset, 4);
assert_eq!(is_start, true);
assert_eq!(is_end, false);
}
}