Skip to main content

rtc_rtp/codec/h265/
mod.rs

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