xref: /webrtc/rtp/src/codecs/h265/mod.rs (revision ffe74184)
1 use crate::error::{Error, Result};
2 use crate::packetizer::Depacketizer;
3 use bytes::Bytes;
4 
5 #[cfg(test)]
6 mod h265_test;
7 
8 ///
9 /// Network Abstraction Unit Header implementation
10 ///
11 
12 const H265NALU_HEADER_SIZE: usize = 2;
13 /// https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
14 const H265NALU_AGGREGATION_PACKET_TYPE: u8 = 48;
15 /// https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3
16 const H265NALU_FRAGMENTATION_UNIT_TYPE: u8 = 49;
17 /// https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.4
18 const 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)]
28 pub struct H265NALUHeader(pub u16);
29 
30 impl H265NALUHeader {
new(high_byte: u8, low_byte: u8) -> Self31     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.
f(&self) -> bool36     pub fn f(&self) -> bool {
37         (self.0 >> 15) != 0
38     }
39 
40     /// nalu_type of NAL Unit.
nalu_type(&self) -> u841     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.
is_type_vcl_unit(&self) -> bool48     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.
layer_id(&self) -> u855     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.
tid(&self) -> u862     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.
is_aggregation_packet(&self) -> bool68     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.
is_fragmentation_unit(&self) -> bool73     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.
is_paci_packet(&self) -> bool78     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)]
101 pub 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 
112 impl 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.
with_donl(&mut self, value: bool)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.
depacketize(&mut self, payload: &Bytes) -> Result<()>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.
payload_header(&self) -> H265NALUHeader156     pub fn payload_header(&self) -> H265NALUHeader {
157         self.payload_header
158     }
159 
160     /// donl returns the DONL of the packet.
donl(&self) -> Option<u16>161     pub fn donl(&self) -> Option<u16> {
162         self.donl
163     }
164 
165     /// payload returns the Fragmentation Unit packet payload.
payload(&self) -> Bytes166     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)]
190 pub struct H265AggregationUnitFirst {
191     donl: Option<u16>,
192     nal_unit_size: u16,
193     nal_unit: Bytes,
194 }
195 
196 impl 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.
donl(&self) -> Option<u16>200     pub fn donl(&self) -> Option<u16> {
201         self.donl
202     }
203 
204     /// nalu_size represents the size, in bytes, of the nal_unit.
nalu_size(&self) -> u16205     pub fn nalu_size(&self) -> u16 {
206         self.nal_unit_size
207     }
208 
209     /// nal_unit payload.
nal_unit(&self) -> Bytes210     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)]
230 pub struct H265AggregationUnit {
231     dond: Option<u8>,
232     nal_unit_size: u16,
233     nal_unit: Bytes,
234 }
235 
236 impl 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.
dond(&self) -> Option<u8>240     pub fn dond(&self) -> Option<u8> {
241         self.dond
242     }
243 
244     /// nalu_size represents the size, in bytes, of the nal_unit.
nalu_size(&self) -> u16245     pub fn nalu_size(&self) -> u16 {
246         self.nal_unit_size
247     }
248 
249     /// nal_unit payload.
nal_unit(&self) -> Bytes250     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)]
270 pub struct H265AggregationPacket {
271     first_unit: Option<H265AggregationUnitFirst>,
272     other_units: Vec<H265AggregationUnit>,
273 
274     might_need_donl: bool,
275 }
276 
277 impl 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.
with_donl(&mut self, value: bool)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.
depacketize(&mut self, payload: &Bytes) -> Result<()>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.
first_unit(&self) -> Option<&H265AggregationUnitFirst>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).
other_units(&self) -> &[H265AggregationUnit]374     pub fn other_units(&self) -> &[H265AggregationUnit] {
375         self.other_units.as_slice()
376     }
377 }
378 
379 ///
380 /// Fragmentation Unit implementation
381 ///
382 
383 const 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)]
392 pub struct H265FragmentationUnitHeader(pub u8);
393 
394 impl H265FragmentationUnitHeader {
395     /// s represents the start of a fragmented NAL unit.
s(&self) -> bool396     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.
e(&self) -> bool402     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.
fu_type(&self) -> u8408     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)]
431 pub 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 
444 impl 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.
with_donl(&mut self, value: bool)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.
depacketize(&mut self, payload: &Bytes) -> Result<()>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.
payload_header(&self) -> H265NALUHeader487     pub fn payload_header(&self) -> H265NALUHeader {
488         self.payload_header
489     }
490 
491     /// fu_header returns the Fragmentation Unit Header of the packet.
fu_header(&self) -> H265FragmentationUnitHeader492     pub fn fu_header(&self) -> H265FragmentationUnitHeader {
493         self.fu_header
494     }
495 
496     /// donl returns the DONL of the packet.
donl(&self) -> Option<u16>497     pub fn donl(&self) -> Option<u16> {
498         self.donl
499     }
500 
501     /// payload returns the Fragmentation Unit packet payload.
payload(&self) -> Bytes502     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)]
530 pub 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 
544 impl H265PACIPacket {
545     /// payload_header returns the NAL Unit Header.
payload_header(&self) -> H265NALUHeader546     pub fn payload_header(&self) -> H265NALUHeader {
547         self.payload_header
548     }
549 
550     /// a copies the F bit of the PACI payload NALU.
a(&self) -> bool551     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.
ctype(&self) -> u8557     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.
phs_size(&self) -> u8563     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.
f0(&self) -> bool569     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.
f1(&self) -> bool575     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.
f2(&self) -> bool581     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.
y(&self) -> bool587     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.
phes(&self) -> Bytes593     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).
payload(&self) -> Bytes598     pub fn payload(&self) -> Bytes {
599         self.payload.clone()
600     }
601 
602     /// tsci returns the Temporal Scalability Control Information extension, if present.
tsci(&self) -> Option<H265TSCI>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.
depacketize(&mut self, payload: &Bytes) -> Result<()>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)]
659 pub struct H265TSCI(pub u32);
660 
661 impl H265TSCI {
662     /// tl0picidx see RFC7798 for more details.
tl0picidx(&self) -> u8663     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.
irap_pic_id(&self) -> u8670     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.
s(&self) -> bool677     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.
e(&self) -> bool684     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.
res(&self) -> u8691     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)]
702 pub enum H265Payload {
703     H265SingleNALUnitPacket(H265SingleNALUnitPacket),
704     H265FragmentationUnitPacket(H265FragmentationUnitPacket),
705     H265AggregationPacket(H265AggregationPacket),
706     H265PACIPacket(H265PACIPacket),
707 }
708 
709 impl Default for H265Payload {
default() -> Self710     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)]
721 pub struct H265Packet {
722     payload: H265Payload,
723     might_need_donl: bool,
724 }
725 
726 impl 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.
with_donl(&mut self, value: bool)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
payload(&self) -> &H265Payload739     pub fn payload(&self) -> &H265Payload {
740         &self.payload
741     }
742 }
743 
744 impl Depacketizer for H265Packet {
745     /// depacketize parses the passed byte slice and stores the result in the H265Packet this method is called upon
depacketize(&mut self, payload: &Bytes) -> Result<Bytes>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.
is_partition_head(&self, _payload: &Bytes) -> bool788     fn is_partition_head(&self, _payload: &Bytes) -> bool {
789         //TODO:
790         true
791     }
792 
is_partition_tail(&self, marker: bool, _payload: &Bytes) -> bool793     fn is_partition_tail(&self, marker: bool, _payload: &Bytes) -> bool {
794         marker
795     }
796 }
797