rtc_rtp/codecs/vp9/
mod.rs

1#[cfg(test)]
2mod vp9_test;
3
4use crate::packetizer::{Depacketizer, Payloader};
5use shared::error::{Error, Result};
6
7use bytes::{Buf, BufMut, Bytes, BytesMut};
8use std::fmt;
9use std::sync::Arc;
10
11/// Flexible mode 15 bit picture ID
12const VP9HEADER_SIZE: usize = 3;
13const MAX_SPATIAL_LAYERS: u8 = 5;
14const MAX_VP9REF_PICS: usize = 3;
15
16/// InitialPictureIDFn is a function that returns random initial picture ID.
17pub type InitialPictureIDFn = Arc<dyn (Fn() -> u16)>;
18
19/// Vp9Payloader payloads VP9 packets
20#[derive(Default, Clone)]
21pub struct Vp9Payloader {
22    picture_id: u16,
23    initialized: bool,
24
25    pub initial_picture_id_fn: Option<InitialPictureIDFn>,
26}
27
28impl fmt::Debug for Vp9Payloader {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        f.debug_struct("Vp9Payloader")
31            .field("picture_id", &self.picture_id)
32            .field("initialized", &self.initialized)
33            .finish()
34    }
35}
36
37impl Payloader for Vp9Payloader {
38    /// Payload fragments an Vp9Payloader packet across one or more byte arrays
39    fn payload(&mut self, mtu: usize, payload: &Bytes) -> Result<Vec<Bytes>> {
40        /*
41         * https://www.ietf.org/id/draft-ietf-payload-vp9-13.txt
42         *
43         * Flexible mode (F=1)
44         *        0 1 2 3 4 5 6 7
45         *       +-+-+-+-+-+-+-+-+
46         *       |I|P|L|F|B|E|V|Z| (REQUIRED)
47         *       +-+-+-+-+-+-+-+-+
48         *  I:   |M| PICTURE ID  | (REQUIRED)
49         *       +-+-+-+-+-+-+-+-+
50         *  M:   | EXTENDED PID  | (RECOMMENDED)
51         *       +-+-+-+-+-+-+-+-+
52         *  L:   | tid |U| SID |D| (CONDITIONALLY RECOMMENDED)
53         *       +-+-+-+-+-+-+-+-+                             -\
54         *  P,F: | P_DIFF      |N| (CONDITIONALLY REQUIRED)    - up to 3 times
55         *       +-+-+-+-+-+-+-+-+                             -/
56         *  V:   | SS            |
57         *       | ..            |
58         *       +-+-+-+-+-+-+-+-+
59         *
60         * Non-flexible mode (F=0)
61         *        0 1 2 3 4 5 6 7
62         *       +-+-+-+-+-+-+-+-+
63         *       |I|P|L|F|B|E|V|Z| (REQUIRED)
64         *       +-+-+-+-+-+-+-+-+
65         *  I:   |M| PICTURE ID  | (RECOMMENDED)
66         *       +-+-+-+-+-+-+-+-+
67         *  M:   | EXTENDED PID  | (RECOMMENDED)
68         *       +-+-+-+-+-+-+-+-+
69         *  L:   | tid |U| SID |D| (CONDITIONALLY RECOMMENDED)
70         *       +-+-+-+-+-+-+-+-+
71         *       |   tl0picidx   | (CONDITIONALLY REQUIRED)
72         *       +-+-+-+-+-+-+-+-+
73         *  V:   | SS            |
74         *       | ..            |
75         *       +-+-+-+-+-+-+-+-+
76         */
77
78        if payload.is_empty() || mtu == 0 {
79            return Ok(vec![]);
80        }
81
82        if !self.initialized {
83            if self.initial_picture_id_fn.is_none() {
84                self.initial_picture_id_fn =
85                    Some(Arc::new(|| -> u16 { rand::random::<u16>() & 0x7FFF }));
86            }
87            self.picture_id = if let Some(f) = &self.initial_picture_id_fn {
88                f()
89            } else {
90                0
91            };
92            self.initialized = true;
93        }
94
95        let max_fragment_size = mtu as isize - VP9HEADER_SIZE as isize;
96        let mut payloads = vec![];
97        let mut payload_data_remaining = payload.len();
98        let mut payload_data_index = 0;
99
100        if std::cmp::min(max_fragment_size, payload_data_remaining as isize) <= 0 {
101            return Ok(vec![]);
102        }
103
104        while payload_data_remaining > 0 {
105            let current_fragment_size =
106                std::cmp::min(max_fragment_size as usize, payload_data_remaining);
107            let mut out = BytesMut::with_capacity(VP9HEADER_SIZE + current_fragment_size);
108            let mut buf = [0u8; VP9HEADER_SIZE];
109            buf[0] = 0x90; // F=1 I=1
110            if payload_data_index == 0 {
111                buf[0] |= 0x08; // B=1
112            }
113            if payload_data_remaining == current_fragment_size {
114                buf[0] |= 0x04; // E=1
115            }
116            buf[1] = (self.picture_id >> 8) as u8 | 0x80;
117            buf[2] = (self.picture_id & 0xFF) as u8;
118
119            out.put(&buf[..]);
120
121            out.put(
122                &*payload.slice(payload_data_index..payload_data_index + current_fragment_size),
123            );
124
125            payloads.push(out.freeze());
126
127            payload_data_remaining -= current_fragment_size;
128            payload_data_index += current_fragment_size;
129        }
130
131        self.picture_id += 1;
132        self.picture_id &= 0x7FFF;
133
134        Ok(payloads)
135    }
136
137    fn clone_to(&self) -> Box<dyn Payloader> {
138        Box::new(self.clone())
139    }
140}
141
142/// Vp9Packet represents the VP9 header that is stored in the payload of an RTP Packet
143#[derive(PartialEq, Eq, Debug, Default, Clone)]
144pub struct Vp9Packet {
145    /// picture ID is present
146    pub i: bool,
147    /// inter-picture predicted frame.
148    pub p: bool,
149    /// layer indices present
150    pub l: bool,
151    /// flexible mode
152    pub f: bool,
153    /// start of frame. beginning of new vp9 frame
154    pub b: bool,
155    /// end of frame
156    pub e: bool,
157    /// scalability structure (SS) present
158    pub v: bool,
159    /// Not a reference frame for upper spatial layers
160    pub z: bool,
161
162    /// Recommended headers
163    /// 7 or 16 bits, picture ID.
164    pub picture_id: u16,
165
166    /// Conditionally recommended headers
167    /// Temporal layer ID
168    pub tid: u8,
169    /// Switching up point
170    pub u: bool,
171    /// Spatial layer ID
172    pub sid: u8,
173    /// Inter-layer dependency used
174    pub d: bool,
175
176    /// Conditionally required headers
177    /// Reference index (F=1)
178    pub pdiff: Vec<u8>,
179    /// Temporal layer zero index (F=0)
180    pub tl0picidx: u8,
181
182    /// Scalability structure headers
183    /// N_S + 1 indicates the number of spatial layers present in the VP9 stream
184    pub ns: u8,
185    /// Each spatial layer's frame resolution present
186    pub y: bool,
187    /// PG description present flag.
188    pub g: bool,
189    /// N_G indicates the number of pictures in a Picture Group (PG)
190    pub ng: u8,
191    pub width: Vec<u16>,
192    pub height: Vec<u16>,
193    /// Temporal layer ID of pictures in a Picture Group
194    pub pgtid: Vec<u8>,
195    /// Switching up point of pictures in a Picture Group
196    pub pgu: Vec<bool>,
197    /// Reference indecies of pictures in a Picture Group
198    pub pgpdiff: Vec<Vec<u8>>,
199}
200
201impl Depacketizer for Vp9Packet {
202    /// depacketize parses the passed byte slice and stores the result in the Vp9Packet this method is called upon
203    fn depacketize(&mut self, packet: &Bytes) -> Result<Bytes> {
204        if packet.is_empty() {
205            return Err(Error::ErrShortPacket);
206        }
207
208        let reader = &mut packet.clone();
209        let b = reader.get_u8();
210
211        self.i = (b & 0x80) != 0;
212        self.p = (b & 0x40) != 0;
213        self.l = (b & 0x20) != 0;
214        self.f = (b & 0x10) != 0;
215        self.b = (b & 0x08) != 0;
216        self.e = (b & 0x04) != 0;
217        self.v = (b & 0x02) != 0;
218        self.z = (b & 0x01) != 0;
219
220        let mut payload_index = 1;
221
222        if self.i {
223            payload_index = self.parse_picture_id(reader, payload_index)?;
224        }
225
226        if self.l {
227            payload_index = self.parse_layer_info(reader, payload_index)?;
228        }
229
230        if self.f && self.p {
231            payload_index = self.parse_ref_indices(reader, payload_index)?;
232        }
233
234        if self.v {
235            payload_index = self.parse_ssdata(reader, payload_index)?;
236        }
237
238        Ok(packet.slice(payload_index..))
239    }
240
241    /// is_partition_head checks whether if this is a head of the VP9 partition
242    fn is_partition_head(&self, payload: &Bytes) -> bool {
243        if payload.is_empty() {
244            false
245        } else {
246            (payload[0] & 0x08) != 0
247        }
248    }
249
250    fn is_partition_tail(&self, marker: bool, _payload: &Bytes) -> bool {
251        marker
252    }
253}
254
255impl Vp9Packet {
256    // Picture ID:
257    //
258    //      +-+-+-+-+-+-+-+-+
259    // I:   |M| PICTURE ID  |   M:0 => picture id is 7 bits.
260    //      +-+-+-+-+-+-+-+-+   M:1 => picture id is 15 bits.
261    // M:   | EXTENDED PID  |
262    //      +-+-+-+-+-+-+-+-+
263    //
264    fn parse_picture_id(
265        &mut self,
266        reader: &mut dyn Buf,
267        mut payload_index: usize,
268    ) -> Result<usize> {
269        if reader.remaining() == 0 {
270            return Err(Error::ErrShortPacket);
271        }
272        let b = reader.get_u8();
273        payload_index += 1;
274        // PID present?
275        if (b & 0x80) != 0 {
276            if reader.remaining() == 0 {
277                return Err(Error::ErrShortPacket);
278            }
279            // M == 1, PID is 15bit
280            self.picture_id = (((b & 0x7f) as u16) << 8) | (reader.get_u8() as u16);
281            payload_index += 1;
282        } else {
283            self.picture_id = (b & 0x7F) as u16;
284        }
285
286        Ok(payload_index)
287    }
288
289    fn parse_layer_info(
290        &mut self,
291        reader: &mut dyn Buf,
292        mut payload_index: usize,
293    ) -> Result<usize> {
294        payload_index = self.parse_layer_info_common(reader, payload_index)?;
295
296        if self.f {
297            Ok(payload_index)
298        } else {
299            self.parse_layer_info_non_flexible_mode(reader, payload_index)
300        }
301    }
302
303    // Layer indices (flexible mode):
304    //
305    //      +-+-+-+-+-+-+-+-+
306    // L:   |  T  |U|  S  |D|
307    //      +-+-+-+-+-+-+-+-+
308    //
309    fn parse_layer_info_common(
310        &mut self,
311        reader: &mut dyn Buf,
312        mut payload_index: usize,
313    ) -> Result<usize> {
314        if reader.remaining() == 0 {
315            return Err(Error::ErrShortPacket);
316        }
317        let b = reader.get_u8();
318        payload_index += 1;
319
320        self.tid = b >> 5;
321        self.u = b & 0x10 != 0;
322        self.sid = (b >> 1) & 0x7;
323        self.d = b & 0x01 != 0;
324
325        if self.sid >= MAX_SPATIAL_LAYERS {
326            Err(Error::ErrTooManySpatialLayers)
327        } else {
328            Ok(payload_index)
329        }
330    }
331
332    // Layer indices (non-flexible mode):
333    //
334    //      +-+-+-+-+-+-+-+-+
335    // L:   |  T  |U|  S  |D|
336    //      +-+-+-+-+-+-+-+-+
337    //      |   tl0picidx   |
338    //      +-+-+-+-+-+-+-+-+
339    //
340    fn parse_layer_info_non_flexible_mode(
341        &mut self,
342        reader: &mut dyn Buf,
343        mut payload_index: usize,
344    ) -> Result<usize> {
345        if reader.remaining() == 0 {
346            return Err(Error::ErrShortPacket);
347        }
348        self.tl0picidx = reader.get_u8();
349        payload_index += 1;
350        Ok(payload_index)
351    }
352
353    // Reference indices:
354    //
355    //      +-+-+-+-+-+-+-+-+                P=1,F=1: At least one reference index
356    // P,F: | P_DIFF      |N|  up to 3 times          has to be specified.
357    //      +-+-+-+-+-+-+-+-+                    N=1: An additional P_DIFF follows
358    //                                                current P_DIFF.
359    //
360    fn parse_ref_indices(
361        &mut self,
362        reader: &mut dyn Buf,
363        mut payload_index: usize,
364    ) -> Result<usize> {
365        let mut b = 1u8;
366        while (b & 0x1) != 0 {
367            if reader.remaining() == 0 {
368                return Err(Error::ErrShortPacket);
369            }
370            b = reader.get_u8();
371            payload_index += 1;
372
373            self.pdiff.push(b >> 1);
374            if self.pdiff.len() >= MAX_VP9REF_PICS {
375                return Err(Error::ErrTooManyPDiff);
376            }
377        }
378
379        Ok(payload_index)
380    }
381
382    // Scalability structure (SS):
383    //
384    //      +-+-+-+-+-+-+-+-+
385    // V:   | N_S |Y|G|-|-|-|
386    //      +-+-+-+-+-+-+-+-+              -|
387    // Y:   |     WIDTH     | (OPTIONAL)    .
388    //      +               +               .
389    //      |               | (OPTIONAL)    .
390    //      +-+-+-+-+-+-+-+-+               . N_S + 1 times
391    //      |     HEIGHT    | (OPTIONAL)    .
392    //      +               +               .
393    //      |               | (OPTIONAL)    .
394    //      +-+-+-+-+-+-+-+-+              -|
395    // G:   |      N_G      | (OPTIONAL)
396    //      +-+-+-+-+-+-+-+-+                           -|
397    // N_G: |  T  |U| R |-|-| (OPTIONAL)                 .
398    //      +-+-+-+-+-+-+-+-+              -|            . N_G times
399    //      |    P_DIFF     | (OPTIONAL)    . R times    .
400    //      +-+-+-+-+-+-+-+-+              -|           -|
401    //
402    fn parse_ssdata(&mut self, reader: &mut dyn Buf, mut payload_index: usize) -> Result<usize> {
403        if reader.remaining() == 0 {
404            return Err(Error::ErrShortPacket);
405        }
406
407        let b = reader.get_u8();
408        payload_index += 1;
409
410        self.ns = b >> 5;
411        self.y = b & 0x10 != 0;
412        self.g = (b >> 1) & 0x7 != 0;
413
414        let ns = (self.ns + 1) as usize;
415        self.ng = 0;
416
417        if self.y {
418            if reader.remaining() < 4 * ns {
419                return Err(Error::ErrShortPacket);
420            }
421
422            self.width = vec![0u16; ns];
423            self.height = vec![0u16; ns];
424            for i in 0..ns {
425                self.width[i] = reader.get_u16();
426                self.height[i] = reader.get_u16();
427            }
428            payload_index += 4 * ns;
429        }
430
431        if self.g {
432            if reader.remaining() == 0 {
433                return Err(Error::ErrShortPacket);
434            }
435
436            self.ng = reader.get_u8();
437            payload_index += 1;
438        }
439
440        for i in 0..self.ng as usize {
441            if reader.remaining() == 0 {
442                return Err(Error::ErrShortPacket);
443            }
444            let b = reader.get_u8();
445            payload_index += 1;
446
447            self.pgtid.push(b >> 5);
448            self.pgu.push(b & 0x10 != 0);
449
450            let r = ((b >> 2) & 0x3) as usize;
451            if reader.remaining() < r {
452                return Err(Error::ErrShortPacket);
453            }
454
455            self.pgpdiff.push(vec![]);
456            for _ in 0..r {
457                let b = reader.get_u8();
458                payload_index += 1;
459
460                self.pgpdiff[i].push(b);
461            }
462        }
463
464        Ok(payload_index)
465    }
466}