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