rtc_rtp/codecs/h265/
mod.rs

1use crate::packetizer::Depacketizer;
2use bytes::Bytes;
3use shared::error::{Error, Result};
4
5#[cfg(test)]
6mod h265_test;
7
8///
9/// Network Abstraction Unit Header implementation
10///
11
12const H265NALU_HEADER_SIZE: usize = 2;
13/// https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
14const H265NALU_AGGREGATION_PACKET_TYPE: u8 = 48;
15/// https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3
16const H265NALU_FRAGMENTATION_UNIT_TYPE: u8 = 49;
17/// https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.4
18const H265NALU_PACI_PACKET_TYPE: u8 = 50;
19
20/// H265NALUHeader is a H265 NAL Unit Header
21/// https://datatracker.ietf.org/doc/html/rfc7798#section-1.1.4
22/// +---------------+---------------+
23///  |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
24///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25///  |F|   Type    |  layer_id  | tid |
26///  +-------------+-----------------+
27#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
28pub struct H265NALUHeader(pub u16);
29
30impl H265NALUHeader {
31    fn new(high_byte: u8, low_byte: u8) -> Self {
32        H265NALUHeader(((high_byte as u16) << 8) | low_byte as u16)
33    }
34
35    /// f is the forbidden bit, should always be 0.
36    pub fn f(&self) -> bool {
37        (self.0 >> 15) != 0
38    }
39
40    /// nalu_type of NAL Unit.
41    pub fn nalu_type(&self) -> u8 {
42        // 01111110 00000000
43        const MASK: u16 = 0b01111110 << 8;
44        ((self.0 & MASK) >> (8 + 1)) as u8
45    }
46
47    /// is_type_vcl_unit returns whether or not the NAL Unit type is a VCL NAL unit.
48    pub fn is_type_vcl_unit(&self) -> bool {
49        // Type is coded on 6 bits
50        const MSB_MASK: u8 = 0b00100000;
51        (self.nalu_type() & MSB_MASK) == 0
52    }
53
54    /// layer_id should always be 0 in non-3D HEVC context.
55    pub fn layer_id(&self) -> u8 {
56        // 00000001 11111000
57        const MASK: u16 = (0b00000001 << 8) | 0b11111000;
58        ((self.0 & MASK) >> 3) as u8
59    }
60
61    /// tid is the temporal identifier of the NAL unit +1.
62    pub fn tid(&self) -> u8 {
63        const MASK: u16 = 0b00000111;
64        (self.0 & MASK) as u8
65    }
66
67    /// is_aggregation_packet returns whether or not the packet is an Aggregation packet.
68    pub fn is_aggregation_packet(&self) -> bool {
69        self.nalu_type() == H265NALU_AGGREGATION_PACKET_TYPE
70    }
71
72    /// is_fragmentation_unit returns whether or not the packet is a Fragmentation Unit packet.
73    pub fn is_fragmentation_unit(&self) -> bool {
74        self.nalu_type() == H265NALU_FRAGMENTATION_UNIT_TYPE
75    }
76
77    /// is_paci_packet returns whether or not the packet is a PACI packet.
78    pub fn is_paci_packet(&self) -> bool {
79        self.nalu_type() == H265NALU_PACI_PACKET_TYPE
80    }
81}
82
83///
84/// Single NAL Unit Packet implementation
85///
86/// H265SingleNALUnitPacket represents a NALU packet, containing exactly one NAL unit.
87///     0                   1                   2                   3
88///    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
89///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90///   |           PayloadHdr          |      DONL (conditional)       |
91///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92///   |                                                               |
93///   |                  NAL unit payload data                        |
94///   |                                                               |
95///   |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96///   |                               :...OPTIONAL RTP padding        |
97///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98///
99/// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.1
100#[derive(Default, Debug, Clone, PartialEq, Eq)]
101pub struct H265SingleNALUnitPacket {
102    /// payload_header is the header of the H265 packet.
103    payload_header: H265NALUHeader,
104    /// donl is a 16-bit field, that may or may not be present.
105    donl: Option<u16>,
106    /// payload of the fragmentation unit.
107    payload: Bytes,
108
109    might_need_donl: bool,
110}
111
112impl H265SingleNALUnitPacket {
113    /// with_donl can be called to specify whether or not DONL might be parsed.
114    /// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
115    pub fn with_donl(&mut self, value: bool) {
116        self.might_need_donl = value;
117    }
118
119    /// depacketize parses the passed byte slice and stores the result in the H265SingleNALUnitPacket this method is called upon.
120    fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
121        if payload.len() <= H265NALU_HEADER_SIZE {
122            return Err(Error::ErrShortPacket);
123        }
124
125        let payload_header = H265NALUHeader::new(payload[0], payload[1]);
126        if payload_header.f() {
127            return Err(Error::ErrH265CorruptedPacket);
128        }
129        if payload_header.is_fragmentation_unit()
130            || payload_header.is_paci_packet()
131            || payload_header.is_aggregation_packet()
132        {
133            return Err(Error::ErrInvalidH265PacketType);
134        }
135
136        let mut payload = payload.slice(2..);
137
138        if self.might_need_donl {
139            // sizeof(uint16)
140            if payload.len() <= 2 {
141                return Err(Error::ErrShortPacket);
142            }
143
144            let donl = ((payload[0] as u16) << 8) | (payload[1] as u16);
145            self.donl = Some(donl);
146            payload = payload.slice(2..);
147        }
148
149        self.payload_header = payload_header;
150        self.payload = payload;
151
152        Ok(())
153    }
154
155    /// payload_header returns the NALU header of the packet.
156    pub fn payload_header(&self) -> H265NALUHeader {
157        self.payload_header
158    }
159
160    /// donl returns the DONL of the packet.
161    pub fn donl(&self) -> Option<u16> {
162        self.donl
163    }
164
165    /// payload returns the Fragmentation Unit packet payload.
166    pub fn payload(&self) -> Bytes {
167        self.payload.clone()
168    }
169}
170
171///
172/// Aggregation Packets implementation
173///
174/// H265AggregationUnitFirst represent the First Aggregation Unit in an AP.
175///
176///    0                   1                   2                   3
177///    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
178///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179///                   :       DONL (conditional)      |   NALU size   |
180///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
181///   |   NALU size   |                                               |
182///   +-+-+-+-+-+-+-+-+         NAL unit                              |
183///   |                                                               |
184///   |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
185///   |                               :
186///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
187///
188/// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
189#[derive(Default, Debug, Clone, PartialEq, Eq)]
190pub struct H265AggregationUnitFirst {
191    donl: Option<u16>,
192    nal_unit_size: u16,
193    nal_unit: Bytes,
194}
195
196impl H265AggregationUnitFirst {
197    /// donl field, when present, specifies the value of the 16 least
198    /// significant bits of the decoding order number of the aggregated NAL
199    /// unit.
200    pub fn donl(&self) -> Option<u16> {
201        self.donl
202    }
203
204    /// nalu_size represents the size, in bytes, of the nal_unit.
205    pub fn nalu_size(&self) -> u16 {
206        self.nal_unit_size
207    }
208
209    /// nal_unit payload.
210    pub fn nal_unit(&self) -> Bytes {
211        self.nal_unit.clone()
212    }
213}
214
215/// H265AggregationUnit represent the an Aggregation Unit in an AP, which is not the first one.
216///
217///    0                   1                   2                   3
218///    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
219///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
220///                   : DOND (cond)   |          NALU size            |
221///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
222///   |                                                               |
223///   |                       NAL unit                                |
224///   |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
225///   |                               :
226///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
227///
228/// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
229#[derive(Default, Debug, Clone, PartialEq, Eq)]
230pub struct H265AggregationUnit {
231    dond: Option<u8>,
232    nal_unit_size: u16,
233    nal_unit: Bytes,
234}
235
236impl H265AggregationUnit {
237    /// dond field plus 1 specifies the difference between
238    /// the decoding order number values of the current aggregated NAL unit
239    /// and the preceding aggregated NAL unit in the same AP.
240    pub fn dond(&self) -> Option<u8> {
241        self.dond
242    }
243
244    /// nalu_size represents the size, in bytes, of the nal_unit.
245    pub fn nalu_size(&self) -> u16 {
246        self.nal_unit_size
247    }
248
249    /// nal_unit payload.
250    pub fn nal_unit(&self) -> Bytes {
251        self.nal_unit.clone()
252    }
253}
254
255/// H265AggregationPacket represents an Aggregation packet.
256///   0                   1                   2                   3
257///    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
258///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
259///   |    PayloadHdr (Type=48)       |                               |
260///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
261///   |                                                               |
262///   |             two or more aggregation units                     |
263///   |                                                               |
264///   |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
265///   |                               :...OPTIONAL RTP padding        |
266///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
267///
268/// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
269#[derive(Default, Debug, Clone, PartialEq, Eq)]
270pub struct H265AggregationPacket {
271    first_unit: Option<H265AggregationUnitFirst>,
272    other_units: Vec<H265AggregationUnit>,
273
274    might_need_donl: bool,
275}
276
277impl H265AggregationPacket {
278    /// with_donl can be called to specify whether or not DONL might be parsed.
279    /// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
280    pub fn with_donl(&mut self, value: bool) {
281        self.might_need_donl = value;
282    }
283
284    /// depacketize parses the passed byte slice and stores the result in the H265AggregationPacket this method is called upon.
285    fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
286        if payload.len() <= H265NALU_HEADER_SIZE {
287            return Err(Error::ErrShortPacket);
288        }
289
290        let payload_header = H265NALUHeader::new(payload[0], payload[1]);
291        if payload_header.f() {
292            return Err(Error::ErrH265CorruptedPacket);
293        }
294        if !payload_header.is_aggregation_packet() {
295            return Err(Error::ErrInvalidH265PacketType);
296        }
297
298        // First parse the first aggregation unit
299        let mut payload = payload.slice(2..);
300        let mut first_unit = H265AggregationUnitFirst::default();
301
302        if self.might_need_donl {
303            if payload.len() < 2 {
304                return Err(Error::ErrShortPacket);
305            }
306
307            let donl = ((payload[0] as u16) << 8) | (payload[1] as u16);
308            first_unit.donl = Some(donl);
309
310            payload = payload.slice(2..);
311        }
312        if payload.len() < 2 {
313            return Err(Error::ErrShortPacket);
314        }
315        first_unit.nal_unit_size = ((payload[0] as u16) << 8) | (payload[1] as u16);
316        payload = payload.slice(2..);
317
318        if payload.len() < first_unit.nal_unit_size as usize {
319            return Err(Error::ErrShortPacket);
320        }
321
322        first_unit.nal_unit = payload.slice(..first_unit.nal_unit_size as usize);
323        payload = payload.slice(first_unit.nal_unit_size as usize..);
324
325        // Parse remaining Aggregation Units
326        let mut units = vec![]; //H265AggregationUnit
327        loop {
328            let mut unit = H265AggregationUnit::default();
329
330            if self.might_need_donl {
331                if payload.is_empty() {
332                    break;
333                }
334
335                let dond = payload[0];
336                unit.dond = Some(dond);
337
338                payload = payload.slice(1..);
339            }
340
341            if payload.len() < 2 {
342                break;
343            }
344            unit.nal_unit_size = ((payload[0] as u16) << 8) | (payload[1] as u16);
345            payload = payload.slice(2..);
346
347            if payload.len() < unit.nal_unit_size as usize {
348                break;
349            }
350
351            unit.nal_unit = payload.slice(..unit.nal_unit_size as usize);
352            payload = payload.slice(unit.nal_unit_size as usize..);
353
354            units.push(unit);
355        }
356
357        // There need to be **at least** two Aggregation Units (first + another one)
358        if units.is_empty() {
359            return Err(Error::ErrShortPacket);
360        }
361
362        self.first_unit = Some(first_unit);
363        self.other_units = units;
364
365        Ok(())
366    }
367
368    /// first_unit returns the first Aggregated Unit of the packet.
369    pub fn first_unit(&self) -> Option<&H265AggregationUnitFirst> {
370        self.first_unit.as_ref()
371    }
372
373    /// other_units returns the all the other Aggregated Unit of the packet (excluding the first one).
374    pub fn other_units(&self) -> &[H265AggregationUnit] {
375        self.other_units.as_slice()
376    }
377}
378
379///
380/// Fragmentation Unit implementation
381///
382
383const H265FRAGMENTATION_UNIT_HEADER_SIZE: usize = 1;
384
385/// H265FragmentationUnitHeader is a H265 FU Header
386/// +---------------+
387/// |0|1|2|3|4|5|6|7|
388/// +-+-+-+-+-+-+-+-+
389/// |S|E|  fu_type   |
390/// +---------------+
391#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
392pub struct H265FragmentationUnitHeader(pub u8);
393
394impl H265FragmentationUnitHeader {
395    /// s represents the start of a fragmented NAL unit.
396    pub fn s(&self) -> bool {
397        const MASK: u8 = 0b10000000;
398        ((self.0 & MASK) >> 7) != 0
399    }
400
401    /// e represents the end of a fragmented NAL unit.
402    pub fn e(&self) -> bool {
403        const MASK: u8 = 0b01000000;
404        ((self.0 & MASK) >> 6) != 0
405    }
406
407    /// fu_type MUST be equal to the field Type of the fragmented NAL unit.
408    pub fn fu_type(&self) -> u8 {
409        const MASK: u8 = 0b00111111;
410        self.0 & MASK
411    }
412}
413
414/// H265FragmentationUnitPacket represents a single Fragmentation Unit packet.
415///
416///  0                   1                   2                   3
417/// 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
418/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
419/// |    PayloadHdr (Type=49)       |   FU header   | DONL (cond)   |
420/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
421/// | DONL (cond)   |                                               |
422/// |-+-+-+-+-+-+-+-+                                               |
423/// |                         FU payload                            |
424/// |                                                               |
425/// |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
426/// |                               :...OPTIONAL RTP padding        |
427/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
428///
429/// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3
430#[derive(Default, Debug, Clone, PartialEq, Eq)]
431pub struct H265FragmentationUnitPacket {
432    /// payload_header is the header of the H265 packet.
433    payload_header: H265NALUHeader,
434    /// fu_header is the header of the fragmentation unit
435    fu_header: H265FragmentationUnitHeader,
436    /// donl is a 16-bit field, that may or may not be present.
437    donl: Option<u16>,
438    /// payload of the fragmentation unit.
439    payload: Bytes,
440
441    might_need_donl: bool,
442}
443
444impl H265FragmentationUnitPacket {
445    /// with_donl can be called to specify whether or not DONL might be parsed.
446    /// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
447    pub fn with_donl(&mut self, value: bool) {
448        self.might_need_donl = value;
449    }
450
451    /// depacketize parses the passed byte slice and stores the result in the H265FragmentationUnitPacket this method is called upon.
452    fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
453        const TOTAL_HEADER_SIZE: usize = H265NALU_HEADER_SIZE + H265FRAGMENTATION_UNIT_HEADER_SIZE;
454        if payload.len() <= TOTAL_HEADER_SIZE {
455            return Err(Error::ErrShortPacket);
456        }
457
458        let payload_header = H265NALUHeader::new(payload[0], payload[1]);
459        if payload_header.f() {
460            return Err(Error::ErrH265CorruptedPacket);
461        }
462        if !payload_header.is_fragmentation_unit() {
463            return Err(Error::ErrInvalidH265PacketType);
464        }
465
466        let fu_header = H265FragmentationUnitHeader(payload[2]);
467        let mut payload = payload.slice(3..);
468
469        if fu_header.s() && self.might_need_donl {
470            if payload.len() <= 2 {
471                return Err(Error::ErrShortPacket);
472            }
473
474            let donl = ((payload[0] as u16) << 8) | (payload[1] as u16);
475            self.donl = Some(donl);
476            payload = payload.slice(2..);
477        }
478
479        self.payload_header = payload_header;
480        self.fu_header = fu_header;
481        self.payload = payload;
482
483        Ok(())
484    }
485
486    /// payload_header returns the NALU header of the packet.
487    pub fn payload_header(&self) -> H265NALUHeader {
488        self.payload_header
489    }
490
491    /// fu_header returns the Fragmentation Unit Header of the packet.
492    pub fn fu_header(&self) -> H265FragmentationUnitHeader {
493        self.fu_header
494    }
495
496    /// donl returns the DONL of the packet.
497    pub fn donl(&self) -> Option<u16> {
498        self.donl
499    }
500
501    /// payload returns the Fragmentation Unit packet payload.
502    pub fn payload(&self) -> Bytes {
503        self.payload.clone()
504    }
505}
506
507///
508/// PACI implementation
509///
510
511/// H265PACIPacket represents a single H265 PACI packet.
512///
513///  0                   1                   2                   3
514/// 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
515/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516/// |    PayloadHdr (Type=50)       |A|   cType   | phssize |F0..2|Y|
517/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
518/// |        payload Header Extension Structure (phes)              |
519/// |=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=|
520/// |                                                               |
521/// |                  PACI payload: NAL unit                       |
522/// |                   . . .                                       |
523/// |                                                               |
524/// |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
525/// |                               :...OPTIONAL RTP padding        |
526/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
527///
528/// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.4
529#[derive(Default, Debug, Clone, PartialEq, Eq)]
530pub struct H265PACIPacket {
531    /// payload_header is the header of the H265 packet.
532    payload_header: H265NALUHeader,
533
534    /// Field which holds value for `A`, `cType`, `phssize`, `F0`, `F1`, `F2` and `Y` fields.
535    paci_header_fields: u16,
536
537    /// phes is a header extension, of byte length `phssize`
538    phes: Bytes,
539
540    /// payload contains NAL units & optional padding
541    payload: Bytes,
542}
543
544impl H265PACIPacket {
545    /// payload_header returns the NAL Unit Header.
546    pub fn payload_header(&self) -> H265NALUHeader {
547        self.payload_header
548    }
549
550    /// a copies the F bit of the PACI payload NALU.
551    pub fn a(&self) -> bool {
552        const MASK: u16 = 0b10000000 << 8;
553        (self.paci_header_fields & MASK) != 0
554    }
555
556    /// ctype copies the Type field of the PACI payload NALU.
557    pub fn ctype(&self) -> u8 {
558        const MASK: u16 = 0b01111110 << 8;
559        ((self.paci_header_fields & MASK) >> (8 + 1)) as u8
560    }
561
562    /// phs_size indicates the size of the phes field.
563    pub fn phs_size(&self) -> u8 {
564        const MASK: u16 = (0b00000001 << 8) | 0b11110000;
565        ((self.paci_header_fields & MASK) >> 4) as u8
566    }
567
568    /// f0 indicates the presence of a Temporal Scalability support extension in the phes.
569    pub fn f0(&self) -> bool {
570        const MASK: u16 = 0b00001000;
571        (self.paci_header_fields & MASK) != 0
572    }
573
574    /// f1 must be zero, reserved for future extensions.
575    pub fn f1(&self) -> bool {
576        const MASK: u16 = 0b00000100;
577        (self.paci_header_fields & MASK) != 0
578    }
579
580    /// f2 must be zero, reserved for future extensions.
581    pub fn f2(&self) -> bool {
582        const MASK: u16 = 0b00000010;
583        (self.paci_header_fields & MASK) != 0
584    }
585
586    /// y must be zero, reserved for future extensions.
587    pub fn y(&self) -> bool {
588        const MASK: u16 = 0b00000001;
589        (self.paci_header_fields & MASK) != 0
590    }
591
592    /// phes contains header extensions. Its size is indicated by phssize.
593    pub fn phes(&self) -> Bytes {
594        self.phes.clone()
595    }
596
597    /// payload is a single NALU or NALU-like struct, not including the first two octets (header).
598    pub fn payload(&self) -> Bytes {
599        self.payload.clone()
600    }
601
602    /// tsci returns the Temporal Scalability Control Information extension, if present.
603    pub fn tsci(&self) -> Option<H265TSCI> {
604        if !self.f0() || self.phs_size() < 3 {
605            return None;
606        }
607
608        Some(H265TSCI(
609            ((self.phes[0] as u32) << 16) | ((self.phes[1] as u32) << 8) | self.phes[0] as u32,
610        ))
611    }
612
613    /// depacketize parses the passed byte slice and stores the result in the H265PACIPacket this method is called upon.
614    fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
615        const TOTAL_HEADER_SIZE: usize = H265NALU_HEADER_SIZE + 2;
616        if payload.len() <= TOTAL_HEADER_SIZE {
617            return Err(Error::ErrShortPacket);
618        }
619
620        let payload_header = H265NALUHeader::new(payload[0], payload[1]);
621        if payload_header.f() {
622            return Err(Error::ErrH265CorruptedPacket);
623        }
624        if !payload_header.is_paci_packet() {
625            return Err(Error::ErrInvalidH265PacketType);
626        }
627
628        let paci_header_fields = ((payload[2] as u16) << 8) | (payload[3] as u16);
629        let mut payload = payload.slice(4..);
630
631        self.paci_header_fields = paci_header_fields;
632        let header_extension_size = self.phs_size();
633
634        if payload.len() < header_extension_size as usize + 1 {
635            self.paci_header_fields = 0;
636            return Err(Error::ErrShortPacket);
637        }
638
639        self.payload_header = payload_header;
640
641        if header_extension_size > 0 {
642            self.phes = payload.slice(..header_extension_size as usize);
643        }
644
645        payload = payload.slice(header_extension_size as usize..);
646        self.payload = payload;
647
648        Ok(())
649    }
650}
651
652///
653/// Temporal Scalability Control Information
654///
655
656/// H265TSCI is a Temporal Scalability Control Information header extension.
657/// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.5
658#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
659pub struct H265TSCI(pub u32);
660
661impl H265TSCI {
662    /// tl0picidx see RFC7798 for more details.
663    pub fn tl0picidx(&self) -> u8 {
664        const M1: u32 = 0xFFFF0000;
665        const M2: u32 = 0xFF00;
666        ((((self.0 & M1) >> 16) & M2) >> 8) as u8
667    }
668
669    /// irap_pic_id see RFC7798 for more details.
670    pub fn irap_pic_id(&self) -> u8 {
671        const M1: u32 = 0xFFFF0000;
672        const M2: u32 = 0x00FF;
673        (((self.0 & M1) >> 16) & M2) as u8
674    }
675
676    /// s see RFC7798 for more details.
677    pub fn s(&self) -> bool {
678        const M1: u32 = 0xFF00;
679        const M2: u32 = 0b10000000;
680        (((self.0 & M1) >> 8) & M2) != 0
681    }
682
683    /// e see RFC7798 for more details.
684    pub fn e(&self) -> bool {
685        const M1: u32 = 0xFF00;
686        const M2: u32 = 0b01000000;
687        (((self.0 & M1) >> 8) & M2) != 0
688    }
689
690    /// res see RFC7798 for more details.
691    pub fn res(&self) -> u8 {
692        const M1: u32 = 0xFF00;
693        const M2: u32 = 0b00111111;
694        (((self.0 & M1) >> 8) & M2) as u8
695    }
696}
697
698///
699/// H265 Payload Enum
700///
701#[derive(Debug, Clone, PartialEq, Eq)]
702pub enum H265Payload {
703    H265SingleNALUnitPacket(H265SingleNALUnitPacket),
704    H265FragmentationUnitPacket(H265FragmentationUnitPacket),
705    H265AggregationPacket(H265AggregationPacket),
706    H265PACIPacket(H265PACIPacket),
707}
708
709impl Default for H265Payload {
710    fn default() -> Self {
711        H265Payload::H265SingleNALUnitPacket(H265SingleNALUnitPacket::default())
712    }
713}
714
715///
716/// Packet implementation
717///
718
719/// H265Packet represents a H265 packet, stored in the payload of an RTP packet.
720#[derive(Default, Debug, Clone, PartialEq, Eq)]
721pub struct H265Packet {
722    payload: H265Payload,
723    might_need_donl: bool,
724}
725
726impl H265Packet {
727    /// with_donl can be called to specify whether or not DONL might be parsed.
728    /// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
729    pub fn with_donl(&mut self, value: bool) {
730        self.might_need_donl = value;
731    }
732
733    /// payload returns the populated payload.
734    /// Must be casted to one of:
735    /// - H265SingleNALUnitPacket
736    /// - H265FragmentationUnitPacket
737    /// - H265AggregationPacket
738    /// - H265PACIPacket
739    pub fn payload(&self) -> &H265Payload {
740        &self.payload
741    }
742}
743
744impl Depacketizer for H265Packet {
745    /// depacketize parses the passed byte slice and stores the result in the H265Packet this method is called upon
746    fn depacketize(&mut self, payload: &Bytes) -> Result<Bytes> {
747        if payload.len() <= H265NALU_HEADER_SIZE {
748            return Err(Error::ErrShortPacket);
749        }
750
751        let payload_header = H265NALUHeader::new(payload[0], payload[1]);
752        if payload_header.f() {
753            return Err(Error::ErrH265CorruptedPacket);
754        }
755
756        if payload_header.is_paci_packet() {
757            let mut decoded = H265PACIPacket::default();
758            decoded.depacketize(payload)?;
759
760            self.payload = H265Payload::H265PACIPacket(decoded);
761        } else if payload_header.is_fragmentation_unit() {
762            let mut decoded = H265FragmentationUnitPacket::default();
763            decoded.with_donl(self.might_need_donl);
764
765            decoded.depacketize(payload)?;
766
767            self.payload = H265Payload::H265FragmentationUnitPacket(decoded);
768        } else if payload_header.is_aggregation_packet() {
769            let mut decoded = H265AggregationPacket::default();
770            decoded.with_donl(self.might_need_donl);
771
772            decoded.depacketize(payload)?;
773
774            self.payload = H265Payload::H265AggregationPacket(decoded);
775        } else {
776            let mut decoded = H265SingleNALUnitPacket::default();
777            decoded.with_donl(self.might_need_donl);
778
779            decoded.depacketize(payload)?;
780
781            self.payload = H265Payload::H265SingleNALUnitPacket(decoded);
782        }
783
784        Ok(payload.clone())
785    }
786
787    /// is_partition_head checks if this is the head of a packetized nalu stream.
788    fn is_partition_head(&self, _payload: &Bytes) -> bool {
789        //TODO:
790        true
791    }
792
793    fn is_partition_tail(&self, marker: bool, _payload: &Bytes) -> bool {
794        marker
795    }
796}