Skip to main content

rtc_rtp/codec/vp8/
mod.rs

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