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