rtc_rtp/codec/h265/
mod.rs

1use bytes::{BufMut, Bytes, BytesMut};
2
3use super::h264::ANNEXB_NALUSTART_CODE;
4use crate::packetizer::{Depacketizer, Payloader};
5use shared::error::{Error, Result};
6
7#[cfg(test)]
8mod h265_test;
9
10pub static ANNEXB_3_NALUSTART_CODE: Bytes = Bytes::from_static(&[0x00, 0x00, 0x01]);
11pub static SING_PAYLOAD_HDR: Bytes = Bytes::from_static(&[0x1C, 0x01]);
12pub static AGGR_PAYLOAD_HDR: Bytes = Bytes::from_static(&[0x60, 0x01]);
13pub static FRAG_PAYLOAD_HDR: Bytes = Bytes::from_static(&[0x62, 0x01]);
14pub static FU_HDR_IDR_S: u8 = 0x93;
15pub static FU_HDR_IDR_M: u8 = 0x13;
16pub static FU_HDR_IDR_E: u8 = 0x53;
17pub static FU_HDR_P_S: u8 = 0x81;
18pub static FU_HDR_P_M: u8 = 0x01;
19pub static FU_HDR_P_E: u8 = 0x41;
20pub static FU_HDR_B_S: u8 = 0x80;
21pub static FU_HDR_B_M: u8 = 0x00;
22pub static FU_HDR_B_E: u8 = 0x40;
23pub const RTP_OUTBOUND_MTU: usize = 1200;
24pub const H265FRAGMENTATION_UNIT_HEADER_SIZE: usize = 1;
25pub const NAL_HEADER_SIZE: usize = 2;
26
27#[derive(PartialEq, Hash, Debug, Copy, Clone)]
28pub enum UnitType {
29    VPS = 32,
30    SPS = 33,
31    PPS = 34,
32    CRA = 21,
33    SEI = 39,
34    IDR = 19,
35    PFR = 1,
36    BFR = 0,
37    IGNORE = -1,
38}
39impl UnitType {
40    pub fn for_id(id: u8) -> Result<UnitType> {
41        if id > 64 {
42            Err(Error::ErrUnhandledNaluType)
43        } else {
44            let t = match id {
45                32 => UnitType::VPS,
46                33 => UnitType::SPS,
47                34 => UnitType::PPS,
48                21 => UnitType::CRA,
49                39 => UnitType::SEI,
50                19 => UnitType::IDR,
51                1 => UnitType::PFR,
52                0 => UnitType::BFR,
53                _ => UnitType::IGNORE, // shouldn't happen
54            };
55            Ok(t)
56        }
57    }
58}
59
60#[derive(Default, Debug, Clone)]
61pub struct HevcPayloader {
62    vps_nalu: Option<Bytes>,
63    sps_nalu: Option<Bytes>,
64    pps_nalu: Option<Bytes>,
65}
66
67impl HevcPayloader {
68    pub fn parse(nalu: &Bytes) -> (Vec<usize>, usize) {
69        let finder = memchr::memmem::Finder::new(&ANNEXB_NALUSTART_CODE);
70        let nals = finder.find_iter(nalu).collect::<Vec<usize>>();
71        if nals.is_empty() {
72            let finder = memchr::memmem::Finder::new(&ANNEXB_3_NALUSTART_CODE);
73            return (finder.find_iter(nalu).collect::<Vec<usize>>(), 3);
74        }
75        (nals, 4)
76    }
77
78    fn emit(&mut self, nalu: &Bytes, mtu: usize, payloads: &mut Vec<Bytes>) {
79        if nalu.is_empty() {
80            return;
81        }
82        let payload_header = H265NALUHeader::new(nalu[0], nalu[1]);
83        let payload_nalu_type = payload_header.nalu_type();
84        let nalu_type = UnitType::for_id(payload_nalu_type).unwrap_or(UnitType::IGNORE);
85        if nalu_type == UnitType::IGNORE {
86            return;
87        } else if nalu_type == UnitType::VPS {
88            self.vps_nalu.replace(nalu.clone());
89        } else if nalu_type == UnitType::SPS {
90            self.sps_nalu.replace(nalu.clone());
91        } else if nalu_type == UnitType::PPS {
92            self.pps_nalu.replace(nalu.clone());
93        }
94        if let (Some(vps_nalu), Some(sps_nalu), Some(pps_nalu)) =
95            (&self.vps_nalu, &self.sps_nalu, &self.pps_nalu)
96        {
97            // Pack current NALU with SPS and PPS as STAP-A
98            let vps_len = (vps_nalu.len() as u16).to_be_bytes();
99            let sps_len = (sps_nalu.len() as u16).to_be_bytes();
100            let pps_len = (pps_nalu.len() as u16).to_be_bytes();
101
102            // TODO DONL not impl yet
103            let mut aggr_nalu = BytesMut::new();
104            aggr_nalu.extend_from_slice(&AGGR_PAYLOAD_HDR);
105            aggr_nalu.extend_from_slice(&vps_len);
106            aggr_nalu.extend_from_slice(vps_nalu);
107            aggr_nalu.extend_from_slice(&sps_len);
108            aggr_nalu.extend_from_slice(sps_nalu);
109            aggr_nalu.extend_from_slice(&pps_len);
110            aggr_nalu.extend_from_slice(pps_nalu);
111            if aggr_nalu.len() <= mtu {
112                payloads.push(Bytes::from(aggr_nalu));
113                self.vps_nalu.take();
114                self.sps_nalu.take();
115                self.pps_nalu.take();
116                return;
117            }
118        } else if nalu_type == UnitType::VPS
119            || nalu_type == UnitType::SPS
120            || nalu_type == UnitType::PPS
121        {
122            return;
123        }
124        // if self.sps_nalu.is_some() && self.pps_nalu.is_some() {
125        //     self.sps_nalu = None;
126        //     self.pps_nalu = None;
127        // }
128
129        // Single NALU
130        if nalu.len() <= mtu {
131            payloads.push(nalu.clone());
132            return;
133        }
134        let max_fragment_size =
135            mtu as isize - NAL_HEADER_SIZE as isize - H265FRAGMENTATION_UNIT_HEADER_SIZE as isize;
136        let nalu_data = nalu;
137        let mut nalu_data_index = 2;
138        let nalu_data_length = nalu.len() as isize - nalu_data_index;
139        let mut nalu_data_remaining = nalu_data_length;
140        if std::cmp::min(max_fragment_size, nalu_data_remaining) <= 0 {
141            return;
142        }
143        while nalu_data_remaining > 0 {
144            let current_fragment_size = std::cmp::min(max_fragment_size, nalu_data_remaining);
145            //out: = make([]byte, fuaHeaderSize + currentFragmentSize)
146            let mut out = BytesMut::with_capacity(
147                H265FRAGMENTATION_UNIT_HEADER_SIZE + current_fragment_size as usize,
148            );
149            out.extend_from_slice(&FRAG_PAYLOAD_HDR);
150            let is_first = nalu_data_index == 2;
151            let is_last = !is_first && current_fragment_size < max_fragment_size;
152            /*
153            +---------------+
154            |0|1|2|3|4|5|6|7|
155            +-+-+-+-+-+-+-+-+
156            |S|E|  fu_type  |
157            +---------------+
158            */
159            if nalu_type == UnitType::IDR {
160                if is_first {
161                    out.put_u8(FU_HDR_IDR_S);
162                } else if is_last {
163                    out.put_u8(FU_HDR_IDR_E);
164                } else {
165                    out.put_u8(FU_HDR_IDR_M);
166                }
167            } else if nalu_type == UnitType::PFR {
168                if is_first {
169                    out.put_u8(FU_HDR_P_S);
170                } else if is_last {
171                    out.put_u8(FU_HDR_P_E);
172                } else {
173                    out.put_u8(FU_HDR_P_M);
174                }
175            } else if nalu_type == UnitType::BFR {
176                if is_first {
177                    out.put_u8(FU_HDR_B_S);
178                } else if is_last {
179                    out.put_u8(FU_HDR_B_E);
180                } else {
181                    out.put_u8(FU_HDR_B_M);
182                }
183            }
184
185            out.extend_from_slice(
186                &nalu_data
187                    [nalu_data_index as usize..(nalu_data_index + current_fragment_size) as usize],
188            );
189            // println!("pkt payload {:?}", &out[0..5]);
190            payloads.push(out.freeze());
191
192            nalu_data_remaining -= current_fragment_size;
193            nalu_data_index += current_fragment_size;
194        }
195    }
196}
197
198impl Payloader for HevcPayloader {
199    /// Payload fragments a H264 packet across one or more byte arrays
200    fn payload(&mut self, mtu: usize, payload: &Bytes) -> Result<Vec<Bytes>> {
201        if payload.is_empty() || mtu == 0 {
202            return Ok(vec![]);
203        }
204
205        let mut payloads = vec![];
206
207        let (nal_idxs, offset) = HevcPayloader::parse(payload);
208        let nal_len = nal_idxs.len();
209        for (i, start) in nal_idxs.iter().enumerate() {
210            let end = if (i + 1) < nal_len {
211                nal_idxs[i + 1]
212            } else {
213                payload.len()
214            };
215            // println!(
216            //     "start {}, end {} payload {:?}",
217            //     start,
218            //     end,
219            //     &payload
220            //         .slice((start + offset)..(start + offset + 5))
221            //         .to_vec()
222            // );
223            self.emit(&payload.slice((start + offset)..end), mtu, &mut payloads);
224        }
225
226        Ok(payloads)
227    }
228
229    fn clone_to(&self) -> Box<dyn Payloader> {
230        Box::new(self.clone())
231    }
232}
233
234///
235/// Network Abstraction Unit Header implementation
236///
237const H265NALU_HEADER_SIZE: usize = 2;
238/// <https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2>
239const H265NALU_AGGREGATION_PACKET_TYPE: u8 = 48;
240/// <https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3>
241const H265NALU_FRAGMENTATION_UNIT_TYPE: u8 = 49;
242/// <https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.4>
243const H265NALU_PACI_PACKET_TYPE: u8 = 50;
244
245/// H265NALUHeader is a H265 NAL Unit Header
246///
247/// ```text
248/// +---------------+---------------+
249/// |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
250/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
251/// |F|   Type    |  layer_id  | tid|
252/// +-------------+-----------------+
253/// ```
254///
255/// ## Specifications
256///
257/// * [RFC 7798 §1.1.4]
258///
259/// [RFC 7798 §1.1.4]: https://tools.ietf.org/html/rfc7798#section-1.1.4
260#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
261pub struct H265NALUHeader(pub u16);
262
263impl H265NALUHeader {
264    pub fn new(high_byte: u8, low_byte: u8) -> Self {
265        H265NALUHeader(((high_byte as u16) << 8) | low_byte as u16)
266    }
267
268    /// f is the forbidden bit, should always be 0.
269    pub fn f(&self) -> bool {
270        (self.0 >> 15) != 0
271    }
272
273    /// nalu_type of NAL Unit.
274    pub fn nalu_type(&self) -> u8 {
275        // 01111110 00000000
276        const MASK: u16 = 0b01111110 << 8;
277        ((self.0 & MASK) >> (8 + 1)) as u8
278    }
279
280    /// is_type_vcl_unit returns whether or not the NAL Unit type is a VCL NAL unit.
281    pub fn is_type_vcl_unit(&self) -> bool {
282        // Type is coded on 6 bits
283        const MSB_MASK: u8 = 0b00100000;
284        (self.nalu_type() & MSB_MASK) == 0
285    }
286
287    /// layer_id should always be 0 in non-3D HEVC context.
288    pub fn layer_id(&self) -> u8 {
289        // 00000001 11111000
290        const MASK: u16 = (0b00000001 << 8) | 0b11111000;
291        ((self.0 & MASK) >> 3) as u8
292    }
293
294    /// tid is the temporal identifier of the NAL unit +1.
295    pub fn tid(&self) -> u8 {
296        const MASK: u16 = 0b00000111;
297        (self.0 & MASK) as u8
298    }
299
300    /// is_aggregation_packet returns whether or not the packet is an Aggregation packet.
301    pub fn is_aggregation_packet(&self) -> bool {
302        self.nalu_type() == H265NALU_AGGREGATION_PACKET_TYPE
303    }
304
305    /// is_fragmentation_unit returns whether or not the packet is a Fragmentation Unit packet.
306    pub fn is_fragmentation_unit(&self) -> bool {
307        self.nalu_type() == H265NALU_FRAGMENTATION_UNIT_TYPE
308    }
309
310    /// is_paci_packet returns whether or not the packet is a PACI packet.
311    pub fn is_paci_packet(&self) -> bool {
312        self.nalu_type() == H265NALU_PACI_PACKET_TYPE
313    }
314}
315
316///
317/// Single NAL Unit Packet implementation
318///
319/// H265SingleNALUnitPacket represents a NALU packet, containing exactly one NAL unit.
320///     0                   1                   2                   3
321///    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
322///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
323///   |           PayloadHdr          |      DONL (conditional)       |
324///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
325///   |                                                               |
326///   |                  NAL unit payload data                        |
327///   |                                                               |
328///   |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
329///   |                               :...OPTIONAL RTP padding        |
330///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
331///
332/// ## Specifications
333///
334/// * [RFC 7798 §4.4.1]
335///
336/// [RFC 7798 §4.4.1]: https://tools.ietf.org/html/rfc7798#section-4.4.1
337#[derive(Default, Debug, Clone, PartialEq, Eq)]
338pub struct H265SingleNALUnitPacket {
339    /// payload_header is the header of the H265 packet.
340    payload_header: H265NALUHeader,
341    /// donl is a 16-bit field, that may or may not be present.
342    donl: Option<u16>,
343    /// payload of the fragmentation unit.
344    payload: Bytes,
345
346    might_need_donl: bool,
347}
348
349impl H265SingleNALUnitPacket {
350    /// with_donl can be called to specify whether or not DONL might be parsed.
351    /// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
352    pub fn with_donl(&mut self, value: bool) {
353        self.might_need_donl = value;
354    }
355
356    /// depacketize parses the passed byte slice and stores the result in the H265SingleNALUnitPacket this method is called upon.
357    fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
358        if payload.len() <= H265NALU_HEADER_SIZE {
359            return Err(Error::ErrShortPacket);
360        }
361
362        let payload_header = H265NALUHeader::new(payload[0], payload[1]);
363        if payload_header.f() {
364            return Err(Error::ErrH265CorruptedPacket);
365        }
366        if payload_header.is_fragmentation_unit()
367            || payload_header.is_paci_packet()
368            || payload_header.is_aggregation_packet()
369        {
370            return Err(Error::ErrInvalidH265PacketType);
371        }
372
373        let mut payload = payload.slice(2..);
374
375        if self.might_need_donl {
376            // sizeof(uint16)
377            if payload.len() <= 2 {
378                return Err(Error::ErrShortPacket);
379            }
380
381            let donl = ((payload[0] as u16) << 8) | (payload[1] as u16);
382            self.donl = Some(donl);
383            payload = payload.slice(2..);
384        }
385
386        self.payload_header = payload_header;
387        self.payload = payload;
388
389        Ok(())
390    }
391
392    /// payload_header returns the NALU header of the packet.
393    pub fn payload_header(&self) -> H265NALUHeader {
394        self.payload_header
395    }
396
397    /// donl returns the DONL of the packet.
398    pub fn donl(&self) -> Option<u16> {
399        self.donl
400    }
401
402    /// payload returns the Fragmentation Unit packet payload.
403    pub fn payload(&self) -> Bytes {
404        self.payload.clone()
405    }
406}
407
408///
409/// Aggregation Packets implementation
410///
411/// H265AggregationUnitFirst represent the First Aggregation Unit in an AP.
412///
413///    0                   1                   2                   3
414///    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
415///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
416///                   :       DONL (conditional)      |   NALU size   |
417///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
418///   |   NALU size   |                                               |
419///   +-+-+-+-+-+-+-+-+         NAL unit                              |
420///   |                                                               |
421///   |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
422///   |                               :
423///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
424///
425/// ## Specifications
426///
427/// * [RFC 7798 §4.4.2]
428///
429/// [RFC 7798 §4.4.2]: https://tools.ietf.org/html/rfc7798#section-4.4.2
430#[derive(Default, Debug, Clone, PartialEq, Eq)]
431pub struct H265AggregationUnitFirst {
432    donl: Option<u16>,
433    nal_unit_size: u16,
434    nal_unit: Bytes,
435}
436
437impl H265AggregationUnitFirst {
438    /// donl field, when present, specifies the value of the 16 least
439    /// significant bits of the decoding order number of the aggregated NAL
440    /// unit.
441    pub fn donl(&self) -> Option<u16> {
442        self.donl
443    }
444
445    /// nalu_size represents the size, in bytes, of the nal_unit.
446    pub fn nalu_size(&self) -> u16 {
447        self.nal_unit_size
448    }
449
450    /// nal_unit payload.
451    pub fn nal_unit(&self) -> Bytes {
452        self.nal_unit.clone()
453    }
454}
455
456/// H265AggregationUnit represent the an Aggregation Unit in an AP, which is not the first one.
457///
458///    0                   1                   2                   3
459///    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
460///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
461///                   : DOND (cond)   |          NALU size            |
462///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
463///   |                                                               |
464///   |                       NAL unit                                |
465///   |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
466///   |                               :
467///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
468///
469/// ## Specifications
470///
471/// * [RFC 7798 §4.4.2]
472///
473/// [RFC 7798 §4.4.2]: https://tools.ietf.org/html/rfc7798#section-4.4.2
474#[derive(Default, Debug, Clone, PartialEq, Eq)]
475pub struct H265AggregationUnit {
476    dond: Option<u8>,
477    nal_unit_size: u16,
478    nal_unit: Bytes,
479}
480
481impl H265AggregationUnit {
482    /// dond field plus 1 specifies the difference between
483    /// the decoding order number values of the current aggregated NAL unit
484    /// and the preceding aggregated NAL unit in the same AP.
485    pub fn dond(&self) -> Option<u8> {
486        self.dond
487    }
488
489    /// nalu_size represents the size, in bytes, of the nal_unit.
490    pub fn nalu_size(&self) -> u16 {
491        self.nal_unit_size
492    }
493
494    /// nal_unit payload.
495    pub fn nal_unit(&self) -> Bytes {
496        self.nal_unit.clone()
497    }
498}
499
500/// H265AggregationPacket represents an Aggregation packet.
501///   0                   1                   2                   3
502///    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
503///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
504///   |    PayloadHdr (Type=48)       |                               |
505///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
506///   |                                                               |
507///   |             two or more aggregation units                     |
508///   |                                                               |
509///   |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
510///   |                               :...OPTIONAL RTP padding        |
511///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
512///
513/// ## Specifications
514///
515/// * [RFC 7798 §4.4.2]
516///
517/// [RFC 7798 §4.4.2]: https://tools.ietf.org/html/rfc7798#section-4.4.2
518#[derive(Default, Debug, Clone, PartialEq, Eq)]
519pub struct H265AggregationPacket {
520    first_unit: Option<H265AggregationUnitFirst>,
521    other_units: Vec<H265AggregationUnit>,
522
523    might_need_donl: bool,
524}
525
526impl H265AggregationPacket {
527    /// with_donl can be called to specify whether or not DONL might be parsed.
528    /// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
529    pub fn with_donl(&mut self, value: bool) {
530        self.might_need_donl = value;
531    }
532
533    /// depacketize parses the passed byte slice and stores the result in the H265AggregationPacket this method is called upon.
534    fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
535        if payload.len() <= H265NALU_HEADER_SIZE {
536            return Err(Error::ErrShortPacket);
537        }
538
539        let payload_header = H265NALUHeader::new(payload[0], payload[1]);
540        if payload_header.f() {
541            return Err(Error::ErrH265CorruptedPacket);
542        }
543        if !payload_header.is_aggregation_packet() {
544            return Err(Error::ErrInvalidH265PacketType);
545        }
546
547        // First parse the first aggregation unit
548        let mut payload = payload.slice(2..);
549        let mut first_unit = H265AggregationUnitFirst::default();
550
551        if self.might_need_donl {
552            if payload.len() < 2 {
553                return Err(Error::ErrShortPacket);
554            }
555
556            let donl = ((payload[0] as u16) << 8) | (payload[1] as u16);
557            first_unit.donl = Some(donl);
558
559            payload = payload.slice(2..);
560        }
561        if payload.len() < 2 {
562            return Err(Error::ErrShortPacket);
563        }
564        first_unit.nal_unit_size = ((payload[0] as u16) << 8) | (payload[1] as u16);
565        payload = payload.slice(2..);
566
567        if payload.len() < first_unit.nal_unit_size as usize {
568            return Err(Error::ErrShortPacket);
569        }
570
571        first_unit.nal_unit = payload.slice(..first_unit.nal_unit_size as usize);
572        payload = payload.slice(first_unit.nal_unit_size as usize..);
573
574        // Parse remaining Aggregation Units
575        let mut units = vec![]; //H265AggregationUnit
576        loop {
577            let mut unit = H265AggregationUnit::default();
578
579            if self.might_need_donl {
580                if payload.is_empty() {
581                    break;
582                }
583
584                let dond = payload[0];
585                unit.dond = Some(dond);
586
587                payload = payload.slice(1..);
588            }
589
590            if payload.len() < 2 {
591                break;
592            }
593            unit.nal_unit_size = ((payload[0] as u16) << 8) | (payload[1] as u16);
594            payload = payload.slice(2..);
595
596            if payload.len() < unit.nal_unit_size as usize {
597                break;
598            }
599
600            unit.nal_unit = payload.slice(..unit.nal_unit_size as usize);
601            payload = payload.slice(unit.nal_unit_size as usize..);
602
603            units.push(unit);
604        }
605
606        // There need to be **at least** two Aggregation Units (first + another one)
607        if units.is_empty() {
608            return Err(Error::ErrShortPacket);
609        }
610
611        self.first_unit = Some(first_unit);
612        self.other_units = units;
613
614        Ok(())
615    }
616
617    /// first_unit returns the first Aggregated Unit of the packet.
618    pub fn first_unit(&self) -> Option<&H265AggregationUnitFirst> {
619        self.first_unit.as_ref()
620    }
621
622    /// other_units returns the all the other Aggregated Unit of the packet (excluding the first one).
623    pub fn other_units(&self) -> &[H265AggregationUnit] {
624        self.other_units.as_slice()
625    }
626}
627
628/// Fragmentation Unit implementation
629///
630/// H265FragmentationUnitHeader is a H265 FU Header
631/// +---------------+
632/// |0|1|2|3|4|5|6|7|
633/// +-+-+-+-+-+-+-+-+
634/// |S|E|  fu_type   |
635/// +---------------+
636#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
637pub struct H265FragmentationUnitHeader(pub u8);
638
639impl H265FragmentationUnitHeader {
640    /// s represents the start of a fragmented NAL unit.
641    pub fn s(&self) -> bool {
642        const MASK: u8 = 0b10000000;
643        ((self.0 & MASK) >> 7) != 0
644    }
645
646    /// e represents the end of a fragmented NAL unit.
647    pub fn e(&self) -> bool {
648        const MASK: u8 = 0b01000000;
649        ((self.0 & MASK) >> 6) != 0
650    }
651
652    /// fu_type MUST be equal to the field Type of the fragmented NAL unit.
653    pub fn fu_type(&self) -> u8 {
654        const MASK: u8 = 0b00111111;
655        self.0 & MASK
656    }
657}
658
659/// H265FragmentationUnitPacket represents a single Fragmentation Unit packet.
660///
661///  0                   1                   2                   3
662/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
663/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
664/// |    PayloadHdr (Type=49)       |   FU header   | DONL (cond)   |
665/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
666/// | DONL (cond)   |                                               |
667/// |-+-+-+-+-+-+-+-+                                               |
668/// |                         FU payload                            |
669/// |                                                               |
670/// |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
671/// |                               :...OPTIONAL RTP padding        |
672/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
673///
674/// ## Specifications
675///
676/// * [RFC 7798 §4.4.3]
677///
678/// [RFC 7798 §4.4.3]: https://tools.ietf.org/html/rfc7798#section-4.4.3
679#[derive(Default, Debug, Clone, PartialEq, Eq)]
680pub struct H265FragmentationUnitPacket {
681    /// payload_header is the header of the H265 packet.
682    payload_header: H265NALUHeader,
683    /// fu_header is the header of the fragmentation unit
684    fu_header: H265FragmentationUnitHeader,
685    /// donl is a 16-bit field, that may or may not be present.
686    donl: Option<u16>,
687    /// payload of the fragmentation unit.
688    payload: Bytes,
689
690    might_need_donl: bool,
691}
692
693impl H265FragmentationUnitPacket {
694    /// with_donl can be called to specify whether or not DONL might be parsed.
695    /// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
696    pub fn with_donl(&mut self, value: bool) {
697        self.might_need_donl = value;
698    }
699
700    /// depacketize parses the passed byte slice and stores the result in the H265FragmentationUnitPacket this method is called upon.
701    fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
702        const TOTAL_HEADER_SIZE: usize = H265NALU_HEADER_SIZE + H265FRAGMENTATION_UNIT_HEADER_SIZE;
703        if payload.len() <= TOTAL_HEADER_SIZE {
704            return Err(Error::ErrShortPacket);
705        }
706
707        let payload_header = H265NALUHeader::new(payload[0], payload[1]);
708        if payload_header.f() {
709            return Err(Error::ErrH265CorruptedPacket);
710        }
711        if !payload_header.is_fragmentation_unit() {
712            return Err(Error::ErrInvalidH265PacketType);
713        }
714
715        let fu_header = H265FragmentationUnitHeader(payload[2]);
716        let mut payload = payload.slice(3..);
717
718        if fu_header.s() && self.might_need_donl {
719            if payload.len() <= 2 {
720                return Err(Error::ErrShortPacket);
721            }
722
723            let donl = ((payload[0] as u16) << 8) | (payload[1] as u16);
724            self.donl = Some(donl);
725            payload = payload.slice(2..);
726        }
727
728        self.payload_header = payload_header;
729        self.fu_header = fu_header;
730        self.payload = payload;
731
732        Ok(())
733    }
734
735    /// payload_header returns the NALU header of the packet.
736    pub fn payload_header(&self) -> H265NALUHeader {
737        self.payload_header
738    }
739
740    /// fu_header returns the Fragmentation Unit Header of the packet.
741    pub fn fu_header(&self) -> H265FragmentationUnitHeader {
742        self.fu_header
743    }
744
745    /// donl returns the DONL of the packet.
746    pub fn donl(&self) -> Option<u16> {
747        self.donl
748    }
749
750    /// payload returns the Fragmentation Unit packet payload.
751    pub fn payload(&self) -> Bytes {
752        self.payload.clone()
753    }
754}
755
756///
757/// PACI implementation
758///
759/// H265PACIPacket represents a single H265 PACI packet.
760///
761///  0                   1                   2                   3
762/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
763/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
764/// |    PayloadHdr (Type=50)       |A|   cType   | phssize |F0..2|Y|
765/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
766/// |        payload Header Extension Structure (phes)              |
767/// |=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=|
768/// |                                                               |
769/// |                  PACI payload: NAL unit                       |
770/// |                   . . .                                       |
771/// |                                                               |
772/// |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
773/// |                               :...OPTIONAL RTP padding        |
774/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
775///
776/// ## Specifications
777///
778/// * [RFC 7798 §4.4.4]
779///
780/// [RFC 7798 §4.4.4]: https://tools.ietf.org/html/rfc7798#section-4.4.4
781#[derive(Default, Debug, Clone, PartialEq, Eq)]
782pub struct H265PACIPacket {
783    /// payload_header is the header of the H265 packet.
784    payload_header: H265NALUHeader,
785
786    /// Field which holds value for `A`, `cType`, `phssize`, `F0`, `F1`, `F2` and `Y` fields.
787    paci_header_fields: u16,
788
789    /// phes is a header extension, of byte length `phssize`
790    phes: Bytes,
791
792    /// payload contains NAL units & optional padding
793    payload: Bytes,
794}
795
796impl H265PACIPacket {
797    /// payload_header returns the NAL Unit Header.
798    pub fn payload_header(&self) -> H265NALUHeader {
799        self.payload_header
800    }
801
802    /// a copies the F bit of the PACI payload NALU.
803    pub fn a(&self) -> bool {
804        const MASK: u16 = 0b10000000 << 8;
805        (self.paci_header_fields & MASK) != 0
806    }
807
808    /// ctype copies the Type field of the PACI payload NALU.
809    pub fn ctype(&self) -> u8 {
810        const MASK: u16 = 0b01111110 << 8;
811        ((self.paci_header_fields & MASK) >> (8 + 1)) as u8
812    }
813
814    /// phs_size indicates the size of the phes field.
815    pub fn phs_size(&self) -> u8 {
816        const MASK: u16 = (0b00000001 << 8) | 0b11110000;
817        ((self.paci_header_fields & MASK) >> 4) as u8
818    }
819
820    /// f0 indicates the presence of a Temporal Scalability support extension in the phes.
821    pub fn f0(&self) -> bool {
822        const MASK: u16 = 0b00001000;
823        (self.paci_header_fields & MASK) != 0
824    }
825
826    /// f1 must be zero, reserved for future extensions.
827    pub fn f1(&self) -> bool {
828        const MASK: u16 = 0b00000100;
829        (self.paci_header_fields & MASK) != 0
830    }
831
832    /// f2 must be zero, reserved for future extensions.
833    pub fn f2(&self) -> bool {
834        const MASK: u16 = 0b00000010;
835        (self.paci_header_fields & MASK) != 0
836    }
837
838    /// y must be zero, reserved for future extensions.
839    pub fn y(&self) -> bool {
840        const MASK: u16 = 0b00000001;
841        (self.paci_header_fields & MASK) != 0
842    }
843
844    /// phes contains header extensions. Its size is indicated by phssize.
845    pub fn phes(&self) -> Bytes {
846        self.phes.clone()
847    }
848
849    /// payload is a single NALU or NALU-like struct, not including the first two octets (header).
850    pub fn payload(&self) -> Bytes {
851        self.payload.clone()
852    }
853
854    /// tsci returns the Temporal Scalability Control Information extension, if present.
855    pub fn tsci(&self) -> Option<H265TSCI> {
856        if !self.f0() || self.phs_size() < 3 {
857            return None;
858        }
859
860        Some(H265TSCI(
861            ((self.phes[0] as u32) << 16) | ((self.phes[1] as u32) << 8) | self.phes[0] as u32,
862        ))
863    }
864
865    /// depacketize parses the passed byte slice and stores the result in the H265PACIPacket this method is called upon.
866    fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
867        const TOTAL_HEADER_SIZE: usize = H265NALU_HEADER_SIZE + 2;
868        if payload.len() <= TOTAL_HEADER_SIZE {
869            return Err(Error::ErrShortPacket);
870        }
871
872        let payload_header = H265NALUHeader::new(payload[0], payload[1]);
873        if payload_header.f() {
874            return Err(Error::ErrH265CorruptedPacket);
875        }
876        if !payload_header.is_paci_packet() {
877            return Err(Error::ErrInvalidH265PacketType);
878        }
879
880        let paci_header_fields = ((payload[2] as u16) << 8) | (payload[3] as u16);
881        let mut payload = payload.slice(4..);
882
883        self.paci_header_fields = paci_header_fields;
884        let header_extension_size = self.phs_size();
885
886        if payload.len() < header_extension_size as usize + 1 {
887            self.paci_header_fields = 0;
888            return Err(Error::ErrShortPacket);
889        }
890
891        self.payload_header = payload_header;
892
893        if header_extension_size > 0 {
894            self.phes = payload.slice(..header_extension_size as usize);
895        }
896
897        payload = payload.slice(header_extension_size as usize..);
898        self.payload = payload;
899
900        Ok(())
901    }
902}
903
904///
905/// Temporal Scalability Control Information
906///
907/// H265TSCI is a Temporal Scalability Control Information header extension.
908///
909/// ## Specifications
910///
911/// * [RFC 7798 §4.5]
912///
913/// [RFC 7798 §4.5]: https://tools.ietf.org/html/rfc7798#section-4.5
914#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
915pub struct H265TSCI(pub u32);
916
917impl H265TSCI {
918    /// tl0picidx see RFC7798 for more details.
919    pub fn tl0picidx(&self) -> u8 {
920        const M1: u32 = 0xFFFF0000;
921        const M2: u32 = 0xFF00;
922        ((((self.0 & M1) >> 16) & M2) >> 8) as u8
923    }
924
925    /// irap_pic_id see RFC7798 for more details.
926    pub fn irap_pic_id(&self) -> u8 {
927        const M1: u32 = 0xFFFF0000;
928        const M2: u32 = 0x00FF;
929        (((self.0 & M1) >> 16) & M2) as u8
930    }
931
932    /// s see RFC7798 for more details.
933    pub fn s(&self) -> bool {
934        const M1: u32 = 0xFF00;
935        const M2: u32 = 0b10000000;
936        (((self.0 & M1) >> 8) & M2) != 0
937    }
938
939    /// e see RFC7798 for more details.
940    pub fn e(&self) -> bool {
941        const M1: u32 = 0xFF00;
942        const M2: u32 = 0b01000000;
943        (((self.0 & M1) >> 8) & M2) != 0
944    }
945
946    /// res see RFC7798 for more details.
947    pub fn res(&self) -> u8 {
948        const M1: u32 = 0xFF00;
949        const M2: u32 = 0b00111111;
950        (((self.0 & M1) >> 8) & M2) as u8
951    }
952}
953
954///
955/// H265 Payload Enum
956///
957#[derive(Debug, Clone, PartialEq, Eq)]
958pub enum H265Payload {
959    H265SingleNALUnitPacket(H265SingleNALUnitPacket),
960    H265FragmentationUnitPacket(H265FragmentationUnitPacket),
961    H265AggregationPacket(H265AggregationPacket),
962    H265PACIPacket(H265PACIPacket),
963}
964
965impl Default for H265Payload {
966    fn default() -> Self {
967        H265Payload::H265SingleNALUnitPacket(H265SingleNALUnitPacket::default())
968    }
969}
970
971///
972/// Packet implementation
973///
974/// H265Packet represents a H265 packet, stored in the payload of an RTP packet.
975#[derive(Default, Debug, Clone, PartialEq, Eq)]
976pub struct H265Packet {
977    payload: H265Payload,
978    might_need_donl: bool,
979}
980
981impl H265Packet {
982    /// with_donl can be called to specify whether or not DONL might be parsed.
983    /// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
984    pub fn with_donl(&mut self, value: bool) {
985        self.might_need_donl = value;
986    }
987
988    /// payload returns the populated payload.
989    /// Must be casted to one of:
990    /// - H265SingleNALUnitPacket
991    /// - H265FragmentationUnitPacket
992    /// - H265AggregationPacket
993    /// - H265PACIPacket
994    pub fn payload(&self) -> &H265Payload {
995        &self.payload
996    }
997}
998
999impl Depacketizer for H265Packet {
1000    /// depacketize parses the passed byte slice and stores the result in the H265Packet this method is called upon
1001    fn depacketize(&mut self, payload: &Bytes) -> Result<Bytes> {
1002        if payload.len() <= H265NALU_HEADER_SIZE {
1003            return Err(Error::ErrShortPacket);
1004        }
1005
1006        let payload_header = H265NALUHeader::new(payload[0], payload[1]);
1007        if payload_header.f() {
1008            return Err(Error::ErrH265CorruptedPacket);
1009        }
1010
1011        if payload_header.is_paci_packet() {
1012            let mut decoded = H265PACIPacket::default();
1013            decoded.depacketize(payload)?;
1014
1015            self.payload = H265Payload::H265PACIPacket(decoded);
1016        } else if payload_header.is_fragmentation_unit() {
1017            let mut decoded = H265FragmentationUnitPacket::default();
1018            decoded.with_donl(self.might_need_donl);
1019
1020            decoded.depacketize(payload)?;
1021
1022            self.payload = H265Payload::H265FragmentationUnitPacket(decoded);
1023        } else if payload_header.is_aggregation_packet() {
1024            let mut decoded = H265AggregationPacket::default();
1025            decoded.with_donl(self.might_need_donl);
1026
1027            decoded.depacketize(payload)?;
1028
1029            self.payload = H265Payload::H265AggregationPacket(decoded);
1030        } else {
1031            let mut decoded = H265SingleNALUnitPacket::default();
1032            decoded.with_donl(self.might_need_donl);
1033
1034            decoded.depacketize(payload)?;
1035
1036            self.payload = H265Payload::H265SingleNALUnitPacket(decoded);
1037        }
1038
1039        Ok(payload.clone())
1040    }
1041
1042    /// is_partition_head checks if this is the head of a packetized nalu stream.
1043    fn is_partition_head(&self, _payload: &Bytes) -> bool {
1044        //TODO:
1045        true
1046    }
1047
1048    fn is_partition_tail(&self, marker: bool, _payload: &Bytes) -> bool {
1049        marker
1050    }
1051}