1use crate::bit_reader::BitReader;
26use crate::BitstreamError;
27
28pub const NAL_TYPE_IDR_W_RADL: u8 = 19;
32pub const NAL_TYPE_IDR_N_LP: u8 = 20;
34pub const NAL_TYPE_CRA: u8 = 21;
36pub const NAL_TYPE_VPS: u8 = 32;
38pub const NAL_TYPE_SPS: u8 = 33;
40pub const NAL_TYPE_PPS: u8 = 34;
42pub const NAL_TYPE_AUD: u8 = 35;
44
45pub fn split_annex_b(buf: &[u8]) -> Vec<&[u8]> {
52 let mut out = Vec::new();
53 let mut i = 0;
54 let n = buf.len();
55 let mut last_payload_start: Option<usize> = None;
56 while i < n {
57 let four =
58 i + 3 < n && buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 0 && buf[i + 3] == 1;
59 let three = !four && i + 2 < n && buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1;
60 if four || three {
61 if let Some(start) = last_payload_start.take() {
62 out.push(&buf[start..i]);
63 }
64 i += if four { 4 } else { 3 };
65 last_payload_start = Some(i);
66 continue;
67 }
68 i += 1;
69 }
70 if let Some(start) = last_payload_start.take() {
71 out.push(&buf[start..n]);
72 }
73 out
74}
75
76pub fn ebsp_to_rbsp(ebsp: &[u8]) -> Vec<u8> {
79 let mut out = Vec::with_capacity(ebsp.len());
80 let mut i = 0;
81 let n = ebsp.len();
82 while i < n {
83 if i + 2 < n && ebsp[i] == 0 && ebsp[i + 1] == 0 && ebsp[i + 2] == 3 {
84 out.push(0);
85 out.push(0);
86 i += 3;
87 } else {
88 out.push(ebsp[i]);
89 i += 1;
90 }
91 }
92 out
93}
94
95pub fn nal_header(b0: u8, b1: u8) -> (u8, u8, u8, u8) {
98 let forbidden = (b0 >> 7) & 1;
99 let nal_unit_type = (b0 >> 1) & 0x3f;
100 let layer_id = ((b0 & 1) << 5) | ((b1 >> 3) & 0x1f);
101 let temporal_id_plus1 = b1 & 0x7;
102 (forbidden, nal_unit_type, layer_id, temporal_id_plus1)
103}
104
105pub fn is_irap(nal_unit_type: u8) -> bool {
108 matches!(
109 nal_unit_type,
110 NAL_TYPE_IDR_W_RADL | NAL_TYPE_IDR_N_LP | NAL_TYPE_CRA
111 )
112}
113
114#[derive(Debug, Clone, Default, PartialEq, Eq)]
120pub struct HevcProfileTierLevel {
121 pub general_profile_space: u8,
122 pub general_tier_flag: bool,
123 pub general_profile_idc: u8,
124 pub general_profile_compatibility_flags: u32,
126 pub general_level_idc: u8,
127}
128
129#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
131pub struct HevcConformanceWindow {
132 pub left: u32,
133 pub right: u32,
134 pub top: u32,
135 pub bottom: u32,
136}
137
138#[derive(Debug, Clone, Default, PartialEq, Eq)]
141pub struct HevcVps {
142 pub vps_video_parameter_set_id: u8,
143 pub vps_max_layers_minus1: u8,
144 pub vps_max_sub_layers_minus1: u8,
145 pub vps_temporal_id_nesting_flag: bool,
146 pub profile_tier_level: HevcProfileTierLevel,
147}
148
149#[derive(Debug, Clone, Default, PartialEq, Eq)]
151pub struct HevcSps {
152 pub sps_video_parameter_set_id: u8,
153 pub sps_max_sub_layers_minus1: u8,
154 pub sps_temporal_id_nesting_flag: bool,
155 pub profile_tier_level: HevcProfileTierLevel,
156
157 pub sps_seq_parameter_set_id: u8,
158 pub chroma_format_idc: u8,
159 pub separate_colour_plane_flag: bool,
160
161 pub pic_width_in_luma_samples: u32,
162 pub pic_height_in_luma_samples: u32,
163 pub conformance_window: Option<HevcConformanceWindow>,
164
165 pub bit_depth_luma_minus8: u8,
166 pub bit_depth_chroma_minus8: u8,
167
168 pub log2_max_pic_order_cnt_lsb_minus4: u8,
169 pub sps_max_dec_pic_buffering_minus1: u32,
171 pub sps_max_num_reorder_pics: u32,
172 pub sps_max_latency_increase_plus1: u32,
173
174 pub log2_min_luma_coding_block_size_minus3: u8,
175 pub log2_diff_max_min_luma_coding_block_size: u8,
176 pub log2_min_luma_transform_block_size_minus2: u8,
177 pub log2_diff_max_min_luma_transform_block_size: u8,
178 pub max_transform_hierarchy_depth_inter: u8,
179 pub max_transform_hierarchy_depth_intra: u8,
180
181 pub scaling_list_enabled_flag: bool,
182 pub amp_enabled_flag: bool,
183 pub sample_adaptive_offset_enabled_flag: bool,
184 pub pcm_enabled_flag: bool,
185 pub num_short_term_ref_pic_sets: u32,
186 pub long_term_ref_pics_present_flag: bool,
187 pub num_long_term_ref_pics_sps: u32,
192 pub sps_temporal_mvp_enabled_flag: bool,
193 pub strong_intra_smoothing_enabled_flag: bool,
194}
195
196impl HevcSps {
197 pub fn coded_width(&self) -> u32 {
199 self.pic_width_in_luma_samples
200 }
201
202 pub fn coded_height(&self) -> u32 {
204 self.pic_height_in_luma_samples
205 }
206
207 fn sub_width_c(&self) -> u32 {
209 match self.chroma_format_idc {
210 1 | 2 => 2,
211 _ => 1,
212 }
213 }
214
215 fn sub_height_c(&self) -> u32 {
216 match self.chroma_format_idc {
217 1 => 2,
218 _ => 1,
219 }
220 }
221
222 pub fn display_width(&self) -> u32 {
225 let Some(c) = self.conformance_window else {
226 return self.coded_width();
227 };
228 let sw = self.sub_width_c();
229 self.coded_width().saturating_sub((c.left + c.right) * sw)
230 }
231
232 pub fn display_height(&self) -> u32 {
234 let Some(c) = self.conformance_window else {
235 return self.coded_height();
236 };
237 let sh = self.sub_height_c();
238 self.coded_height().saturating_sub((c.top + c.bottom) * sh)
239 }
240}
241
242#[derive(Debug, Clone, Default, PartialEq, Eq)]
244pub struct HevcPps {
245 pub pps_pic_parameter_set_id: u8,
246 pub pps_seq_parameter_set_id: u8,
247 pub dependent_slice_segments_enabled_flag: bool,
248 pub output_flag_present_flag: bool,
249 pub num_extra_slice_header_bits: u8,
250 pub sign_data_hiding_enabled_flag: bool,
251 pub cabac_init_present_flag: bool,
252 pub num_ref_idx_l0_default_active_minus1: u8,
253 pub num_ref_idx_l1_default_active_minus1: u8,
254 pub init_qp_minus26: i32,
255 pub constrained_intra_pred_flag: bool,
256 pub transform_skip_enabled_flag: bool,
257 pub cu_qp_delta_enabled_flag: bool,
258 pub diff_cu_qp_delta_depth: u32,
259 pub pps_cb_qp_offset: i32,
260 pub pps_cr_qp_offset: i32,
261 pub pps_slice_chroma_qp_offsets_present_flag: bool,
262 pub weighted_pred_flag: bool,
263 pub weighted_bipred_flag: bool,
264 pub transquant_bypass_enabled_flag: bool,
265 pub tiles_enabled_flag: bool,
266 pub entropy_coding_sync_enabled_flag: bool,
267 pub pps_loop_filter_across_slices_enabled_flag: bool,
270 pub deblocking_filter_control_present_flag: bool,
272 pub deblocking_filter_override_enabled_flag: bool,
275 pub pps_deblocking_filter_disabled_flag: bool,
277 pub pps_beta_offset_div2: i32,
279 pub pps_tc_offset_div2: i32,
281 pub lists_modification_present_flag: bool,
284 pub log2_parallel_merge_level_minus2: u32,
287 pub slice_segment_header_extension_present_flag: bool,
289}
290
291#[derive(Debug, Clone, Default, PartialEq, Eq)]
293pub struct HevcSliceHeader {
294 pub first_slice_segment_in_pic_flag: bool,
295 pub no_output_of_prior_pics_flag: bool,
296 pub slice_pic_parameter_set_id: u8,
297 pub slice_type: u8,
299 pub slice_pic_order_cnt_lsb: u32,
300 pub slice_temporal_mvp_enabled_flag: bool,
301 pub is_irap: bool,
304}
305
306#[derive(Debug)]
308pub struct HevcIdrParse<'a> {
309 pub vps: HevcVps,
310 pub sps: HevcSps,
311 pub pps: HevcPps,
312 pub slice_header: HevcSliceHeader,
313 pub nal_unit_type: u8,
314 pub idr_access_unit: &'a [u8],
315}
316
317fn parse_profile_tier_level(
320 r: &mut BitReader<'_>,
321 profile_present: bool,
322 max_num_sub_layers_minus1: u8,
323) -> Result<HevcProfileTierLevel, BitstreamError> {
324 let mut ptl = HevcProfileTierLevel::default();
325 if profile_present {
326 ptl.general_profile_space = r.u(2) as u8;
327 ptl.general_tier_flag = r.u(1) != 0;
328 ptl.general_profile_idc = r.u(5) as u8;
329 ptl.general_profile_compatibility_flags = r.u(32);
330 let _flags_top = r.u(4);
334 let _flags_mid = r.u(32);
337 let _flags_bot = r.u(11);
338 let _general_inbld_or_reserved = r.u(1);
339 }
340 ptl.general_level_idc = r.u(8) as u8;
341
342 if max_num_sub_layers_minus1 > 0 {
345 let mut sub_layer_profile_present = [false; 7];
346 let mut sub_layer_level_present = [false; 7];
347 for i in 0..max_num_sub_layers_minus1 as usize {
348 sub_layer_profile_present[i] = r.u(1) != 0;
349 sub_layer_level_present[i] = r.u(1) != 0;
350 }
351 for _ in max_num_sub_layers_minus1..8 {
353 let _ = r.u(2);
354 }
355 for i in 0..max_num_sub_layers_minus1 as usize {
356 if sub_layer_profile_present[i] {
357 let _profile_space = r.u(2);
358 let _tier_flag = r.u(1);
359 let _profile_idc = r.u(5);
360 let _compat = r.u(32);
361 let _ = r.u(4);
363 let _ = r.u(32);
364 let _ = r.u(11);
365 let _ = r.u(1);
366 }
367 if sub_layer_level_present[i] {
368 let _sub_level_idc = r.u(8);
369 }
370 }
371 }
372 Ok(ptl)
373}
374
375#[allow(dead_code)]
385fn skip_st_ref_pic_set(_r: &mut BitReader<'_>) -> Result<(), BitstreamError> {
386 Err(BitstreamError::unsupported(
387 "HEVC st_ref_pic_set parsing not implemented in minimal parser",
388 ))
389}
390
391pub fn parse_vps_nal(nal: &[u8]) -> Result<HevcVps, BitstreamError> {
395 if nal.len() < 2 {
396 return Err(BitstreamError::unexpected_end(
397 "VPS NAL shorter than 2 bytes",
398 ));
399 }
400 let (_, nal_type, _, _) = nal_header(nal[0], nal[1]);
401 if nal_type != NAL_TYPE_VPS {
402 return Err(BitstreamError::invalid(format!(
403 "expected VPS NAL (type=32), got type={nal_type}"
404 )));
405 }
406 let rbsp = ebsp_to_rbsp(&nal[2..]);
407 let mut r = BitReader::new(&rbsp);
408 let mut vps = HevcVps {
409 vps_video_parameter_set_id: r.u(4) as u8,
410 ..HevcVps::default()
411 };
412 let _vps_base_layer_internal_flag = r.u(1);
413 let _vps_base_layer_available_flag = r.u(1);
414 vps.vps_max_layers_minus1 = r.u(6) as u8;
415 vps.vps_max_sub_layers_minus1 = r.u(3) as u8;
416 vps.vps_temporal_id_nesting_flag = r.u(1) != 0;
417 let _vps_reserved_0xffff_16bits = r.u(16);
418 vps.profile_tier_level = parse_profile_tier_level(&mut r, true, vps.vps_max_sub_layers_minus1)?;
419 Ok(vps)
422}
423
424pub fn parse_sps_nal(nal: &[u8]) -> Result<HevcSps, BitstreamError> {
426 if nal.len() < 2 {
427 return Err(BitstreamError::unexpected_end(
428 "SPS NAL shorter than 2 bytes",
429 ));
430 }
431 let (_, nal_type, _, _) = nal_header(nal[0], nal[1]);
432 if nal_type != NAL_TYPE_SPS {
433 return Err(BitstreamError::invalid(format!(
434 "expected SPS NAL (type=33), got type={nal_type}"
435 )));
436 }
437 let rbsp = ebsp_to_rbsp(&nal[2..]);
438 let mut r = BitReader::new(&rbsp);
439 let mut sps = HevcSps {
440 sps_video_parameter_set_id: r.u(4) as u8,
441 sps_max_sub_layers_minus1: r.u(3) as u8,
442 sps_temporal_id_nesting_flag: r.u(1) != 0,
443 ..HevcSps::default()
444 };
445 sps.profile_tier_level = parse_profile_tier_level(&mut r, true, sps.sps_max_sub_layers_minus1)?;
446 sps.sps_seq_parameter_set_id = r.ue()? as u8;
447 sps.chroma_format_idc = r.ue()? as u8;
448 if sps.chroma_format_idc == 3 {
449 sps.separate_colour_plane_flag = r.u(1) != 0;
450 }
451 sps.pic_width_in_luma_samples = r.ue()?;
452 sps.pic_height_in_luma_samples = r.ue()?;
453 let conformance_window_flag = r.u(1);
454 if conformance_window_flag != 0 {
455 sps.conformance_window = Some(HevcConformanceWindow {
456 left: r.ue()?,
457 right: r.ue()?,
458 top: r.ue()?,
459 bottom: r.ue()?,
460 });
461 }
462 sps.bit_depth_luma_minus8 = r.ue()? as u8;
463 sps.bit_depth_chroma_minus8 = r.ue()? as u8;
464 sps.log2_max_pic_order_cnt_lsb_minus4 = r.ue()? as u8;
465
466 let sps_sub_layer_ordering_info_present_flag = r.u(1);
467 let start = if sps_sub_layer_ordering_info_present_flag != 0 {
468 0
469 } else {
470 sps.sps_max_sub_layers_minus1 as usize
471 };
472 let mut last_max_dec = 0u32;
476 let mut last_max_reorder = 0u32;
477 let mut last_max_latency = 0u32;
478 for _ in start..=sps.sps_max_sub_layers_minus1 as usize {
479 last_max_dec = r.ue()?;
480 last_max_reorder = r.ue()?;
481 last_max_latency = r.ue()?;
482 }
483 sps.sps_max_dec_pic_buffering_minus1 = last_max_dec;
484 sps.sps_max_num_reorder_pics = last_max_reorder;
485 sps.sps_max_latency_increase_plus1 = last_max_latency;
486
487 sps.log2_min_luma_coding_block_size_minus3 = r.ue()? as u8;
488 sps.log2_diff_max_min_luma_coding_block_size = r.ue()? as u8;
489 sps.log2_min_luma_transform_block_size_minus2 = r.ue()? as u8;
490 sps.log2_diff_max_min_luma_transform_block_size = r.ue()? as u8;
491 sps.max_transform_hierarchy_depth_inter = r.ue()? as u8;
492 sps.max_transform_hierarchy_depth_intra = r.ue()? as u8;
493
494 sps.scaling_list_enabled_flag = r.u(1) != 0;
495 if sps.scaling_list_enabled_flag {
496 return Err(BitstreamError::unsupported(
497 "HEVC SPS scaling_list_enabled_flag=1 not supported by minimal parser",
498 ));
499 }
500 sps.amp_enabled_flag = r.u(1) != 0;
501 sps.sample_adaptive_offset_enabled_flag = r.u(1) != 0;
502 sps.pcm_enabled_flag = r.u(1) != 0;
503 if sps.pcm_enabled_flag {
504 return Err(BitstreamError::unsupported(
505 "HEVC SPS pcm_enabled_flag=1 not supported by minimal parser",
506 ));
507 }
508 sps.num_short_term_ref_pic_sets = r.ue()?;
509 if sps.num_short_term_ref_pic_sets > 0 {
510 return Err(BitstreamError::unsupported(
511 "HEVC SPS num_short_term_ref_pic_sets>0 not supported by minimal parser",
512 ));
513 }
514 sps.long_term_ref_pics_present_flag = r.u(1) != 0;
515 if sps.long_term_ref_pics_present_flag {
516 return Err(BitstreamError::unsupported(
517 "HEVC SPS long_term_ref_pics_present_flag=1 not supported by minimal parser",
518 ));
519 }
520 sps.sps_temporal_mvp_enabled_flag = r.u(1) != 0;
521 sps.strong_intra_smoothing_enabled_flag = r.u(1) != 0;
522 Ok(sps)
524}
525
526pub fn parse_pps_nal(nal: &[u8]) -> Result<HevcPps, BitstreamError> {
528 if nal.len() < 2 {
529 return Err(BitstreamError::unexpected_end(
530 "PPS NAL shorter than 2 bytes",
531 ));
532 }
533 let (_, nal_type, _, _) = nal_header(nal[0], nal[1]);
534 if nal_type != NAL_TYPE_PPS {
535 return Err(BitstreamError::invalid(format!(
536 "expected PPS NAL (type=34), got type={nal_type}"
537 )));
538 }
539 let rbsp = ebsp_to_rbsp(&nal[2..]);
540 let mut r = BitReader::new(&rbsp);
541 let mut pps = HevcPps {
542 pps_pic_parameter_set_id: r.ue()? as u8,
543 pps_seq_parameter_set_id: r.ue()? as u8,
544 dependent_slice_segments_enabled_flag: r.u(1) != 0,
545 output_flag_present_flag: r.u(1) != 0,
546 num_extra_slice_header_bits: r.u(3) as u8,
547 sign_data_hiding_enabled_flag: r.u(1) != 0,
548 cabac_init_present_flag: r.u(1) != 0,
549 num_ref_idx_l0_default_active_minus1: r.ue()? as u8,
550 num_ref_idx_l1_default_active_minus1: r.ue()? as u8,
551 init_qp_minus26: r.se()?,
552 constrained_intra_pred_flag: r.u(1) != 0,
553 transform_skip_enabled_flag: r.u(1) != 0,
554 cu_qp_delta_enabled_flag: r.u(1) != 0,
555 ..HevcPps::default()
556 };
557 if pps.cu_qp_delta_enabled_flag {
558 pps.diff_cu_qp_delta_depth = r.ue()?;
559 }
560 pps.pps_cb_qp_offset = r.se()?;
561 pps.pps_cr_qp_offset = r.se()?;
562 pps.pps_slice_chroma_qp_offsets_present_flag = r.u(1) != 0;
563 pps.weighted_pred_flag = r.u(1) != 0;
564 pps.weighted_bipred_flag = r.u(1) != 0;
565 pps.transquant_bypass_enabled_flag = r.u(1) != 0;
566 pps.tiles_enabled_flag = r.u(1) != 0;
567 pps.entropy_coding_sync_enabled_flag = r.u(1) != 0;
568 if pps.tiles_enabled_flag {
569 return Err(BitstreamError::unsupported(
570 "HEVC PPS tiles_enabled_flag=1 not supported by minimal parser",
571 ));
572 }
573 if pps.entropy_coding_sync_enabled_flag {
574 return Err(BitstreamError::unsupported(
575 "HEVC PPS entropy_coding_sync_enabled_flag=1 (WPP) not supported by minimal parser",
576 ));
577 }
578 pps.pps_loop_filter_across_slices_enabled_flag = r.u(1) != 0;
581 pps.deblocking_filter_control_present_flag = r.u(1) != 0;
582 if pps.deblocking_filter_control_present_flag {
583 pps.deblocking_filter_override_enabled_flag = r.u(1) != 0;
584 pps.pps_deblocking_filter_disabled_flag = r.u(1) != 0;
585 if !pps.pps_deblocking_filter_disabled_flag {
586 pps.pps_beta_offset_div2 = r.se()?;
587 pps.pps_tc_offset_div2 = r.se()?;
588 }
589 }
590 let pps_scaling_list_data_present_flag = r.u(1);
591 if pps_scaling_list_data_present_flag != 0 {
592 return Err(BitstreamError::unsupported(
593 "HEVC PPS pps_scaling_list_data_present_flag=1 not supported by minimal parser",
594 ));
595 }
596 pps.lists_modification_present_flag = r.u(1) != 0;
597 pps.log2_parallel_merge_level_minus2 = r.ue()?;
598 pps.slice_segment_header_extension_present_flag = r.u(1) != 0;
599 Ok(pps)
603}
604
605pub fn parse_slice_header_minimal(
609 nal: &[u8],
610 sps: &HevcSps,
611 pps: &HevcPps,
612) -> Result<HevcSliceHeader, BitstreamError> {
613 if nal.len() < 2 {
614 return Err(BitstreamError::unexpected_end(
615 "slice NAL shorter than 2 bytes",
616 ));
617 }
618 let (_, nal_unit_type, _, _) = nal_header(nal[0], nal[1]);
619 let is_irap_slice = is_irap(nal_unit_type);
620
621 let rbsp = ebsp_to_rbsp(&nal[2..]);
622 let mut r = BitReader::new(&rbsp);
623 let mut sh = HevcSliceHeader {
624 first_slice_segment_in_pic_flag: r.u(1) != 0,
625 ..HevcSliceHeader::default()
626 };
627
628 if is_irap_slice {
629 sh.no_output_of_prior_pics_flag = r.u(1) != 0;
630 }
631 sh.slice_pic_parameter_set_id = r.ue()? as u8;
632
633 let dependent_slice_segment_flag =
634 if !sh.first_slice_segment_in_pic_flag && pps.dependent_slice_segments_enabled_flag {
635 r.u(1) != 0
636 } else {
637 false
638 };
639 if dependent_slice_segment_flag {
640 return Err(BitstreamError::unsupported(
641 "HEVC dependent slice segments not supported by minimal parser",
642 ));
643 }
644 if !sh.first_slice_segment_in_pic_flag {
645 let ctb_log2 = sps.log2_min_luma_coding_block_size_minus3 as u32
648 + 3
649 + sps.log2_diff_max_min_luma_coding_block_size as u32;
650 let ctb_size = 1u32 << ctb_log2;
651 let pic_w_in_ctbs = sps.pic_width_in_luma_samples.div_ceil(ctb_size);
652 let pic_h_in_ctbs = sps.pic_height_in_luma_samples.div_ceil(ctb_size);
653 let total_ctbs = pic_w_in_ctbs as u64 * pic_h_in_ctbs as u64;
654 let bits = 64 - total_ctbs.leading_zeros();
655 let _slice_segment_address = r.u(bits);
656 }
657
658 for _ in 0..pps.num_extra_slice_header_bits {
660 let _ = r.u(1);
661 }
662 sh.slice_type = r.ue()? as u8;
663
664 if pps.output_flag_present_flag {
665 let _pic_output_flag = r.u(1);
666 }
667 if sps.separate_colour_plane_flag {
668 let _colour_plane_id = r.u(2);
669 }
670
671 if !matches!(nal_unit_type, NAL_TYPE_IDR_W_RADL | NAL_TYPE_IDR_N_LP) {
673 sh.slice_pic_order_cnt_lsb = r.u(sps.log2_max_pic_order_cnt_lsb_minus4 as u32 + 4);
674 } else {
678 sh.slice_pic_order_cnt_lsb = 0;
679 }
680
681 sh.is_irap = is_irap_slice;
682 Ok(sh)
688}
689
690pub fn parse_idr_only(stream: &[u8]) -> Result<HevcIdrParse<'_>, BitstreamError> {
694 let nals = locate_annex_b(stream);
695 if nals.is_empty() {
696 return Err(BitstreamError::invalid("no NAL units found in stream"));
697 }
698
699 let mut vps: Option<HevcVps> = None;
700 let mut sps: Option<HevcSps> = None;
701 let mut pps: Option<HevcPps> = None;
702 let mut irap_idx: Option<usize> = None;
703 let mut irap_nal_type: u8 = 0;
704 for (idx, n) in nals.iter().enumerate() {
705 let body = &stream[n.body_start..n.body_end];
706 if body.len() < 2 {
707 continue;
708 }
709 let (_, nal_type, _, _) = nal_header(body[0], body[1]);
710 match nal_type {
711 NAL_TYPE_VPS if vps.is_none() => vps = Some(parse_vps_nal(body)?),
712 NAL_TYPE_SPS if sps.is_none() => sps = Some(parse_sps_nal(body)?),
713 NAL_TYPE_PPS if pps.is_none() => pps = Some(parse_pps_nal(body)?),
714 t if is_irap(t) && irap_idx.is_none() => {
715 irap_idx = Some(idx);
716 irap_nal_type = t;
717 }
718 _ => {}
719 }
720 }
721 let vps = vps.ok_or_else(|| BitstreamError::invalid("stream has no VPS"))?;
722 let sps = sps.ok_or_else(|| BitstreamError::invalid("stream has no SPS"))?;
723 let pps = pps.ok_or_else(|| BitstreamError::invalid("stream has no PPS"))?;
724 let irap_idx = irap_idx.ok_or_else(|| BitstreamError::invalid("stream has no IRAP slice"))?;
725 let irap = &nals[irap_idx];
726 let body = &stream[irap.body_start..irap.body_end];
727 let slice_header = parse_slice_header_minimal(body, &sps, &pps)?;
728 let access_unit = &stream[irap.start_code_start..];
729 Ok(HevcIdrParse {
730 vps,
731 sps,
732 pps,
733 slice_header,
734 nal_unit_type: irap_nal_type,
735 idr_access_unit: access_unit,
736 })
737}
738
739#[derive(Debug, Clone, Copy)]
742struct NalLoc {
743 start_code_start: usize,
744 body_start: usize,
745 body_end: usize,
746}
747
748fn locate_annex_b(buf: &[u8]) -> Vec<NalLoc> {
749 let mut out = Vec::new();
750 let mut i = 0;
751 let n = buf.len();
752 let mut current: Option<(usize, usize)> = None;
753 while i < n {
754 let four =
755 i + 3 < n && buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 0 && buf[i + 3] == 1;
756 let three = !four && i + 2 < n && buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1;
757 if four || three {
758 if let Some((sc, body_start)) = current.take() {
759 out.push(NalLoc {
760 start_code_start: sc,
761 body_start,
762 body_end: i,
763 });
764 }
765 let sc = i;
766 i += if four { 4 } else { 3 };
767 current = Some((sc, i));
768 continue;
769 }
770 i += 1;
771 }
772 if let Some((sc, body_start)) = current.take() {
773 out.push(NalLoc {
774 start_code_start: sc,
775 body_start,
776 body_end: n,
777 });
778 }
779 out
780}
781
782#[cfg(test)]
785mod tests {
786 use super::*;
787
788 #[test]
789 fn split_finds_three_nals() {
790 let buf = [
791 0, 0, 0, 1, 0x40, 0x01, 0xaa, 0, 0, 1, 0x42, 0x01, 0xbb, 0, 0, 0, 1, 0x28, 0x01, 0xcc, ];
795 let nals = split_annex_b(&buf);
796 assert_eq!(nals.len(), 3);
797 }
798
799 #[test]
800 fn nal_header_decodes_vps() {
801 let (f, t, l, tid) = nal_header(0x40, 0x01);
804 assert_eq!(f, 0);
805 assert_eq!(t, NAL_TYPE_VPS);
806 assert_eq!(l, 0);
807 assert_eq!(tid, 1);
808 }
809
810 #[test]
811 fn ebsp_to_rbsp_strips_03_in_zero_zero_run() {
812 let ebsp = [0x00, 0x00, 0x03, 0x01];
813 let rbsp = ebsp_to_rbsp(&ebsp);
814 assert_eq!(rbsp, &[0x00, 0x00, 0x01]);
815 }
816}