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