Skip to main content

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