xref: /webrtc/rtp/src/codecs/vp8/mod.rs (revision ffe74184)
1 #[cfg(test)]
2 mod vp8_test;
3 
4 use crate::{
5     error::{Error, Result},
6     packetizer::{Depacketizer, Payloader},
7 };
8 
9 use bytes::{Buf, BufMut, Bytes, BytesMut};
10 
11 pub const VP8_HEADER_SIZE: usize = 1;
12 
13 /// Vp8Payloader payloads VP8 packets
14 #[derive(Default, Debug, Copy, Clone)]
15 pub struct Vp8Payloader {
16     pub enable_picture_id: bool,
17     picture_id: u16,
18 }
19 
20 impl Payloader for Vp8Payloader {
21     /// Payload fragments a VP8 packet across one or more byte arrays
payload(&mut self, mtu: usize, payload: &Bytes) -> Result<Vec<Bytes>>22     fn payload(&mut self, mtu: usize, payload: &Bytes) -> Result<Vec<Bytes>> {
23         if payload.is_empty() || mtu == 0 {
24             return Ok(vec![]);
25         }
26 
27         /*
28          * https://tools.ietf.org/html/rfc7741#section-4.2
29          *
30          *       0 1 2 3 4 5 6 7
31          *      +-+-+-+-+-+-+-+-+
32          *      |X|R|N|S|R| PID | (REQUIRED)
33          *      +-+-+-+-+-+-+-+-+
34          * X:   |I|L|T|K| RSV   | (OPTIONAL)
35          *      +-+-+-+-+-+-+-+-+
36          * I:   |M| PictureID   | (OPTIONAL)
37          *      +-+-+-+-+-+-+-+-+
38          * L:   |   tl0picidx   | (OPTIONAL)
39          *      +-+-+-+-+-+-+-+-+
40          * T/K: |tid|Y| KEYIDX  | (OPTIONAL)
41          *      +-+-+-+-+-+-+-+-+
42          *  S: Start of VP8 partition.  SHOULD be set to 1 when the first payload
43          *     octet of the RTP packet is the beginning of a new VP8 partition,
44          *     and MUST NOT be 1 otherwise.  The S bit MUST be set to 1 for the
45          *     first packet of each encoded frame.
46          */
47         let using_header_size = if self.enable_picture_id {
48             if self.picture_id == 0 || self.picture_id < 128 {
49                 VP8_HEADER_SIZE + 2
50             } else {
51                 VP8_HEADER_SIZE + 3
52             }
53         } else {
54             VP8_HEADER_SIZE
55         };
56 
57         let max_fragment_size = mtu as isize - using_header_size as isize;
58         let mut payload_data_remaining = payload.len() as isize;
59         let mut payload_data_index: usize = 0;
60         let mut payloads = vec![];
61 
62         // Make sure the fragment/payload size is correct
63         if std::cmp::min(max_fragment_size, payload_data_remaining) <= 0 {
64             return Ok(payloads);
65         }
66 
67         let mut first = true;
68         while payload_data_remaining > 0 {
69             let current_fragment_size =
70                 std::cmp::min(max_fragment_size, payload_data_remaining) as usize;
71             let mut out = BytesMut::with_capacity(using_header_size + current_fragment_size);
72             let mut buf = vec![0u8; 4];
73             if first {
74                 buf[0] = 0x10;
75                 first = false;
76             }
77 
78             if self.enable_picture_id {
79                 if using_header_size == VP8_HEADER_SIZE + 2 {
80                     buf[0] |= 0x80;
81                     buf[1] |= 0x80;
82                     buf[2] |= (self.picture_id & 0x7F) as u8;
83                 } else if using_header_size == VP8_HEADER_SIZE + 3 {
84                     buf[0] |= 0x80;
85                     buf[1] |= 0x80;
86                     buf[2] |= 0x80 | ((self.picture_id >> 8) & 0x7F) as u8;
87                     buf[3] |= (self.picture_id & 0xFF) as u8;
88                 }
89             }
90 
91             out.put(&buf[..using_header_size]);
92 
93             out.put(
94                 &*payload.slice(payload_data_index..payload_data_index + current_fragment_size),
95             );
96             payloads.push(out.freeze());
97 
98             payload_data_remaining -= current_fragment_size as isize;
99             payload_data_index += current_fragment_size;
100         }
101 
102         self.picture_id += 1;
103         self.picture_id &= 0x7FFF;
104 
105         Ok(payloads)
106     }
107 
clone_to(&self) -> Box<dyn Payloader + Send + Sync>108     fn clone_to(&self) -> Box<dyn Payloader + Send + Sync> {
109         Box::new(*self)
110     }
111 }
112 
113 /// Vp8Packet represents the VP8 header that is stored in the payload of an RTP Packet
114 #[derive(PartialEq, Eq, Debug, Default, Clone)]
115 pub struct Vp8Packet {
116     /// Required Header
117     /// extended controlbits present
118     pub x: u8,
119     /// when set to 1 this frame can be discarded
120     pub n: u8,
121     /// start of VP8 partition
122     pub s: u8,
123     /// partition index
124     pub pid: u8,
125 
126     /// Extended control bits
127     /// 1 if PictureID is present
128     pub i: u8,
129     /// 1 if tl0picidx is present
130     pub l: u8,
131     /// 1 if tid is present
132     pub t: u8,
133     /// 1 if KEYIDX is present
134     pub k: u8,
135 
136     /// Optional extension
137     /// 8 or 16 bits, picture ID
138     pub picture_id: u16,
139     /// 8 bits temporal level zero index
140     pub tl0_pic_idx: u8,
141     /// 2 bits temporal layer index
142     pub tid: u8,
143     /// 1 bit layer sync bit
144     pub y: u8,
145     /// 5 bits temporal key frame index
146     pub key_idx: u8,
147 }
148 
149 impl Depacketizer for Vp8Packet {
150     /// depacketize parses the passed byte slice and stores the result in the VP8Packet this method is called upon
depacketize(&mut self, packet: &Bytes) -> Result<Bytes>151     fn depacketize(&mut self, packet: &Bytes) -> Result<Bytes> {
152         let payload_len = packet.len();
153         if payload_len < 4 {
154             return Err(Error::ErrShortPacket);
155         }
156         //    0 1 2 3 4 5 6 7                      0 1 2 3 4 5 6 7
157         //    +-+-+-+-+-+-+-+-+                   +-+-+-+-+-+-+-+-+
158         //    |X|R|N|S|R| PID | (REQUIRED)        |X|R|N|S|R| PID | (REQUIRED)
159         //    +-+-+-+-+-+-+-+-+                   +-+-+-+-+-+-+-+-+
160         // X: |I|L|T|K| RSV   | (OPTIONAL)   X:   |I|L|T|K| RSV   | (OPTIONAL)
161         //    +-+-+-+-+-+-+-+-+                   +-+-+-+-+-+-+-+-+
162         // I: |M| PictureID   | (OPTIONAL)   I:   |M| PictureID   | (OPTIONAL)
163         //    +-+-+-+-+-+-+-+-+                   +-+-+-+-+-+-+-+-+
164         // L: |   tl0picidx   | (OPTIONAL)        |   PictureID   |
165         //    +-+-+-+-+-+-+-+-+                   +-+-+-+-+-+-+-+-+
166         //T/K:|tid|Y| KEYIDX  | (OPTIONAL)   L:   |   tl0picidx   | (OPTIONAL)
167         //    +-+-+-+-+-+-+-+-+                   +-+-+-+-+-+-+-+-+
168         //T/K:|tid|Y| KEYIDX  | (OPTIONAL)
169         //    +-+-+-+-+-+-+-+-+
170 
171         let reader = &mut packet.clone();
172         let mut payload_index = 0;
173 
174         let mut b = reader.get_u8();
175         payload_index += 1;
176 
177         self.x = (b & 0x80) >> 7;
178         self.n = (b & 0x20) >> 5;
179         self.s = (b & 0x10) >> 4;
180         self.pid = b & 0x07;
181 
182         if self.x == 1 {
183             b = reader.get_u8();
184             payload_index += 1;
185             self.i = (b & 0x80) >> 7;
186             self.l = (b & 0x40) >> 6;
187             self.t = (b & 0x20) >> 5;
188             self.k = (b & 0x10) >> 4;
189         }
190 
191         if self.i == 1 {
192             b = reader.get_u8();
193             payload_index += 1;
194             // PID present?
195             if b & 0x80 > 0 {
196                 // M == 1, PID is 16bit
197                 self.picture_id = (((b & 0x7f) as u16) << 8) | (reader.get_u8() as u16);
198                 payload_index += 1;
199             } else {
200                 self.picture_id = b as u16;
201             }
202         }
203 
204         if payload_index >= payload_len {
205             return Err(Error::ErrShortPacket);
206         }
207 
208         if self.l == 1 {
209             self.tl0_pic_idx = reader.get_u8();
210             payload_index += 1;
211         }
212 
213         if payload_index >= payload_len {
214             return Err(Error::ErrShortPacket);
215         }
216 
217         if self.t == 1 || self.k == 1 {
218             let b = reader.get_u8();
219             if self.t == 1 {
220                 self.tid = b >> 6;
221                 self.y = (b >> 5) & 0x1;
222             }
223             if self.k == 1 {
224                 self.key_idx = b & 0x1F;
225             }
226             payload_index += 1;
227         }
228 
229         if payload_index >= packet.len() {
230             return Err(Error::ErrShortPacket);
231         }
232 
233         Ok(packet.slice(payload_index..))
234     }
235 
236     /// is_partition_head checks whether if this is a head of the VP8 partition
is_partition_head(&self, payload: &Bytes) -> bool237     fn is_partition_head(&self, payload: &Bytes) -> bool {
238         if payload.is_empty() {
239             false
240         } else {
241             (payload[0] & 0x10) != 0
242         }
243     }
244 
is_partition_tail(&self, marker: bool, _payload: &Bytes) -> bool245     fn is_partition_tail(&self, marker: bool, _payload: &Bytes) -> bool {
246         marker
247     }
248 }
249