1use crate::frame::PixelFormat;
16
17pub fn detect(codec: &str, samples: &[Vec<u8>]) -> PixelFormat {
22 if samples.is_empty() {
23 return PixelFormat::Yuv420p;
24 }
25
26 let result = match codec.to_lowercase().as_str() {
27 "h264" | "avc1" | "avc" => detect_h264(&samples[0]),
28 "h265" | "hevc" | "hvc1" | "hev1" => detect_hevc(&samples[0]),
29 "vp9" | "vp09" => detect_vp9(&samples[0]),
30 "av1" | "av01" => detect_av1(&samples[0]),
31 _ => None,
32 };
33
34 result.unwrap_or(PixelFormat::Yuv420p)
35}
36
37struct BitReader<'a> {
39 data: &'a [u8],
40 pos: usize,
41}
42
43impl<'a> BitReader<'a> {
44 fn new(data: &'a [u8]) -> Self {
45 Self { data, pos: 0 }
46 }
47
48 fn read_bits(&mut self, n: usize) -> Option<u32> {
49 let mut val = 0u32;
50 for _ in 0..n {
51 let byte_idx = self.pos / 8;
52 let bit_idx = 7 - (self.pos % 8);
53 if byte_idx >= self.data.len() {
54 return None;
55 }
56 val = (val << 1) | (((self.data[byte_idx] >> bit_idx) & 1) as u32);
57 self.pos += 1;
58 }
59 Some(val)
60 }
61
62 fn read_ue(&mut self) -> Option<u32> {
64 let mut zeros = 0;
65 while self.read_bits(1)? == 0 {
66 zeros += 1;
67 if zeros > 31 {
68 return None;
72 }
73 }
74 if zeros == 0 {
75 return Some(0);
76 }
77 let suffix = self.read_bits(zeros)?;
78 Some((1u32 << zeros) - 1 + suffix)
79 }
80
81 fn read_se(&mut self) -> Option<i32> {
87 let code = self.read_ue()? as i64;
88 let signed = if code & 1 == 1 {
89 ((code + 1) / 2) as i32
90 } else {
91 -((code / 2) as i32)
92 };
93 Some(signed)
94 }
95
96 fn bit_pos(&self) -> usize {
99 self.pos
100 }
101
102 fn byte_align(&mut self) {
105 let rem = self.pos & 7;
106 if rem != 0 {
107 self.pos += 8 - rem;
108 }
109 }
110
111 fn read_su(&mut self, n: usize) -> Option<i32> {
114 let raw = self.read_bits(n)?;
115 let sign_bit = 1u32 << (n - 1);
116 let signed = if raw & sign_bit != 0 {
117 (raw as i32) - (1i32 << n)
118 } else {
119 raw as i32
120 };
121 Some(signed)
122 }
123}
124
125fn detect_h264(sample: &[u8]) -> Option<PixelFormat> {
131 let sps = find_h264_sps(sample)?;
132 let rbsp = remove_h264_rbsp_stuffing(sps);
133 let mut br = BitReader::new(&rbsp);
134
135 let profile_idc = br.read_bits(8)? as u8;
136 let _constraint_flags = br.read_bits(8)?;
137 let _level_idc = br.read_bits(8)?;
138 let _seq_parameter_set_id = br.read_ue()?;
139
140 let profile_gates_chroma = matches!(
141 profile_idc,
142 100 | 110 | 122 | 244 | 44 | 83 | 86 | 118 | 128 | 138 | 139 | 134 | 135
143 );
144
145 let (chroma_format_idc, bit_depth_luma) = if profile_gates_chroma {
146 let chroma_format_idc = br.read_ue()? as u8;
147 if chroma_format_idc == 3 {
148 let _separate_colour_plane_flag = br.read_bits(1)?;
149 }
150 let bit_depth_luma_minus8 = br.read_ue()? as u8;
151 (chroma_format_idc, bit_depth_luma_minus8 + 8)
152 } else {
153 (1, 8)
155 };
156
157 Some(PixelFormat::from_chroma_and_depth(
158 chroma_format_idc,
159 bit_depth_luma,
160 ))
161}
162
163fn find_h264_sps(data: &[u8]) -> Option<&[u8]> {
167 let mut i = 0;
168 while i + 4 < data.len() {
169 let (start_len, nal_byte) = if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 {
170 (3, i + 3)
171 } else if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 1 {
172 (4, i + 4)
173 } else {
174 i += 1;
175 continue;
176 };
177 if nal_byte >= data.len() {
178 return None;
179 }
180 let nal_unit_type = data[nal_byte] & 0x1F;
181 if nal_unit_type == 7 {
182 let start = nal_byte + 1;
184 let end = find_next_start_code(&data[start..])
185 .map(|off| start + off)
186 .unwrap_or(data.len());
187 return Some(&data[start..end]);
188 }
189 i += start_len;
190 }
191 None
192}
193
194fn find_next_start_code(data: &[u8]) -> Option<usize> {
195 (0..data.len().saturating_sub(3)).find(|&i| {
196 data[i] == 0
197 && data[i + 1] == 0
198 && (data[i + 2] == 1 || (data[i + 2] == 0 && data[i + 3] == 1))
199 })
200}
201
202fn remove_h264_rbsp_stuffing(sps: &[u8]) -> Vec<u8> {
204 let mut out = Vec::with_capacity(sps.len());
205 let mut i = 0;
206 while i < sps.len() {
207 if i + 2 < sps.len() && sps[i] == 0 && sps[i + 1] == 0 && sps[i + 2] == 3 {
208 out.push(0);
209 out.push(0);
210 i += 3;
211 } else {
212 out.push(sps[i]);
213 i += 1;
214 }
215 }
216 out
217}
218
219fn detect_hevc(sample: &[u8]) -> Option<PixelFormat> {
223 let sps = find_hevc_sps(sample)?;
224 let rbsp = remove_h264_rbsp_stuffing(sps);
225 let mut br = BitReader::new(&rbsp);
226
227 let _sps_video_parameter_set_id = br.read_bits(4)?;
228 let sps_max_sub_layers_minus1 = br.read_bits(3)? as usize;
229 let _sps_temporal_id_nesting_flag = br.read_bits(1)?;
230
231 skip_hevc_profile_tier_level(&mut br, sps_max_sub_layers_minus1)?;
235
236 let _sps_seq_parameter_set_id = br.read_ue()?;
237 let chroma_format_idc = br.read_ue()? as u8;
238 if chroma_format_idc == 3 {
239 let _separate_colour_plane_flag = br.read_bits(1)?;
240 }
241 let _pic_width = br.read_ue()?;
242 let _pic_height = br.read_ue()?;
243 let conformance_window_flag = br.read_bits(1)?;
244 if conformance_window_flag == 1 {
245 let _ = br.read_ue()?;
246 let _ = br.read_ue()?;
247 let _ = br.read_ue()?;
248 let _ = br.read_ue()?;
249 }
250 let bit_depth_luma = br.read_ue()? as u8 + 8;
251 let _bit_depth_chroma_minus8 = br.read_ue()?;
252
253 Some(PixelFormat::from_chroma_and_depth(
254 chroma_format_idc,
255 bit_depth_luma,
256 ))
257}
258
259fn find_hevc_sps(data: &[u8]) -> Option<&[u8]> {
260 let mut i = 0;
261 while i + 4 < data.len() {
262 let (start_len, nal_byte) = if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 {
263 (3, i + 3)
264 } else if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 1 {
265 (4, i + 4)
266 } else {
267 i += 1;
268 continue;
269 };
270 if nal_byte + 1 >= data.len() {
271 return None;
272 }
273 let nal_unit_type = (data[nal_byte] >> 1) & 0x3F;
275 if nal_unit_type == 33 {
276 let start = nal_byte + 2;
278 let end = find_next_start_code(&data[start..])
279 .map(|off| start + off)
280 .unwrap_or(data.len());
281 return Some(&data[start..end]);
282 }
283 i += start_len;
284 }
285 None
286}
287
288fn skip_hevc_profile_tier_level(br: &mut BitReader, max_sub_layers_minus1: usize) -> Option<()> {
289 let _ = br.read_bits(8)?;
291 let _ = br.read_bits(32)?;
293 let _ = br.read_bits(48)?;
296 let _ = br.read_bits(8)?;
297
298 let mut sub_layer_profile_present = Vec::with_capacity(max_sub_layers_minus1);
300 let mut sub_layer_level_present = Vec::with_capacity(max_sub_layers_minus1);
301 for _ in 0..max_sub_layers_minus1 {
302 sub_layer_profile_present.push(br.read_bits(1)?);
303 sub_layer_level_present.push(br.read_bits(1)?);
304 }
305 if max_sub_layers_minus1 > 0 {
306 for _ in max_sub_layers_minus1..8 {
308 let _ = br.read_bits(2)?;
309 }
310 }
311 for i in 0..max_sub_layers_minus1 {
312 if sub_layer_profile_present[i] == 1 {
313 let _ = br.read_bits(8)?;
314 let _ = br.read_bits(32)?;
315 let _ = br.read_bits(48)?;
316 }
317 if sub_layer_level_present[i] == 1 {
318 let _ = br.read_bits(8)?;
319 }
320 }
321 Some(())
322}
323
324fn detect_vp9(sample: &[u8]) -> Option<PixelFormat> {
328 if sample.len() < 2 {
329 return None;
330 }
331 let mut br = BitReader::new(sample);
332 let frame_marker = br.read_bits(2)?;
333 if frame_marker != 2 {
334 return None;
335 }
336 let profile_low = br.read_bits(1)?;
337 let profile_high = br.read_bits(1)?;
338 let profile = (profile_high << 1) | profile_low;
339 if profile == 3 {
340 let _reserved_zero = br.read_bits(1)?;
341 }
342 let show_existing_frame = br.read_bits(1)?;
343 if show_existing_frame == 1 {
344 return None;
345 }
346 let frame_type = br.read_bits(1)?;
347 let _show_frame = br.read_bits(1)?;
348 let _error_resilient = br.read_bits(1)?;
349
350 if frame_type != 0 {
352 return None;
353 }
354
355 let sync = br.read_bits(24)?;
357 if sync != 0x498342 {
358 return None;
359 }
360
361 let bit_depth = if profile >= 2 {
362 if br.read_bits(1)? == 0 { 10 } else { 12 }
363 } else {
364 8
365 };
366 let _color_space = br.read_bits(3)?;
367 let (sx, sy) = if profile == 1 || profile == 3 {
371 let _color_range = br.read_bits(1)?;
372 let sx = br.read_bits(1)?;
373 let sy = br.read_bits(1)?;
374 (sx, sy)
375 } else {
376 (1, 1) };
378
379 let chroma_idc = match (sx, sy) {
380 (1, 1) => 1, (1, 0) => 2, (0, 0) => 3, _ => 1,
384 };
385
386 Some(PixelFormat::from_chroma_and_depth(chroma_idc, bit_depth))
387}
388
389fn detect_av1(sample: &[u8]) -> Option<PixelFormat> {
394 let obu = find_av1_obu(sample, 1)?;
396 let mut br = BitReader::new(obu);
397
398 let _seq_profile = br.read_bits(3)?;
399 let _still_picture = br.read_bits(1)?;
400 let reduced_still_picture_header = br.read_bits(1)?;
401
402 if reduced_still_picture_header == 0 {
403 let timing_info_present = br.read_bits(1)?;
407 if timing_info_present == 1 {
408 let _num_units_in_display_tick = br.read_bits(32)?;
409 let _time_scale = br.read_bits(32)?;
410 let equal_picture_interval = br.read_bits(1)?;
411 if equal_picture_interval == 1 {
412 let _num_ticks_per_picture = br.read_ue()?; }
414 let decoder_model_info_present = br.read_bits(1)?;
415 if decoder_model_info_present == 1 {
416 let _buffer_delay_length_minus_1 = br.read_bits(5)?;
417 let _num_units_in_decoding_tick = br.read_bits(32)?;
418 let _buffer_removal_time_length_minus_1 = br.read_bits(5)?;
419 let _frame_presentation_time_length_minus_1 = br.read_bits(5)?;
420 }
421 }
422 return Some(PixelFormat::Yuv420p);
429 }
430
431 let _seq_level_idx_0 = br.read_bits(5)?;
434
435 Some(PixelFormat::Yuv420p)
439}
440
441fn find_av1_obu(data: &[u8], target_type: u8) -> Option<&[u8]> {
448 find_av1_obu_with_offset(data, target_type).map(|(bytes, _)| bytes)
449}
450
451pub fn find_av1_obu_with_offset_pub(data: &[u8], target_type: u8) -> Option<(&[u8], usize)> {
454 find_av1_obu_with_offset(data, target_type)
455}
456
457fn find_av1_obu_with_offset(data: &[u8], target_type: u8) -> Option<(&[u8], usize)> {
462 let mut i = 0;
463 while i < data.len() {
464 let header = data[i];
465 let obu_type = (header >> 3) & 0x0F;
466 let extension_flag = (header >> 2) & 0x01;
467 let has_size_field = (header >> 1) & 0x01;
468 i += 1;
469 if extension_flag == 1 {
470 i += 1;
471 }
472 if has_size_field == 0 {
473 return None;
474 }
475 let (size, leb_bytes) = read_leb128(&data[i..])?;
476 i += leb_bytes;
477 if obu_type == target_type {
478 let end = (i + size as usize).min(data.len());
479 return Some((&data[i..end], i));
480 }
481 i += size as usize;
482 }
483 None
484}
485
486fn read_leb128(data: &[u8]) -> Option<(u64, usize)> {
487 let mut value = 0u64;
488 for i in 0..8 {
489 if i >= data.len() {
490 return None;
491 }
492 let byte = data[i];
493 value |= ((byte & 0x7F) as u64) << (i * 7);
494 if byte & 0x80 == 0 {
495 return Some((value, i + 1));
496 }
497 }
498 None
499}
500
501#[derive(Debug, Clone, PartialEq, Eq, Default)]
528pub struct H264SpsInfo {
529 pub profile_idc: u8,
530 pub constraint_set_flags: u8,
534 pub level_idc: u8,
535 pub chroma_format_idc: u8,
536 pub separate_colour_plane_flag: bool,
537 pub bit_depth_luma: u8,
538 pub bit_depth_chroma: u8,
539 pub frame_mbs_only: bool,
540 pub width: Option<u32>,
543 pub height: Option<u32>,
544 pub log2_max_frame_num_minus4: Option<u8>,
549 pub pic_order_cnt_type: Option<u8>,
552 pub log2_max_pic_order_cnt_lsb_minus4: Option<u8>,
555 pub delta_pic_order_always_zero_flag: Option<bool>,
558 pub qpprime_y_zero_transform_bypass_flag: Option<bool>,
560 pub seq_scaling_matrix_present_flag: Option<bool>,
561 pub max_num_ref_frames: Option<u8>,
562 pub gaps_in_frame_num_value_allowed_flag: Option<bool>,
563 pub mb_adaptive_frame_field_flag: Option<bool>,
565 pub direct_8x8_inference_flag: Option<bool>,
566 pub frame_cropping_flag: Option<bool>,
567 pub frame_crop_left_offset: Option<u32>,
568 pub frame_crop_right_offset: Option<u32>,
569 pub frame_crop_top_offset: Option<u32>,
570 pub frame_crop_bottom_offset: Option<u32>,
571 pub offset_for_non_ref_pic: Option<i32>,
573 pub offset_for_top_to_bottom_field: Option<i32>,
574 pub num_ref_frames_in_pic_order_cnt_cycle: Option<u8>,
575 pub offset_for_ref_frame: Vec<i32>,
580}
581
582#[derive(Debug, Clone, PartialEq, Eq, Default)]
588pub struct HevcSpsInfo {
589 pub sps_video_parameter_set_id: u8,
590 pub sps_seq_parameter_set_id: u8,
591 pub sps_max_sub_layers_minus1: u8,
592 pub sps_temporal_id_nesting_flag: bool,
593 pub chroma_format_idc: u8,
594 pub separate_colour_plane_flag: bool,
595 pub bit_depth_luma: u8,
596 pub bit_depth_chroma: u8,
597 pub width: Option<u32>,
598 pub height: Option<u32>,
599 pub conf_win_left_offset: u32,
601 pub conf_win_right_offset: u32,
602 pub conf_win_top_offset: u32,
603 pub conf_win_bottom_offset: u32,
604 pub log2_max_pic_order_cnt_lsb_minus4: u8,
605 pub log2_min_luma_coding_block_size_minus3: u8,
606 pub log2_diff_max_min_luma_coding_block_size: u8,
607 pub log2_min_luma_transform_block_size_minus2: u8,
608 pub log2_diff_max_min_luma_transform_block_size: u8,
609 pub max_transform_hierarchy_depth_inter: u8,
610 pub max_transform_hierarchy_depth_intra: u8,
611 pub scaling_list_enabled_flag: bool,
612 pub sps_sub_layer_ordering_info_present_flag: bool,
613 pub amp_enabled_flag: bool,
614 pub sample_adaptive_offset_enabled_flag: bool,
615 pub pcm_enabled_flag: bool,
616 pub pcm_loop_filter_disabled_flag: bool,
618 pub num_short_term_ref_pic_sets: u8,
619 pub long_term_ref_pics_present_flag: bool,
620 pub sps_temporal_mvp_enabled_flag: bool,
621 pub strong_intra_smoothing_enabled_flag: bool,
622 pub profile_idc: u8,
623 pub level_idc: u8,
624 pub tier_flag: bool,
625 pub max_dec_pic_buffering_minus1: [u8; 7],
629 pub max_num_reorder_pics: [u8; 7],
630 pub max_latency_increase_plus1: [u32; 7],
631 pub profile_compatibility_flags: u32,
634 pub general_profile_space: u8,
637 pub general_constraint_flags: u64,
641}
642
643#[derive(Debug, Clone, Copy, PartialEq, Eq)]
645pub struct H265VpsInfo {
646 pub vps_video_parameter_set_id: u8,
647 pub vps_max_sub_layers_minus1: u8,
648 pub vps_temporal_id_nesting_flag: bool,
649 pub profile_idc: u8,
650 pub level_idc: u8,
651 pub tier_flag: bool,
652}
653
654#[derive(Debug, Clone, Copy, PartialEq, Eq)]
656pub struct H265PpsInfo {
657 pub pps_pic_parameter_set_id: u8,
658 pub pps_seq_parameter_set_id: u8,
659 pub dependent_slice_segments_enabled_flag: bool,
660 pub output_flag_present_flag: bool,
661 pub num_extra_slice_header_bits: u8,
662 pub sign_data_hiding_enabled_flag: bool,
663 pub cabac_init_present_flag: bool,
664 pub num_ref_idx_l0_default_active_minus1: u8,
665 pub num_ref_idx_l1_default_active_minus1: u8,
666 pub init_qp_minus26: i8,
667 pub constrained_intra_pred_flag: bool,
668 pub transform_skip_enabled_flag: bool,
669 pub cu_qp_delta_enabled_flag: bool,
670 pub diff_cu_qp_delta_depth: u8,
671 pub pps_cb_qp_offset: i8,
672 pub pps_cr_qp_offset: i8,
673 pub pps_slice_chroma_qp_offsets_present_flag: bool,
674 pub weighted_pred_flag: bool,
675 pub weighted_bipred_flag: bool,
676 pub transquant_bypass_enabled_flag: bool,
677 pub tiles_enabled_flag: bool,
678 pub entropy_coding_sync_enabled_flag: bool,
679 pub num_tile_columns_minus1: u8,
682 pub num_tile_rows_minus1: u8,
683 pub uniform_spacing_flag: bool,
684 pub loop_filter_across_tiles_enabled_flag: bool,
685 pub pps_loop_filter_across_slices_enabled_flag: bool,
687 pub deblocking_filter_control_present_flag: bool,
688 pub deblocking_filter_override_enabled_flag: bool,
689 pub pps_deblocking_filter_disabled_flag: bool,
690 pub pps_beta_offset_div2: i8,
691 pub pps_tc_offset_div2: i8,
692 pub pps_scaling_list_data_present_flag: bool,
693 pub lists_modification_present_flag: bool,
694 pub log2_parallel_merge_level_minus2: u8,
695 pub slice_segment_header_extension_present_flag: bool,
696 pub pps_extension_present_flag: bool,
697}
698
699#[derive(Debug, Clone, Copy, PartialEq, Eq)]
701pub struct H265SliceHeader {
702 pub first_slice_segment_in_pic_flag: bool,
703 pub nal_unit_type: u8,
704 pub slice_pic_parameter_set_id: u8,
705 pub slice_type: H265SliceType,
706 pub pic_order_cnt_lsb: u32,
707 pub short_term_ref_pic_set_sps_flag: bool,
708 pub short_term_ref_pic_set_idx: Option<u8>,
709 pub is_irap: bool,
711 pub is_idr: bool,
713}
714
715#[derive(Debug, Clone, Copy, PartialEq, Eq)]
716pub enum H265SliceType {
717 B,
718 P,
719 I,
720}
721
722impl H265SliceType {
723 fn from_ue(v: u32) -> Option<Self> {
724 match v {
725 0 => Some(Self::B),
726 1 => Some(Self::P),
727 2 => Some(Self::I),
728 _ => None,
729 }
730 }
731}
732
733#[derive(Debug, Clone, Copy, PartialEq, Eq)]
737pub struct Av1SequenceHeader {
738 pub seq_profile: u8,
739 pub still_picture: bool,
740 pub reduced_still_picture_header: bool,
741 pub max_frame_width_minus1: u32,
742 pub max_frame_height_minus1: u32,
743 pub seq_level_idx_0: u8,
744 pub seq_tier_0: u8,
750 pub bit_depth: u8,
751 pub monochrome: bool,
752 pub color_primaries: u8,
753 pub transfer_characteristics: u8,
754 pub matrix_coefficients: u8,
755 pub color_range: bool,
756 pub chroma_subsampling_x: bool,
757 pub chroma_subsampling_y: bool,
758 pub film_grain_params_present: bool,
759 pub enable_filter_intra: bool,
760 pub enable_intra_edge_filter: bool,
761 pub enable_interintra_compound: bool,
762 pub enable_masked_compound: bool,
763 pub enable_warped_motion: bool,
764 pub enable_dual_filter: bool,
765 pub enable_order_hint: bool,
766 pub enable_jnt_comp: bool,
767 pub enable_ref_frame_mvs: bool,
768 pub enable_superres: bool,
769 pub enable_cdef: bool,
770 pub enable_restoration: bool,
771 pub order_hint_bits: u8,
772 pub seq_force_screen_content_tools: u8,
777 pub seq_force_integer_mv: u8,
780 pub frame_width_bits_minus_1: u8,
785 pub frame_height_bits_minus_1: u8,
786 pub use_128x128_superblock: bool,
787 pub separate_uv_delta_q: bool,
792}
793
794#[derive(Debug, Clone)]
799pub struct Av1FrameHeader {
800 pub show_frame: bool,
801 pub showable_frame: bool,
802 pub frame_type: Av1FrameType,
803 pub error_resilient_mode: bool,
804 pub disable_cdf_update: bool,
805 pub allow_screen_content_tools: bool,
806 pub force_integer_mv: bool,
807 pub order_hint: u32,
808 pub primary_ref_frame: u8,
809 pub refresh_frame_flags: u8,
810 pub frame_width: u32,
811 pub frame_height: u32,
812 pub render_width: u32,
813 pub render_height: u32,
814 pub use_ref_frame_mvs: bool,
815 pub allow_high_precision_mv: bool,
816 pub is_filter_switchable: bool,
817 pub disable_frame_end_update_cdf: bool,
818 pub allow_warped_motion: bool,
819 pub reduced_tx_set: bool,
820 pub allow_intrabc: bool,
822 pub frame_size_override_flag: bool,
823 pub use_superres: bool,
824 pub is_motion_mode_switchable: bool,
825 pub reference_select: bool,
826 pub skip_mode_present: bool,
827 pub tile_cols: u8,
830 pub tile_rows: u8,
831 pub uniform_tile_spacing_flag: bool,
832 pub tile_cols_log2: u8,
833 pub tile_rows_log2: u8,
834 pub mi_col_starts: Vec<u16>, pub mi_row_starts: Vec<u16>, pub width_in_sbs_minus_1: Vec<u16>, pub height_in_sbs_minus_1: Vec<u16>, pub context_update_tile_id: u16,
839 pub tile_size_bytes_minus_1: u8,
840 pub base_q_idx: u8,
842 pub delta_q_y_dc: i8,
843 pub delta_q_u_dc: i8,
844 pub delta_q_u_ac: i8,
845 pub delta_q_v_dc: i8,
846 pub delta_q_v_ac: i8,
847 pub using_qmatrix: bool,
848 pub qm_y: u8,
849 pub qm_u: u8,
850 pub qm_v: u8,
851 pub delta_q_present: bool,
853 pub delta_q_res: u8,
854 pub delta_lf_present: bool,
855 pub delta_lf_res: u8,
856 pub delta_lf_multi: bool,
857 pub segmentation_enabled: bool,
861 pub segmentation_update_map: bool,
862 pub segmentation_temporal_update: bool,
863 pub segmentation_update_data: bool,
864 pub feature_enabled: [[bool; 8]; 8],
865 pub feature_data: [[i16; 8]; 8],
866 pub loop_filter_level: [u8; 4],
868 pub loop_filter_sharpness: u8,
869 pub loop_filter_delta_enabled: bool,
870 pub loop_filter_delta_update: bool,
871 pub update_ref_delta_mask: u8, pub loop_filter_ref_deltas: [i8; 8],
873 pub update_mode_delta_mask: u8, pub loop_filter_mode_deltas: [i8; 2],
875 pub cdef_damping_minus_3: u8,
877 pub cdef_bits: u8,
878 pub cdef_y_pri_strength: [u8; 8],
879 pub cdef_y_sec_strength: [u8; 8],
880 pub cdef_uv_pri_strength: [u8; 8],
881 pub cdef_uv_sec_strength: [u8; 8],
882 pub lr_type: [u8; 3], pub lr_unit_shift: u8,
885 pub lr_uv_shift: u8,
886 pub tx_mode: u8,
888 pub interpolation_filter: u8,
889 pub tile_group_offset_in_obu: u32,
896 pub coded_lossless: bool,
898}
899
900impl Default for Av1FrameHeader {
901 fn default() -> Self {
902 Self {
903 show_frame: false,
904 showable_frame: false,
905 frame_type: Av1FrameType::Key,
906 error_resilient_mode: false,
907 disable_cdf_update: false,
908 allow_screen_content_tools: false,
909 force_integer_mv: false,
910 order_hint: 0,
911 primary_ref_frame: 7,
912 refresh_frame_flags: 0,
913 frame_width: 0,
914 frame_height: 0,
915 render_width: 0,
916 render_height: 0,
917 use_ref_frame_mvs: false,
918 allow_high_precision_mv: false,
919 is_filter_switchable: false,
920 disable_frame_end_update_cdf: false,
921 allow_warped_motion: false,
922 reduced_tx_set: false,
923 allow_intrabc: false,
924 frame_size_override_flag: false,
925 use_superres: false,
926 is_motion_mode_switchable: false,
927 reference_select: false,
928 skip_mode_present: false,
929 tile_cols: 1,
930 tile_rows: 1,
931 uniform_tile_spacing_flag: true,
932 tile_cols_log2: 0,
933 tile_rows_log2: 0,
934 mi_col_starts: Vec::new(),
935 mi_row_starts: Vec::new(),
936 width_in_sbs_minus_1: Vec::new(),
937 height_in_sbs_minus_1: Vec::new(),
938 context_update_tile_id: 0,
939 tile_size_bytes_minus_1: 3,
940 base_q_idx: 0,
941 delta_q_y_dc: 0,
942 delta_q_u_dc: 0,
943 delta_q_u_ac: 0,
944 delta_q_v_dc: 0,
945 delta_q_v_ac: 0,
946 using_qmatrix: false,
947 qm_y: 0,
948 qm_u: 0,
949 qm_v: 0,
950 delta_q_present: false,
951 delta_q_res: 0,
952 delta_lf_present: false,
953 delta_lf_res: 0,
954 delta_lf_multi: false,
955 segmentation_enabled: false,
956 segmentation_update_map: false,
957 segmentation_temporal_update: false,
958 segmentation_update_data: false,
959 feature_enabled: [[false; 8]; 8],
960 feature_data: [[0; 8]; 8],
961 loop_filter_level: [0; 4],
962 loop_filter_sharpness: 0,
963 loop_filter_delta_enabled: false,
964 loop_filter_delta_update: false,
965 update_ref_delta_mask: 0,
966 loop_filter_ref_deltas: [0; 8],
967 update_mode_delta_mask: 0,
968 loop_filter_mode_deltas: [0; 2],
969 cdef_damping_minus_3: 0,
970 cdef_bits: 0,
971 cdef_y_pri_strength: [0; 8],
972 cdef_y_sec_strength: [0; 8],
973 cdef_uv_pri_strength: [0; 8],
974 cdef_uv_sec_strength: [0; 8],
975 lr_type: [0; 3],
976 lr_unit_shift: 0,
977 lr_uv_shift: 0,
978 tx_mode: 0,
979 interpolation_filter: 0,
980 tile_group_offset_in_obu: 0,
981 coded_lossless: false,
982 }
983 }
984}
985
986#[derive(Debug, Clone, Copy, PartialEq, Eq)]
987pub enum Av1FrameType {
988 Key,
989 Inter,
990 IntraOnly,
991 Switch,
992}
993
994pub fn parse_av1_sequence_header(sample: &[u8]) -> Option<Av1SequenceHeader> {
999 let obu = find_av1_obu(sample, 1)?;
1000 let mut br = BitReader::new(obu);
1001 let seq_profile = br.read_bits(3)? as u8;
1002 let still_picture = br.read_bits(1)? == 1;
1003 let reduced_still_picture_header = br.read_bits(1)? == 1;
1004
1005 let mut seq_level_idx_0 = 0u8;
1006 let mut seq_tier_0 = 0u8;
1007 let (_operating_points_cnt_minus_1, _timing_info_present_flag);
1008 let mut order_hint_bits = 0u8;
1009 let mut enable_order_hint = false;
1010
1011 if reduced_still_picture_header {
1012 seq_level_idx_0 = br.read_bits(5)? as u8;
1013 _operating_points_cnt_minus_1 = 0;
1014 _timing_info_present_flag = false;
1015 } else {
1016 let timing_info_present_flag = br.read_bits(1)? == 1;
1017 _timing_info_present_flag = timing_info_present_flag;
1018 let mut decoder_model_info_present_flag = false;
1019 let mut buffer_delay_length_minus_1 = 0u32;
1020 if timing_info_present_flag {
1021 let _num_units_in_display_tick = br.read_bits(32)?;
1022 let _time_scale = br.read_bits(32)?;
1023 let equal_picture_interval = br.read_bits(1)? == 1;
1024 if equal_picture_interval {
1025 let _num_ticks_per_picture_minus_1 = read_av1_uvlc(&mut br)?;
1026 }
1027 decoder_model_info_present_flag = br.read_bits(1)? == 1;
1028 if decoder_model_info_present_flag {
1029 buffer_delay_length_minus_1 = br.read_bits(5)?;
1030 let _num_units_in_decoding_tick = br.read_bits(32)?;
1031 let _buffer_removal_time_length_minus_1 = br.read_bits(5)?;
1032 let _frame_presentation_time_length_minus_1 = br.read_bits(5)?;
1033 }
1034 }
1035 let initial_display_delay_present_flag = br.read_bits(1)? == 1;
1040 let operating_points_cnt_minus_1 = br.read_bits(5)? as u8;
1041 _operating_points_cnt_minus_1 = operating_points_cnt_minus_1;
1042 for i in 0..=operating_points_cnt_minus_1 {
1043 let _operating_point_idc = br.read_bits(12)?;
1044 let seq_level_idx_i = br.read_bits(5)? as u8;
1045 let seq_tier_i = if seq_level_idx_i > 7 {
1048 br.read_bits(1)? as u8
1049 } else {
1050 0
1051 };
1052 if i == 0 {
1053 seq_level_idx_0 = seq_level_idx_i;
1054 seq_tier_0 = seq_tier_i;
1055 }
1056 if decoder_model_info_present_flag {
1059 let decoder_model_present_for_this_op = br.read_bits(1)? == 1;
1060 if decoder_model_present_for_this_op {
1061 let n = (buffer_delay_length_minus_1 + 1) as usize;
1062 let _buffer_delay = br.read_bits(n)?;
1063 let _encoder_buffer_delay = br.read_bits(n)?;
1064 let _low_delay_mode_flag = br.read_bits(1)?;
1065 }
1066 }
1067 if initial_display_delay_present_flag {
1068 let idd_present_for_this_op = br.read_bits(1)? == 1;
1069 if idd_present_for_this_op {
1070 let _initial_display_delay_minus_1 = br.read_bits(4)?;
1071 }
1072 }
1073 }
1074 }
1075 let frame_width_bits_minus_1 = br.read_bits(4)? as usize;
1076 let frame_height_bits_minus_1 = br.read_bits(4)? as usize;
1077 let max_frame_width_minus1 = br.read_bits(frame_width_bits_minus_1 + 1)?;
1078 let max_frame_height_minus1 = br.read_bits(frame_height_bits_minus_1 + 1)?;
1079
1080 let frame_id_numbers_present_flag = if reduced_still_picture_header {
1081 false
1082 } else {
1083 br.read_bits(1)? == 1
1084 };
1085 if frame_id_numbers_present_flag {
1086 let _delta_frame_id_length_minus_2 = br.read_bits(4)?;
1087 let _additional_frame_id_length_minus_1 = br.read_bits(3)?;
1088 }
1089 let use_128x128_superblock = br.read_bits(1)? == 1;
1090 let enable_filter_intra = br.read_bits(1)? == 1;
1091 let enable_intra_edge_filter = br.read_bits(1)? == 1;
1092 let mut enable_interintra_compound = false;
1093 let mut enable_masked_compound = false;
1094 let mut enable_warped_motion = false;
1095 let mut enable_dual_filter = false;
1096 let mut enable_jnt_comp = false;
1097 let mut enable_ref_frame_mvs = false;
1098 let mut seq_force_screen_content_tools: u8 = 2; let mut seq_force_integer_mv: u8 = 2;
1100 if !reduced_still_picture_header {
1101 enable_interintra_compound = br.read_bits(1)? == 1;
1102 enable_masked_compound = br.read_bits(1)? == 1;
1103 enable_warped_motion = br.read_bits(1)? == 1;
1104 enable_dual_filter = br.read_bits(1)? == 1;
1105 enable_order_hint = br.read_bits(1)? == 1;
1106 if enable_order_hint {
1107 enable_jnt_comp = br.read_bits(1)? == 1;
1108 enable_ref_frame_mvs = br.read_bits(1)? == 1;
1109 }
1110 let seq_choose_screen_content_tools = br.read_bits(1)? == 1;
1111 seq_force_screen_content_tools = if seq_choose_screen_content_tools {
1112 2u8
1113 } else {
1114 br.read_bits(1)? as u8
1115 };
1116 if seq_force_screen_content_tools > 0 {
1117 let seq_choose_integer_mv = br.read_bits(1)? == 1;
1118 seq_force_integer_mv = if seq_choose_integer_mv {
1119 2u8
1120 } else {
1121 br.read_bits(1)? as u8
1122 };
1123 }
1124 if enable_order_hint {
1125 order_hint_bits = br.read_bits(3)? as u8 + 1;
1126 }
1127 }
1128 let enable_superres = br.read_bits(1)? == 1;
1129 let enable_cdef = br.read_bits(1)? == 1;
1130 let enable_restoration = br.read_bits(1)? == 1;
1131
1132 let high_bitdepth = br.read_bits(1)? == 1;
1134 let bit_depth = if seq_profile == 2 && high_bitdepth {
1135 if br.read_bits(1)? == 1 { 12 } else { 10 }
1136 } else if high_bitdepth {
1137 10
1138 } else {
1139 8
1140 };
1141 let monochrome = if seq_profile == 1 {
1142 false
1143 } else {
1144 br.read_bits(1)? == 1
1145 };
1146 let color_description_present_flag = br.read_bits(1)? == 1;
1147 let (color_primaries, transfer_characteristics, matrix_coefficients) =
1148 if color_description_present_flag {
1149 (
1150 br.read_bits(8)? as u8,
1151 br.read_bits(8)? as u8,
1152 br.read_bits(8)? as u8,
1153 )
1154 } else {
1155 (2u8, 2u8, 2u8) };
1157 let color_range;
1158 let (subx, suby);
1159 let mut separate_uv_delta_q = false;
1160 if monochrome {
1161 color_range = br.read_bits(1)? == 1;
1162 subx = true;
1163 suby = true;
1164 } else if color_primaries == 1 && transfer_characteristics == 13 && matrix_coefficients == 0 {
1165 color_range = true;
1166 subx = false;
1167 suby = false;
1168 } else {
1169 color_range = br.read_bits(1)? == 1;
1170 match seq_profile {
1171 0 => {
1172 subx = true;
1173 suby = true;
1174 }
1175 1 => {
1176 subx = false;
1177 suby = false;
1178 }
1179 2 => {
1180 if bit_depth == 12 {
1181 subx = br.read_bits(1)? == 1;
1182 suby = if subx { br.read_bits(1)? == 1 } else { false };
1183 } else {
1184 subx = true;
1185 suby = false;
1186 }
1187 }
1188 _ => {
1189 subx = true;
1190 suby = true;
1191 }
1192 }
1193 if subx && suby {
1194 let _chroma_sample_position = br.read_bits(2)?;
1195 }
1196 separate_uv_delta_q = br.read_bits(1)? == 1;
1197 }
1198 let film_grain_params_present = br.read_bits(1)? == 1;
1199
1200 Some(Av1SequenceHeader {
1201 seq_profile,
1202 still_picture,
1203 reduced_still_picture_header,
1204 max_frame_width_minus1,
1205 max_frame_height_minus1,
1206 seq_level_idx_0,
1207 seq_tier_0,
1208 bit_depth,
1209 monochrome,
1210 color_primaries,
1211 transfer_characteristics,
1212 matrix_coefficients,
1213 color_range,
1214 chroma_subsampling_x: subx,
1215 chroma_subsampling_y: suby,
1216 film_grain_params_present,
1217 enable_filter_intra,
1218 enable_intra_edge_filter,
1219 enable_interintra_compound,
1220 enable_masked_compound,
1221 enable_warped_motion,
1222 enable_dual_filter,
1223 enable_order_hint,
1224 enable_jnt_comp,
1225 enable_ref_frame_mvs,
1226 enable_superres,
1227 enable_cdef,
1228 enable_restoration,
1229 order_hint_bits,
1230 seq_force_screen_content_tools,
1231 seq_force_integer_mv,
1232 frame_width_bits_minus_1: frame_width_bits_minus_1 as u8,
1233 frame_height_bits_minus_1: frame_height_bits_minus_1 as u8,
1234 use_128x128_superblock,
1235 separate_uv_delta_q,
1236 })
1237}
1238
1239pub fn parse_av1_frame_header(sample: &[u8], seq: &Av1SequenceHeader) -> Option<Av1FrameHeader> {
1253 let obu_bytes = find_av1_obu(sample, 3).or_else(|| find_av1_obu(sample, 6))?;
1254 let mut br = BitReader::new(obu_bytes);
1255 let mut h = Av1FrameHeader::default();
1256
1257 if seq.reduced_still_picture_header {
1259 h.frame_type = Av1FrameType::Key;
1260 h.show_frame = true;
1261 h.showable_frame = false;
1262 h.error_resilient_mode = true;
1263 } else {
1264 let show_existing_frame = br.read_bits(1)? == 1;
1265 if show_existing_frame {
1266 let _frame_to_show_map_idx = br.read_bits(3)?;
1272 h.show_frame = true;
1273 h.showable_frame = true;
1274 h.frame_type = Av1FrameType::Key;
1275 h.frame_width = seq.max_frame_width_minus1 + 1;
1276 h.frame_height = seq.max_frame_height_minus1 + 1;
1277 h.render_width = h.frame_width;
1278 h.render_height = h.frame_height;
1279 return Some(h);
1280 }
1281 let ft_code = br.read_bits(2)?;
1282 h.frame_type = match ft_code {
1283 0 => Av1FrameType::Key,
1284 1 => Av1FrameType::Inter,
1285 2 => Av1FrameType::IntraOnly,
1286 3 => Av1FrameType::Switch,
1287 _ => return None,
1288 };
1289 h.show_frame = br.read_bits(1)? == 1;
1290 h.showable_frame = if h.show_frame {
1291 !matches!(h.frame_type, Av1FrameType::Key)
1292 } else {
1293 br.read_bits(1)? == 1
1294 };
1295 let is_key = matches!(h.frame_type, Av1FrameType::Key);
1296 let is_switch = matches!(h.frame_type, Av1FrameType::Switch);
1297 h.error_resilient_mode = if is_switch || (is_key && h.show_frame) {
1298 true
1299 } else {
1300 br.read_bits(1)? == 1
1301 };
1302 }
1303
1304 let frame_is_intra = matches!(h.frame_type, Av1FrameType::Key | Av1FrameType::IntraOnly);
1305
1306 h.disable_cdf_update = br.read_bits(1)? == 1;
1307 h.allow_screen_content_tools = if seq.seq_force_screen_content_tools == 2 {
1311 br.read_bits(1)? == 1
1312 } else {
1313 seq.seq_force_screen_content_tools == 1
1314 };
1315 if h.allow_screen_content_tools {
1316 h.force_integer_mv = if seq.seq_force_integer_mv == 2 {
1317 br.read_bits(1)? == 1
1318 } else {
1319 seq.seq_force_integer_mv == 1
1320 };
1321 } else {
1322 h.force_integer_mv = false;
1323 }
1324 if frame_is_intra {
1325 h.force_integer_mv = true;
1326 }
1327
1328 let is_switch = matches!(h.frame_type, Av1FrameType::Switch);
1330 h.frame_size_override_flag = if is_switch {
1331 true
1332 } else if seq.reduced_still_picture_header {
1333 false
1334 } else {
1335 br.read_bits(1)? == 1
1336 };
1337
1338 if seq.enable_order_hint && seq.order_hint_bits > 0 {
1340 h.order_hint = br.read_bits(seq.order_hint_bits as usize)?;
1341 }
1342
1343 h.primary_ref_frame = if frame_is_intra || h.error_resilient_mode {
1345 7 } else {
1347 br.read_bits(3)? as u8
1348 };
1349
1350 let all_frames = 0xFFu8;
1352 h.refresh_frame_flags = if matches!(h.frame_type, Av1FrameType::Key) && h.show_frame {
1353 all_frames
1354 } else if is_switch {
1355 all_frames
1356 } else {
1357 br.read_bits(8)? as u8
1358 };
1359
1360 let (frame_width, frame_height) = if frame_is_intra {
1362 let (w, h2) = parse_av1_frame_size(&mut br, seq, h.frame_size_override_flag)?;
1363 h.use_superres = if seq.enable_superres {
1366 br.read_bits(1)? == 1
1367 } else {
1368 false
1369 };
1370 if h.use_superres {
1371 let _superres_denom_minus9 = br.read_bits(3)?;
1372 }
1373 parse_av1_render_size(&mut br, w, h2, &mut h.render_width, &mut h.render_height)?;
1374 if h.allow_screen_content_tools
1375 {
1377 h.allow_intrabc = br.read_bits(1)? == 1;
1378 }
1379 (w, h2)
1380 } else {
1381 let frame_refs_short_signaling = if seq.enable_order_hint {
1387 br.read_bits(1)? == 1
1388 } else {
1389 false
1390 };
1391 if frame_refs_short_signaling {
1392 let _last_frame_idx = br.read_bits(3)?;
1393 let _gold_frame_idx = br.read_bits(3)?;
1394 }
1395 for _ in 0..7u8
1396 {
1398 if !frame_refs_short_signaling {
1399 let _ref_frame_idx = br.read_bits(3)?;
1400 }
1401 }
1404 let (w, h2) = if h.frame_size_override_flag && !h.error_resilient_mode {
1405 parse_av1_frame_size_with_refs(&mut br, seq)?
1406 } else {
1407 let (w, h2) = parse_av1_frame_size(&mut br, seq, h.frame_size_override_flag)?;
1408 h.use_superres = if seq.enable_superres {
1410 br.read_bits(1)? == 1
1411 } else {
1412 false
1413 };
1414 if h.use_superres {
1415 let _superres_denom_minus9 = br.read_bits(3)?;
1416 }
1417 parse_av1_render_size(&mut br, w, h2, &mut h.render_width, &mut h.render_height)?;
1418 (w, h2)
1419 };
1420 h.allow_high_precision_mv = if h.force_integer_mv {
1421 false
1422 } else {
1423 br.read_bits(1)? == 1
1424 };
1425 h.is_filter_switchable = br.read_bits(1)? == 1;
1427 h.interpolation_filter = if h.is_filter_switchable {
1428 4 } else {
1430 br.read_bits(2)? as u8
1431 };
1432 h.is_motion_mode_switchable = br.read_bits(1)? == 1;
1433 h.use_ref_frame_mvs = if h.error_resilient_mode || !seq.enable_ref_frame_mvs {
1434 false
1435 } else {
1436 br.read_bits(1)? == 1
1437 };
1438 (w, h2)
1439 };
1440 h.frame_width = frame_width;
1441 h.frame_height = frame_height;
1442 if h.render_width == 0 {
1443 h.render_width = frame_width;
1444 }
1445 if h.render_height == 0 {
1446 h.render_height = frame_height;
1447 }
1448
1449 h.disable_frame_end_update_cdf = if seq.reduced_still_picture_header {
1450 true
1451 } else {
1452 br.read_bits(1)? == 1
1453 };
1454
1455 let sb_size_log2: u32 = 4; let mi_cols_raw = 2 * ((frame_width.saturating_sub(1) + 8) >> 3);
1462 let mi_rows_raw = 2 * ((frame_height.saturating_sub(1) + 8) >> 3);
1463 let sb_cols = (mi_cols_raw + (1 << sb_size_log2) - 1) >> sb_size_log2;
1465 let sb_rows = (mi_rows_raw + (1 << sb_size_log2) - 1) >> sb_size_log2;
1466 parse_av1_tile_info(
1467 &mut br,
1468 &mut h,
1469 sb_cols,
1470 sb_rows,
1471 sb_size_log2,
1472 mi_cols_raw,
1473 mi_rows_raw,
1474 )?;
1475
1476 parse_av1_quantization_params(&mut br, &mut h, seq)?;
1478
1479 parse_av1_segmentation_params(&mut br, &mut h)?;
1481
1482 h.delta_q_present = if h.base_q_idx > 0 {
1484 br.read_bits(1)? == 1
1485 } else {
1486 false
1487 };
1488 h.delta_q_res = if h.delta_q_present {
1489 br.read_bits(2)? as u8
1490 } else {
1491 0
1492 };
1493 h.delta_lf_present = if h.delta_q_present && !h.allow_intrabc {
1494 br.read_bits(1)? == 1
1495 } else {
1496 false
1497 };
1498 if h.delta_lf_present {
1499 h.delta_lf_res = br.read_bits(2)? as u8;
1500 h.delta_lf_multi = br.read_bits(1)? == 1;
1501 }
1502
1503 h.coded_lossless = h.base_q_idx == 0
1509 && h.delta_q_y_dc == 0
1510 && h.delta_q_u_dc == 0
1511 && h.delta_q_u_ac == 0
1512 && h.delta_q_v_dc == 0
1513 && h.delta_q_v_ac == 0;
1514
1515 parse_av1_loop_filter_params(&mut br, &mut h, frame_is_intra)?;
1517
1518 let num_planes_u32: u32 = if seq.monochrome { 1 } else { 3 };
1520 if !h.coded_lossless && !h.allow_intrabc && seq.enable_cdef {
1521 parse_av1_cdef_params(&mut br, &mut h, num_planes_u32)?;
1522 } else {
1523 h.cdef_bits = 0;
1525 h.cdef_damping_minus_3 = 0;
1526 h.cdef_y_pri_strength = [0; 8];
1527 h.cdef_y_sec_strength = [0; 8];
1528 h.cdef_uv_pri_strength = [0; 8];
1529 h.cdef_uv_sec_strength = [0; 8];
1530 }
1531
1532 if !h.coded_lossless && !h.allow_intrabc && seq.enable_restoration {
1534 parse_av1_lr_params(&mut br, &mut h, num_planes_u32, seq)?;
1535 }
1536
1537 h.tx_mode = if h.coded_lossless {
1539 0 } else if br.read_bits(1)? == 1 {
1541 2 } else {
1543 1 };
1545
1546 h.reference_select = if !frame_is_intra {
1548 br.read_bits(1)? == 1
1549 } else {
1550 false
1551 };
1552
1553 let skip_mode_allowed = false; h.skip_mode_present = if skip_mode_allowed {
1560 br.read_bits(1)? == 1
1561 } else {
1562 false
1563 };
1564
1565 h.allow_warped_motion =
1568 if !frame_is_intra && !h.error_resilient_mode && seq.enable_warped_motion {
1569 br.read_bits(1)? == 1
1570 } else {
1571 false
1572 };
1573
1574 h.reduced_tx_set = br.read_bits(1)? == 1;
1580
1581 if !frame_is_intra {
1586 skip_av1_global_motion_params(&mut br)?;
1587 }
1588
1589 if seq.film_grain_params_present && (h.show_frame || h.showable_frame) {
1591 skip_av1_film_grain_params(&mut br, seq)?;
1592 }
1593
1594 br.byte_align();
1599 h.tile_group_offset_in_obu = (br.bit_pos() / 8) as u32;
1600
1601 Some(h)
1602}
1603
1604fn parse_av1_frame_size(
1606 br: &mut BitReader,
1607 seq: &Av1SequenceHeader,
1608 frame_size_override_flag: bool,
1609) -> Option<(u32, u32)> {
1610 if frame_size_override_flag {
1611 let w_bits = av1_bits_for_max(seq.max_frame_width_minus1 + 1);
1612 let h_bits = av1_bits_for_max(seq.max_frame_height_minus1 + 1);
1613 let w = br.read_bits(w_bits)? + 1;
1614 let hgt = br.read_bits(h_bits)? + 1;
1615 Some((w, hgt))
1616 } else {
1617 Some((
1618 seq.max_frame_width_minus1 + 1,
1619 seq.max_frame_height_minus1 + 1,
1620 ))
1621 }
1622}
1623
1624fn parse_av1_render_size(
1626 br: &mut BitReader,
1627 frame_w: u32,
1628 frame_h: u32,
1629 out_w: &mut u32,
1630 out_h: &mut u32,
1631) -> Option<()> {
1632 let render_and_frame_size_different = br.read_bits(1)? == 1;
1633 if render_and_frame_size_different {
1634 *out_w = br.read_bits(16)? + 1;
1635 *out_h = br.read_bits(16)? + 1;
1636 } else {
1637 *out_w = frame_w;
1638 *out_h = frame_h;
1639 }
1640 Some(())
1641}
1642
1643fn parse_av1_frame_size_with_refs(
1649 br: &mut BitReader,
1650 seq: &Av1SequenceHeader,
1651) -> Option<(u32, u32)> {
1652 let mut found_ref = false;
1653 for _ in 0..7u8 {
1654 if br.read_bits(1)? == 1 {
1655 found_ref = true;
1656 }
1657 }
1658 if !found_ref {
1659 let (w, hgt) = parse_av1_frame_size(br, seq, true)?;
1660 let mut rw = 0;
1661 let mut rh = 0;
1662 parse_av1_render_size(br, w, hgt, &mut rw, &mut rh)?;
1663 if seq.enable_superres && br.read_bits(1)? == 1 {
1665 let _denom = br.read_bits(3)?;
1666 }
1667 Some((w, hgt))
1668 } else {
1669 Some((
1672 seq.max_frame_width_minus1 + 1,
1673 seq.max_frame_height_minus1 + 1,
1674 ))
1675 }
1676}
1677
1678fn av1_bits_for_max(v: u32) -> usize {
1679 let mut bits = 0usize;
1682 let mut x = v.saturating_sub(1);
1683 while x > 0 {
1684 bits += 1;
1685 x >>= 1;
1686 }
1687 bits.max(1)
1688}
1689
1690fn parse_av1_tile_info(
1692 br: &mut BitReader,
1693 h: &mut Av1FrameHeader,
1694 sb_cols: u32,
1695 sb_rows: u32,
1696 sb_size_log2: u32,
1697 mi_cols: u32,
1698 mi_rows: u32,
1699) -> Option<()> {
1700 let max_tile_width_sb = 4096 >> (sb_size_log2 + 2); let max_tile_area_sb = (4096 * 2304) >> (2 * sb_size_log2 + 4); let min_log2_tile_cols = av1_tile_log2(max_tile_width_sb, sb_cols);
1705 let max_log2_tile_cols = av1_tile_log2(1, sb_cols.min(64));
1706 let max_log2_tile_rows = av1_tile_log2(1, sb_rows.min(64));
1707 let min_log2_tiles = min_log2_tile_cols.max(av1_tile_log2(max_tile_area_sb, sb_rows * sb_cols));
1708
1709 h.uniform_tile_spacing_flag = br.read_bits(1)? == 1;
1710 let tile_cols_log2: u32;
1711 let tile_rows_log2: u32;
1712 h.mi_col_starts.clear();
1713 h.mi_row_starts.clear();
1714 h.width_in_sbs_minus_1.clear();
1715 h.height_in_sbs_minus_1.clear();
1716
1717 if h.uniform_tile_spacing_flag {
1718 let mut tcl = min_log2_tile_cols;
1719 while tcl < max_log2_tile_cols {
1720 if br.read_bits(1)? == 0 {
1721 break;
1722 }
1723 tcl += 1;
1724 }
1725 tile_cols_log2 = tcl;
1726 let tile_width_sb = (sb_cols + (1 << tile_cols_log2) - 1) >> tile_cols_log2;
1727 let mut start_sb = 0u32;
1728 let mut mi_starts: Vec<u16> = vec![0];
1729 let mut widths: Vec<u16> = Vec::new();
1730 while start_sb < sb_cols {
1731 let size_sb = tile_width_sb.min(sb_cols - start_sb);
1732 widths.push((size_sb - 1) as u16);
1733 start_sb += size_sb;
1734 mi_starts.push(((start_sb << sb_size_log2).min(mi_cols)) as u16);
1735 }
1736 h.mi_col_starts = mi_starts;
1737 h.width_in_sbs_minus_1 = widths;
1738 h.tile_cols = h.width_in_sbs_minus_1.len() as u8;
1739
1740 let min_log2_tile_rows = min_log2_tiles.saturating_sub(tile_cols_log2);
1741 let mut trl = min_log2_tile_rows;
1742 while trl < max_log2_tile_rows {
1743 if br.read_bits(1)? == 0 {
1744 break;
1745 }
1746 trl += 1;
1747 }
1748 tile_rows_log2 = trl;
1749 let tile_height_sb = (sb_rows + (1 << tile_rows_log2) - 1) >> tile_rows_log2;
1750 let mut start_sb_r = 0u32;
1751 let mut mi_starts_r: Vec<u16> = vec![0];
1752 let mut heights: Vec<u16> = Vec::new();
1753 while start_sb_r < sb_rows {
1754 let size_sb = tile_height_sb.min(sb_rows - start_sb_r);
1755 heights.push((size_sb - 1) as u16);
1756 start_sb_r += size_sb;
1757 mi_starts_r.push(((start_sb_r << sb_size_log2).min(mi_rows)) as u16);
1758 }
1759 h.mi_row_starts = mi_starts_r;
1760 h.height_in_sbs_minus_1 = heights;
1761 h.tile_rows = h.height_in_sbs_minus_1.len() as u8;
1762 } else {
1763 let mut start_sb = 0u32;
1765 let mut mi_starts: Vec<u16> = vec![0];
1766 let mut widths: Vec<u16> = Vec::new();
1767 while start_sb < sb_cols {
1768 let max_width = (sb_cols - start_sb).min(max_tile_width_sb);
1769 let size_minus_1 = av1_read_ns(br, max_width)?;
1770 let size = size_minus_1 + 1;
1771 widths.push(size_minus_1 as u16);
1772 start_sb += size;
1773 mi_starts.push(((start_sb << sb_size_log2).min(mi_cols)) as u16);
1774 }
1775 h.mi_col_starts = mi_starts;
1776 h.width_in_sbs_minus_1 = widths;
1777 h.tile_cols = h.width_in_sbs_minus_1.len() as u8;
1778 tile_cols_log2 = av1_tile_log2(1, h.tile_cols as u32);
1779
1780 let tile_cols = h.tile_cols as u32;
1781 let max_tile_area_sb_r = if min_log2_tiles > 0 {
1782 (sb_rows * sb_cols) >> (min_log2_tiles + 1)
1783 } else {
1784 sb_rows * sb_cols
1785 };
1786 let max_tile_height_sb = (max_tile_area_sb_r / tile_cols).max(1);
1787
1788 let mut start_sb_r = 0u32;
1789 let mut mi_starts_r: Vec<u16> = vec![0];
1790 let mut heights: Vec<u16> = Vec::new();
1791 while start_sb_r < sb_rows {
1792 let max_height = (sb_rows - start_sb_r).min(max_tile_height_sb);
1793 let size_minus_1 = av1_read_ns(br, max_height)?;
1794 let size = size_minus_1 + 1;
1795 heights.push(size_minus_1 as u16);
1796 start_sb_r += size;
1797 mi_starts_r.push(((start_sb_r << sb_size_log2).min(mi_rows)) as u16);
1798 }
1799 h.mi_row_starts = mi_starts_r;
1800 h.height_in_sbs_minus_1 = heights;
1801 h.tile_rows = h.height_in_sbs_minus_1.len() as u8;
1802 tile_rows_log2 = av1_tile_log2(1, h.tile_rows as u32);
1803 }
1804 h.tile_cols_log2 = tile_cols_log2 as u8;
1805 h.tile_rows_log2 = tile_rows_log2 as u8;
1806
1807 if (tile_cols_log2 + tile_rows_log2) > 0 {
1808 let n = (tile_cols_log2 + tile_rows_log2) as usize;
1809 h.context_update_tile_id = br.read_bits(n)? as u16;
1810 h.tile_size_bytes_minus_1 = br.read_bits(2)? as u8;
1811 } else {
1812 h.context_update_tile_id = 0;
1813 h.tile_size_bytes_minus_1 = 0;
1814 }
1815 Some(())
1816}
1817
1818fn av1_tile_log2(blksize: u32, target: u32) -> u32 {
1820 let mut k = 0u32;
1821 while (blksize << k) < target {
1822 k += 1;
1823 }
1824 k
1825}
1826
1827fn av1_read_ns(br: &mut BitReader, n: u32) -> Option<u32> {
1829 if n == 0 {
1830 return Some(0);
1831 }
1832 let w = av1_ceil_log2(n);
1833 if w == 0 {
1834 return Some(0);
1835 }
1836 let m = (1u32 << w) - n;
1837 let v = br.read_bits((w - 1) as usize)?;
1838 if v < m {
1839 Some(v)
1840 } else {
1841 let extra = br.read_bits(1)?;
1842 Some((v << 1) - m + extra)
1843 }
1844}
1845
1846fn av1_ceil_log2(n: u32) -> u32 {
1847 if n <= 1 {
1848 return 1;
1849 }
1850 let mut k = 0;
1851 let mut x = n - 1;
1852 while x > 0 {
1853 k += 1;
1854 x >>= 1;
1855 }
1856 k
1857}
1858
1859fn parse_av1_quantization_params(
1861 br: &mut BitReader,
1862 h: &mut Av1FrameHeader,
1863 seq: &Av1SequenceHeader,
1864) -> Option<()> {
1865 h.base_q_idx = br.read_bits(8)? as u8;
1866 h.delta_q_y_dc = read_delta_q(br)?;
1867 let (diff_uv_delta, num_planes) = if seq.monochrome {
1868 (false, 1u32)
1869 } else {
1870 let diff = if seq.seq_profile == 2 {
1871 br.read_bits(1)? == 1
1872 } else {
1873 false
1874 };
1875 (diff, 3u32)
1876 };
1877 if num_planes > 1 {
1878 h.delta_q_u_dc = read_delta_q(br)?;
1879 h.delta_q_u_ac = read_delta_q(br)?;
1880 if diff_uv_delta {
1881 h.delta_q_v_dc = read_delta_q(br)?;
1882 h.delta_q_v_ac = read_delta_q(br)?;
1883 } else {
1884 h.delta_q_v_dc = h.delta_q_u_dc;
1885 h.delta_q_v_ac = h.delta_q_u_ac;
1886 }
1887 }
1888 h.using_qmatrix = br.read_bits(1)? == 1;
1889 if h.using_qmatrix {
1890 h.qm_y = br.read_bits(4)? as u8;
1891 h.qm_u = br.read_bits(4)? as u8;
1892 h.qm_v = if seq.monochrome {
1893 h.qm_u
1894 } else if br.read_bits(1)? == 0 {
1895 h.qm_u
1896 } else {
1897 br.read_bits(4)? as u8
1898 };
1899 }
1900 Some(())
1901}
1902
1903fn read_delta_q(br: &mut BitReader) -> Option<i8> {
1904 let present = br.read_bits(1)? == 1;
1905 if present {
1906 Some(br.read_su(7)? as i8)
1907 } else {
1908 Some(0)
1909 }
1910}
1911
1912fn parse_av1_segmentation_params(br: &mut BitReader, h: &mut Av1FrameHeader) -> Option<()> {
1914 h.segmentation_enabled = br.read_bits(1)? == 1;
1915 if h.segmentation_enabled {
1916 if h.primary_ref_frame == 7 {
1917 h.segmentation_update_map = true;
1919 h.segmentation_temporal_update = false;
1920 h.segmentation_update_data = true;
1921 } else {
1922 h.segmentation_update_map = br.read_bits(1)? == 1;
1923 if h.segmentation_update_map {
1924 h.segmentation_temporal_update = br.read_bits(1)? == 1;
1925 }
1926 h.segmentation_update_data = br.read_bits(1)? == 1;
1927 }
1928 if h.segmentation_update_data {
1929 const FEAT_INFO: [(u32, bool); 8] = [
1933 (8, true), (6, true), (6, true), (6, true), (6, true), (3, false), (0, false), (0, false), ];
1942 for seg in 0..8 {
1943 for (feat, &(bits, signed)) in FEAT_INFO.iter().enumerate() {
1944 let enabled = br.read_bits(1)? == 1;
1945 h.feature_enabled[seg][feat] = enabled;
1946 if enabled {
1947 if bits == 0 {
1948 h.feature_data[seg][feat] = 1;
1949 } else if signed {
1950 h.feature_data[seg][feat] = br.read_su(bits as usize + 1)? as i16;
1951 } else {
1952 h.feature_data[seg][feat] = br.read_bits(bits as usize)? as i16;
1953 }
1954 }
1955 }
1956 }
1957 }
1958 }
1959 Some(())
1960}
1961
1962fn parse_av1_loop_filter_params(
1964 br: &mut BitReader,
1965 h: &mut Av1FrameHeader,
1966 frame_is_intra: bool,
1967) -> Option<()> {
1968 if h.coded_lossless || h.allow_intrabc {
1969 h.loop_filter_level = [0; 4];
1970 h.loop_filter_sharpness = 0;
1971 h.loop_filter_delta_enabled = false;
1972 h.loop_filter_ref_deltas = [1, 0, 0, 0, -1, 0, -1, -1];
1973 h.loop_filter_mode_deltas = [0, 0];
1974 return Some(());
1975 }
1976 h.loop_filter_level[0] = br.read_bits(6)? as u8;
1977 h.loop_filter_level[1] = br.read_bits(6)? as u8;
1978 if h.loop_filter_level[0] > 0 || h.loop_filter_level[1] > 0 {
1979 h.loop_filter_level[2] = br.read_bits(6)? as u8;
1980 h.loop_filter_level[3] = br.read_bits(6)? as u8;
1981 }
1982 h.loop_filter_sharpness = br.read_bits(3)? as u8;
1983 h.loop_filter_delta_enabled = br.read_bits(1)? == 1;
1984 h.loop_filter_ref_deltas = [1, 0, 0, 0, -1, 0, -1, -1];
1986 h.loop_filter_mode_deltas = [0, 0];
1987 if h.loop_filter_delta_enabled {
1988 h.loop_filter_delta_update = br.read_bits(1)? == 1;
1989 if h.loop_filter_delta_update {
1990 let mut update_mask = 0u8;
1991 for i in 0..8 {
1992 let update = br.read_bits(1)? == 1;
1993 if update {
1994 update_mask |= 1 << i;
1995 h.loop_filter_ref_deltas[i] = br.read_su(7)? as i8;
1996 }
1997 }
1998 h.update_ref_delta_mask = update_mask;
1999 let mut mode_mask = 0u8;
2000 for i in 0..2 {
2001 let update = br.read_bits(1)? == 1;
2002 if update {
2003 mode_mask |= 1 << i;
2004 h.loop_filter_mode_deltas[i] = br.read_su(7)? as i8;
2005 }
2006 }
2007 h.update_mode_delta_mask = mode_mask;
2008 }
2009 }
2010 let _ = frame_is_intra; Some(())
2012}
2013
2014fn parse_av1_cdef_params(
2016 br: &mut BitReader,
2017 h: &mut Av1FrameHeader,
2018 num_planes: u32,
2019) -> Option<()> {
2020 h.cdef_damping_minus_3 = br.read_bits(2)? as u8;
2021 h.cdef_bits = br.read_bits(2)? as u8;
2022 let count = 1usize << h.cdef_bits;
2023 for i in 0..count {
2024 h.cdef_y_pri_strength[i] = br.read_bits(4)? as u8;
2025 let y_sec = br.read_bits(2)? as u8;
2026 h.cdef_y_sec_strength[i] = if y_sec == 3 { 4 } else { y_sec };
2030 if num_planes > 1 {
2031 h.cdef_uv_pri_strength[i] = br.read_bits(4)? as u8;
2032 let uv_sec = br.read_bits(2)? as u8;
2033 h.cdef_uv_sec_strength[i] = if uv_sec == 3 { 4 } else { uv_sec };
2034 }
2035 }
2036 Some(())
2037}
2038
2039fn parse_av1_lr_params(
2041 br: &mut BitReader,
2042 h: &mut Av1FrameHeader,
2043 num_planes: u32,
2044 seq: &Av1SequenceHeader,
2045) -> Option<()> {
2046 let mut uses_lr = false;
2047 let mut uses_chroma_lr = false;
2048 for i in 0..(num_planes as usize) {
2049 let lr_type = br.read_bits(2)? as u8;
2050 h.lr_type[i] = lr_type;
2051 if lr_type != 0 {
2052 uses_lr = true;
2053 if i > 0 {
2054 uses_chroma_lr = true;
2055 }
2056 }
2057 }
2058 if uses_lr {
2059 let base = br.read_bits(1)? as u8;
2064 h.lr_unit_shift = if base != 0 {
2065 let extra = br.read_bits(1)? as u8;
2066 base + extra
2067 } else {
2068 0
2069 };
2070 if num_planes > 1 && uses_chroma_lr && seq.chroma_subsampling_x && seq.chroma_subsampling_y
2073 {
2074 h.lr_uv_shift = br.read_bits(1)? as u8;
2075 }
2076 }
2077 Some(())
2078}
2079
2080fn skip_av1_global_motion_params(br: &mut BitReader) -> Option<()> {
2084 for _ in 0..7 {
2085 let is_global = br.read_bits(1)? == 1;
2086 let is_rot_zoom = if is_global {
2087 br.read_bits(1)? == 1
2088 } else {
2089 false
2090 };
2091 let _is_translation = if is_global && !is_rot_zoom {
2092 br.read_bits(1)? == 1
2093 } else {
2094 false
2095 };
2096 let gm_type = if is_global && !is_rot_zoom {
2097 2u8 } else if is_rot_zoom {
2099 3u8 } else if is_global {
2101 4u8 } else {
2103 0u8 };
2105 if gm_type >= 3 {
2106 for _ in 0..2 {
2108 let _a = av1_read_subexp(br, 12, 0)?;
2109 let _b = av1_read_subexp(br, 12, 0)?;
2110 }
2111 }
2112 if gm_type >= 2 {
2113 for _ in 0..2 {
2115 let _a = av1_read_subexp(br, 12, 0)?;
2116 }
2117 }
2118 }
2119 Some(())
2120}
2121
2122fn av1_read_subexp(br: &mut BitReader, num_syms: u32, _ref: i32) -> Option<i32> {
2123 let bits = av1_ceil_log2(num_syms) as usize + 1; let _ = br.read_bits(bits.min(16))?;
2129 Some(0)
2130}
2131
2132fn skip_av1_film_grain_params(br: &mut BitReader, seq: &Av1SequenceHeader) -> Option<()> {
2136 let apply_grain = br.read_bits(1)? == 1;
2137 if !apply_grain {
2138 return Some(());
2139 }
2140 let _grain_seed = br.read_bits(16)?;
2141 let update_grain = br.read_bits(1)? == 1;
2142 if !update_grain {
2143 let _film_grain_params_ref_idx = br.read_bits(3)?;
2144 return Some(());
2145 }
2146 let num_y_points = br.read_bits(4)?;
2147 for _ in 0..num_y_points {
2148 let _point_y_value = br.read_bits(8)?;
2149 let _point_y_scaling = br.read_bits(8)?;
2150 }
2151 let chroma_scaling_from_luma = if seq.monochrome {
2152 false
2153 } else {
2154 br.read_bits(1)? == 1
2155 };
2156 let num_cb_points: u32;
2157 let num_cr_points: u32;
2158 if seq.monochrome
2159 || chroma_scaling_from_luma
2160 || (seq.chroma_subsampling_x && seq.chroma_subsampling_y && num_y_points == 0)
2161 {
2162 num_cb_points = 0;
2163 num_cr_points = 0;
2164 } else {
2165 num_cb_points = br.read_bits(4)?;
2166 for _ in 0..num_cb_points {
2167 let _point_cb_value = br.read_bits(8)?;
2168 let _point_cb_scaling = br.read_bits(8)?;
2169 }
2170 num_cr_points = br.read_bits(4)?;
2171 for _ in 0..num_cr_points {
2172 let _point_cr_value = br.read_bits(8)?;
2173 let _point_cr_scaling = br.read_bits(8)?;
2174 }
2175 }
2176 let _grain_scaling_minus_8 = br.read_bits(2)?;
2177 let ar_coeff_lag = br.read_bits(2)?;
2178 let num_pos_y = 2 * ar_coeff_lag * (ar_coeff_lag + 1);
2179 let num_pos_chroma = if num_y_points > 0 {
2180 num_pos_y + 1
2181 } else {
2182 num_pos_y
2183 };
2184 for _ in 0..num_pos_y {
2185 let _ar_coeff_y_plus_128 = br.read_bits(8)?;
2186 }
2187 if chroma_scaling_from_luma || num_cb_points > 0 {
2188 for _ in 0..num_pos_chroma {
2189 let _ar_coeff_cb_plus_128 = br.read_bits(8)?;
2190 }
2191 }
2192 if chroma_scaling_from_luma || num_cr_points > 0 {
2193 for _ in 0..num_pos_chroma {
2194 let _ar_coeff_cr_plus_128 = br.read_bits(8)?;
2195 }
2196 }
2197 let _ar_coeff_shift_minus_6 = br.read_bits(2)?;
2198 let _grain_scale_shift = br.read_bits(2)?;
2199 if num_cb_points > 0 {
2200 let _cb_mult = br.read_bits(8)?;
2201 let _cb_luma_mult = br.read_bits(8)?;
2202 let _cb_offset = br.read_bits(9)?;
2203 }
2204 if num_cr_points > 0 {
2205 let _cr_mult = br.read_bits(8)?;
2206 let _cr_luma_mult = br.read_bits(8)?;
2207 let _cr_offset = br.read_bits(9)?;
2208 }
2209 let _overlap_flag = br.read_bits(1)?;
2210 let _clip_to_restricted_range = br.read_bits(1)?;
2211 Some(())
2212}
2213
2214pub fn av1_frame_header_offset(sample: &[u8]) -> Option<u32> {
2225 let mut i = 0usize;
2226 while i < sample.len() {
2227 let header = sample[i];
2228 let obu_type = (header >> 3) & 0x0F;
2229 let extension_flag = (header >> 2) & 0x01;
2230 let has_size_field = (header >> 1) & 0x01;
2231 let mut p = i + 1;
2232 if extension_flag == 1 {
2233 p += 1;
2234 }
2235 let (size, leb) = if has_size_field == 1 {
2236 let (s, n) = read_leb128(&sample[p..])?;
2237 p += n;
2238 (s as usize, n)
2239 } else {
2240 return None;
2243 };
2244 let _ = leb;
2245 if obu_type == 3 || obu_type == 6 {
2246 return Some(p as u32);
2247 }
2248 p += size;
2249 i = p;
2250 }
2251 None
2252}
2253
2254pub fn av1_tile_group_offset(sample: &[u8], seq: &Av1SequenceHeader) -> Option<u32> {
2266 let mut i = 0usize;
2269 while i < sample.len() {
2270 let header = sample[i];
2271 let obu_type = (header >> 3) & 0x0F;
2272 let extension_flag = (header >> 2) & 0x01;
2273 let has_size_field = (header >> 1) & 0x01;
2274 let mut p = i + 1;
2275 if extension_flag == 1 {
2276 p += 1;
2277 }
2278 let size = if has_size_field == 1 {
2279 let (s, n) = read_leb128(&sample[p..])?;
2280 p += n;
2281 s as usize
2282 } else {
2283 return None;
2284 };
2285 if obu_type == 4 {
2286 return Some(p as u32);
2287 }
2288 p += size;
2289 i = p;
2290 }
2291 let (_obu_bytes, payload_offset) = find_av1_obu_with_offset(sample, 6)?;
2294 let hdr = parse_av1_frame_header(sample, seq)?;
2295 Some(payload_offset as u32 + hdr.tile_group_offset_in_obu)
2296}
2297
2298pub fn av1_tile_group_offset_fallback(sample: &[u8]) -> Option<u32> {
2303 let mut i = 0usize;
2304 while i < sample.len() {
2305 let header = sample[i];
2306 let obu_type = (header >> 3) & 0x0F;
2307 let extension_flag = (header >> 2) & 0x01;
2308 let has_size_field = (header >> 1) & 0x01;
2309 let mut p = i + 1;
2310 if extension_flag == 1 {
2311 p += 1;
2312 }
2313 let size = if has_size_field == 1 {
2314 let (s, n) = read_leb128(&sample[p..])?;
2315 p += n;
2316 s as usize
2317 } else {
2318 return None;
2319 };
2320 if obu_type == 4 {
2321 return Some(p as u32);
2322 }
2323 p += size;
2324 i = p;
2325 }
2326 av1_frame_header_offset(sample)
2327}
2328
2329fn read_av1_uvlc(br: &mut BitReader) -> Option<u32> {
2332 let mut leading_zeros = 0;
2333 while leading_zeros < 32 {
2334 if br.read_bits(1)? == 1 {
2335 break;
2336 }
2337 leading_zeros += 1;
2338 }
2339 if leading_zeros >= 32 {
2340 return None;
2341 }
2342 if leading_zeros == 0 {
2343 return Some(0);
2344 }
2345 let suffix = br.read_bits(leading_zeros)?;
2346 Some((1u32 << leading_zeros) - 1 + suffix)
2347}
2348
2349#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2359pub struct Mpeg2SeqInfo {
2360 pub width: u32,
2361 pub height: u32,
2362}
2363
2364pub fn detect_dims(codec: &str, samples: &[Vec<u8>]) -> Option<(u32, u32)> {
2373 if samples.is_empty() {
2374 return None;
2375 }
2376 let sample = &samples[0];
2377 match codec.to_lowercase().as_str() {
2378 "h264" | "avc1" | "avc" | "avc3" => {
2379 let info = parse_h264_sps(sample)?;
2380 Some((info.width?, info.height?))
2381 }
2382 "h265" | "hevc" | "hvc1" | "hev1" | "hvc2" | "hev2" => {
2383 let info = parse_hevc_sps(sample)?;
2384 Some((info.width?, info.height?))
2385 }
2386 "mpeg2" | "mpeg2video" | "mp2v" => {
2387 let info = parse_mpeg2_sequence_header(sample)?;
2388 Some((info.width, info.height))
2389 }
2390 _ => None,
2391 }
2392}
2393
2394pub fn parse_h264_sps(sample: &[u8]) -> Option<H264SpsInfo> {
2401 let sps = find_h264_sps(sample)?;
2402 let rbsp = remove_h264_rbsp_stuffing(sps);
2403 let mut br = BitReader::new(&rbsp);
2404
2405 let profile_idc = br.read_bits(8)? as u8;
2406 let constraint_set_flags = br.read_bits(8)? as u8;
2407 let level_idc = br.read_bits(8)? as u8;
2408 let _seq_parameter_set_id = br.read_ue()?;
2409
2410 let profile_gates_chroma = matches!(
2411 profile_idc,
2412 100 | 110 | 122 | 244 | 44 | 83 | 86 | 118 | 128 | 138 | 139 | 134 | 135
2413 );
2414
2415 let (
2416 chroma_format_idc,
2417 separate_colour_plane_flag,
2418 bit_depth_luma,
2419 bit_depth_chroma,
2420 qpprime_y_zero,
2421 scaling_matrix,
2422 ) = if profile_gates_chroma {
2423 let chroma = br.read_ue()? as u8;
2424 let separate = if chroma == 3 {
2425 br.read_bits(1)? == 1
2426 } else {
2427 false
2428 };
2429 let bit_depth_luma_m8 = br.read_ue()?;
2430 let bit_depth_chroma_m8 = br.read_ue()?;
2431 let qpprime = br.read_bits(1)? == 1;
2432 let scaling_matrix_present = br.read_bits(1)? == 1;
2433 if scaling_matrix_present {
2434 let num_lists = if chroma == 3 { 12 } else { 8 };
2438 for i in 0..num_lists {
2439 if br.read_bits(1)? == 1 {
2440 let size = if i < 6 { 16 } else { 64 };
2441 let mut last_scale: i32 = 8;
2442 let mut next_scale: i32 = 8;
2443 for _j in 0..size {
2444 if next_scale != 0 {
2445 let delta = br.read_se()?;
2446 next_scale = (last_scale + delta + 256).rem_euclid(256);
2447 }
2448 if next_scale != 0 {
2449 last_scale = next_scale;
2450 }
2451 }
2452 }
2453 }
2454 }
2455 (
2456 chroma,
2457 separate,
2458 bit_depth_luma_m8 as u8 + 8,
2459 bit_depth_chroma_m8 as u8 + 8,
2460 qpprime,
2461 scaling_matrix_present,
2462 )
2463 } else {
2464 (1u8, false, 8u8, 8u8, false, false)
2465 };
2466
2467 let info_prefix = H264SpsInfo {
2472 profile_idc,
2473 constraint_set_flags,
2474 level_idc,
2475 chroma_format_idc,
2476 separate_colour_plane_flag,
2477 bit_depth_luma,
2478 bit_depth_chroma,
2479 frame_mbs_only: true,
2480 width: None,
2481 height: None,
2482 log2_max_frame_num_minus4: None,
2483 pic_order_cnt_type: None,
2484 log2_max_pic_order_cnt_lsb_minus4: None,
2485 delta_pic_order_always_zero_flag: None,
2486 qpprime_y_zero_transform_bypass_flag: Some(qpprime_y_zero),
2487 seq_scaling_matrix_present_flag: Some(scaling_matrix),
2488 max_num_ref_frames: None,
2489 gaps_in_frame_num_value_allowed_flag: None,
2490 mb_adaptive_frame_field_flag: None,
2491 direct_8x8_inference_flag: None,
2492 frame_cropping_flag: None,
2493 frame_crop_left_offset: None,
2494 frame_crop_right_offset: None,
2495 frame_crop_top_offset: None,
2496 frame_crop_bottom_offset: None,
2497 offset_for_non_ref_pic: None,
2498 offset_for_top_to_bottom_field: None,
2499 num_ref_frames_in_pic_order_cnt_cycle: None,
2500 offset_for_ref_frame: Vec::new(),
2501 };
2502
2503 let Some(dims) = parse_h264_sps_dims(&mut br, chroma_format_idc, separate_colour_plane_flag)
2504 else {
2505 return Some(info_prefix);
2506 };
2507
2508 Some(H264SpsInfo {
2509 frame_mbs_only: dims.frame_mbs_only,
2510 width: Some(dims.width),
2511 height: Some(dims.height),
2512 log2_max_frame_num_minus4: Some(dims.log2_max_frame_num_minus4),
2513 pic_order_cnt_type: Some(dims.pic_order_cnt_type),
2514 log2_max_pic_order_cnt_lsb_minus4: dims.log2_max_pic_order_cnt_lsb_minus4,
2515 delta_pic_order_always_zero_flag: dims.delta_pic_order_always_zero_flag,
2516 max_num_ref_frames: Some(dims.max_num_ref_frames),
2517 gaps_in_frame_num_value_allowed_flag: Some(dims.gaps_in_frame_num_value_allowed_flag),
2518 mb_adaptive_frame_field_flag: dims.mb_adaptive_frame_field_flag,
2519 direct_8x8_inference_flag: Some(dims.direct_8x8_inference_flag),
2520 frame_cropping_flag: Some(dims.frame_cropping_flag),
2521 frame_crop_left_offset: Some(dims.crop_left),
2522 frame_crop_right_offset: Some(dims.crop_right),
2523 frame_crop_top_offset: Some(dims.crop_top),
2524 frame_crop_bottom_offset: Some(dims.crop_bottom),
2525 offset_for_non_ref_pic: dims.offset_for_non_ref_pic,
2526 offset_for_top_to_bottom_field: dims.offset_for_top_to_bottom_field,
2527 num_ref_frames_in_pic_order_cnt_cycle: dims.num_ref_frames_in_pic_order_cnt_cycle,
2528 offset_for_ref_frame: dims.offset_for_ref_frame,
2529 ..info_prefix
2530 })
2531}
2532
2533struct H264Dims {
2534 width: u32,
2535 height: u32,
2536 frame_mbs_only: bool,
2537 log2_max_frame_num_minus4: u8,
2538 pic_order_cnt_type: u8,
2539 log2_max_pic_order_cnt_lsb_minus4: Option<u8>,
2540 delta_pic_order_always_zero_flag: Option<bool>,
2541 offset_for_non_ref_pic: Option<i32>,
2542 offset_for_top_to_bottom_field: Option<i32>,
2543 num_ref_frames_in_pic_order_cnt_cycle: Option<u8>,
2544 offset_for_ref_frame: Vec<i32>,
2545 max_num_ref_frames: u8,
2546 gaps_in_frame_num_value_allowed_flag: bool,
2547 mb_adaptive_frame_field_flag: Option<bool>,
2548 direct_8x8_inference_flag: bool,
2549 frame_cropping_flag: bool,
2550 crop_left: u32,
2551 crop_right: u32,
2552 crop_top: u32,
2553 crop_bottom: u32,
2554}
2555
2556fn parse_h264_sps_dims(
2557 br: &mut BitReader,
2558 chroma_format_idc: u8,
2559 separate_colour_plane_flag: bool,
2560) -> Option<H264Dims> {
2561 let log2_max_frame_num_minus4 = br.read_ue()? as u8;
2562 let pic_order_cnt_type = br.read_ue()? as u8;
2563 let mut log2_max_pic_order_cnt_lsb_minus4 = None;
2564 let mut delta_pic_order_always_zero_flag = None;
2565 let mut offset_for_non_ref_pic = None;
2566 let mut offset_for_top_to_bottom_field = None;
2567 let mut num_ref_frames_in_pic_order_cnt_cycle: Option<u8> = None;
2568 let mut offset_for_ref_frame: Vec<i32> = Vec::new();
2569 match pic_order_cnt_type {
2570 0 => {
2571 log2_max_pic_order_cnt_lsb_minus4 = Some(br.read_ue()? as u8);
2572 }
2573 1 => {
2574 delta_pic_order_always_zero_flag = Some(br.read_bits(1)? == 1);
2575 offset_for_non_ref_pic = Some(br.read_se()?);
2576 offset_for_top_to_bottom_field = Some(br.read_se()?);
2577 let cycle_len = br.read_ue()?;
2578 let capped = cycle_len.min(255) as u8;
2581 num_ref_frames_in_pic_order_cnt_cycle = Some(capped);
2582 offset_for_ref_frame.reserve(capped as usize);
2583 for _ in 0..capped {
2584 offset_for_ref_frame.push(br.read_se()?);
2585 }
2586 }
2587 2 => { }
2588 _ => return None, }
2590 let max_num_ref_frames = br.read_ue()?.min(u8::MAX as u32) as u8;
2591 let gaps_in_frame_num_value_allowed_flag = br.read_bits(1)? == 1;
2592 let pic_width_in_mbs_minus1 = br.read_ue()?;
2593 let pic_height_in_map_units_minus1 = br.read_ue()?;
2594 let frame_mbs_only_flag = br.read_bits(1)?;
2595 let mut mb_adaptive_frame_field_flag = None;
2596 if frame_mbs_only_flag == 0 {
2597 mb_adaptive_frame_field_flag = Some(br.read_bits(1)? == 1);
2598 }
2599 let direct_8x8_inference_flag = br.read_bits(1)? == 1;
2600 let frame_cropping_flag = br.read_bits(1)? == 1;
2601 let (cl, cr, ct, cb) = if frame_cropping_flag {
2602 (br.read_ue()?, br.read_ue()?, br.read_ue()?, br.read_ue()?)
2603 } else {
2604 (0, 0, 0, 0)
2605 };
2606
2607 let pic_width_in_mbs = pic_width_in_mbs_minus1.saturating_add(1);
2608 let pic_height_in_map_units = pic_height_in_map_units_minus1.saturating_add(1);
2609 let frame_mbs_only = frame_mbs_only_flag == 1;
2610 let frame_height_in_mbs = if frame_mbs_only {
2611 pic_height_in_map_units
2612 } else {
2613 pic_height_in_map_units.saturating_mul(2)
2614 };
2615
2616 let chroma_array_type = if separate_colour_plane_flag {
2618 0
2619 } else {
2620 chroma_format_idc
2621 };
2622 let (sub_w, sub_h) = match chroma_array_type {
2623 0 => (1u32, 1u32), 1 => (2, 2), 2 => (2, 1), 3 => (1, 1), _ => (1, 1),
2628 };
2629 let (crop_x, crop_y) = if chroma_array_type == 0 {
2630 (1u32, 2u32 - frame_mbs_only_flag)
2631 } else {
2632 (sub_w, sub_h * (2 - frame_mbs_only_flag))
2633 };
2634
2635 let width = pic_width_in_mbs
2636 .saturating_mul(16)
2637 .saturating_sub(crop_x.saturating_mul(cl.saturating_add(cr)));
2638 let height = frame_height_in_mbs
2639 .saturating_mul(16)
2640 .saturating_sub(crop_y.saturating_mul(ct.saturating_add(cb)));
2641
2642 Some(H264Dims {
2643 width,
2644 height,
2645 frame_mbs_only,
2646 log2_max_frame_num_minus4,
2647 pic_order_cnt_type,
2648 log2_max_pic_order_cnt_lsb_minus4,
2649 delta_pic_order_always_zero_flag,
2650 offset_for_non_ref_pic,
2651 offset_for_top_to_bottom_field,
2652 num_ref_frames_in_pic_order_cnt_cycle,
2653 offset_for_ref_frame,
2654 max_num_ref_frames,
2655 gaps_in_frame_num_value_allowed_flag,
2656 mb_adaptive_frame_field_flag,
2657 direct_8x8_inference_flag,
2658 frame_cropping_flag,
2659 crop_left: cl,
2660 crop_right: cr,
2661 crop_top: ct,
2662 crop_bottom: cb,
2663 })
2664}
2665
2666pub fn parse_hevc_sps(sample: &[u8]) -> Option<HevcSpsInfo> {
2671 let sps = find_hevc_sps(sample)?;
2672 let rbsp = remove_h264_rbsp_stuffing(sps);
2673 let mut br = BitReader::new(&rbsp);
2674
2675 let sps_video_parameter_set_id = br.read_bits(4)? as u8;
2676 let sps_max_sub_layers_minus1 = br.read_bits(3)? as u8;
2677 let sps_temporal_id_nesting_flag = br.read_bits(1)? == 1;
2678 let general_profile_space = br.read_bits(2)? as u8;
2682 let tier_flag = br.read_bits(1)? == 1;
2683 let profile_idc = br.read_bits(5)? as u8;
2684 let profile_compatibility_flags = br.read_bits(32)?;
2686 let constraint_hi = br.read_bits(24)? as u64;
2690 let constraint_lo = br.read_bits(24)? as u64;
2691 let general_constraint_flags = (constraint_hi << 24) | constraint_lo;
2692 let level_idc = br.read_bits(8)? as u8;
2693 let mut spl = Vec::with_capacity(sps_max_sub_layers_minus1 as usize);
2696 let mut sll = Vec::with_capacity(sps_max_sub_layers_minus1 as usize);
2697 for _ in 0..sps_max_sub_layers_minus1 {
2698 spl.push(br.read_bits(1)?);
2699 sll.push(br.read_bits(1)?);
2700 }
2701 if sps_max_sub_layers_minus1 > 0 {
2702 for _ in sps_max_sub_layers_minus1 as usize..8 {
2703 let _ = br.read_bits(2)?;
2704 }
2705 }
2706 for i in 0..sps_max_sub_layers_minus1 as usize {
2707 if spl[i] == 1 {
2708 let _ = br.read_bits(8)?;
2709 let _ = br.read_bits(32)?;
2710 let _ = br.read_bits(48)?;
2711 }
2712 if sll[i] == 1 {
2713 let _ = br.read_bits(8)?;
2714 }
2715 }
2716
2717 let sps_seq_parameter_set_id = br.read_ue()? as u8;
2718 let chroma_format_idc = br.read_ue()? as u8;
2719 let separate_colour_plane_flag = if chroma_format_idc == 3 {
2720 br.read_bits(1)? == 1
2721 } else {
2722 false
2723 };
2724 let pic_width = br.read_ue()?;
2725 let pic_height = br.read_ue()?;
2726 let conformance_window_flag = br.read_bits(1)?;
2727 let (cl, cr, ct, cb) = if conformance_window_flag == 1 {
2728 (br.read_ue()?, br.read_ue()?, br.read_ue()?, br.read_ue()?)
2729 } else {
2730 (0u32, 0u32, 0u32, 0u32)
2731 };
2732 let bit_depth_luma_m8 = br.read_ue()?;
2733 let bit_depth_chroma_m8 = br.read_ue()?;
2734 let log2_max_pic_order_cnt_lsb_minus4 = br.read_ue()? as u8;
2735
2736 let sps_sub_layer_ordering_info_present_flag = br.read_bits(1)? == 1;
2743 let mut max_dec_pic_buffering_minus1 = [0u8; 7];
2744 let mut max_num_reorder_pics = [0u8; 7];
2745 let mut max_latency_increase_plus1 = [0u32; 7];
2746 let start = if sps_sub_layer_ordering_info_present_flag {
2747 0
2748 } else {
2749 sps_max_sub_layers_minus1
2750 };
2751 for i in start..=sps_max_sub_layers_minus1 {
2752 let dec = br.read_ue()?;
2753 let nro = br.read_ue()?;
2754 let latency = br.read_ue()?;
2755 let idx = (i as usize).min(6);
2756 max_dec_pic_buffering_minus1[idx] = dec.min(u8::MAX as u32) as u8;
2757 max_num_reorder_pics[idx] = nro.min(u8::MAX as u32) as u8;
2758 max_latency_increase_plus1[idx] = latency;
2759 }
2760 if !sps_sub_layer_ordering_info_present_flag {
2762 let top = sps_max_sub_layers_minus1 as usize;
2763 for i in 0..top {
2764 max_dec_pic_buffering_minus1[i] = max_dec_pic_buffering_minus1[top];
2765 max_num_reorder_pics[i] = max_num_reorder_pics[top];
2766 max_latency_increase_plus1[i] = max_latency_increase_plus1[top];
2767 }
2768 }
2769
2770 let log2_min_luma_coding_block_size_minus3 = br.read_ue()? as u8;
2771 let log2_diff_max_min_luma_coding_block_size = br.read_ue()? as u8;
2772 let log2_min_luma_transform_block_size_minus2 = br.read_ue()? as u8;
2773 let log2_diff_max_min_luma_transform_block_size = br.read_ue()? as u8;
2774 let max_transform_hierarchy_depth_inter = br.read_ue()? as u8;
2775 let max_transform_hierarchy_depth_intra = br.read_ue()? as u8;
2776
2777 let scaling_list_enabled_flag = br.read_bits(1)? == 1;
2778 if scaling_list_enabled_flag {
2779 let sps_scaling_list_data_present_flag = br.read_bits(1)? == 1;
2780 if sps_scaling_list_data_present_flag {
2781 skip_hevc_scaling_list_data(&mut br)?;
2782 }
2783 }
2784 let amp_enabled_flag = br.read_bits(1)? == 1;
2785 let sample_adaptive_offset_enabled_flag = br.read_bits(1)? == 1;
2786 let pcm_enabled_flag = br.read_bits(1)? == 1;
2787 let mut pcm_loop_filter_disabled_flag = false;
2788 if pcm_enabled_flag {
2789 let _pcm_sample_bit_depth_luma_minus1 = br.read_bits(4)?;
2790 let _pcm_sample_bit_depth_chroma_minus1 = br.read_bits(4)?;
2791 let _log2_min_pcm_luma_cb_size_minus3 = br.read_ue()?;
2792 let _log2_diff_max_min_pcm_luma_cb_size = br.read_ue()?;
2793 pcm_loop_filter_disabled_flag = br.read_bits(1)? == 1;
2794 }
2795 let num_short_term_ref_pic_sets = br.read_ue()? as u8;
2796 let mut st_rps_offsets: Vec<()> = Vec::with_capacity(num_short_term_ref_pic_sets as usize);
2802 for rps_idx in 0..num_short_term_ref_pic_sets {
2803 skip_hevc_short_term_rps(&mut br, rps_idx, num_short_term_ref_pic_sets)?;
2804 st_rps_offsets.push(());
2805 }
2806 let long_term_ref_pics_present_flag = br.read_bits(1)? == 1;
2807 if long_term_ref_pics_present_flag {
2808 let num_long_term_ref_pics_sps = br.read_ue()?;
2809 let lsb_bits = (log2_max_pic_order_cnt_lsb_minus4 as usize) + 4;
2810 for _ in 0..num_long_term_ref_pics_sps {
2811 let _lt_ref_pic_poc_lsb_sps = br.read_bits(lsb_bits)?;
2812 let _used_by_curr_pic_lt_sps_flag = br.read_bits(1)?;
2813 }
2814 }
2815 let sps_temporal_mvp_enabled_flag = br.read_bits(1)? == 1;
2816 let strong_intra_smoothing_enabled_flag = br.read_bits(1)? == 1;
2817 let chroma_array_type = if separate_colour_plane_flag {
2820 0
2821 } else {
2822 chroma_format_idc
2823 };
2824 let (sub_w, sub_h) = match chroma_array_type {
2825 0 => (1u32, 1u32),
2826 1 => (2, 2),
2827 2 => (2, 1),
2828 3 => (1, 1),
2829 _ => (1, 1),
2830 };
2831 let width = pic_width.saturating_sub(sub_w.saturating_mul(cl.saturating_add(cr)));
2832 let height = pic_height.saturating_sub(sub_h.saturating_mul(ct.saturating_add(cb)));
2833
2834 Some(HevcSpsInfo {
2835 sps_video_parameter_set_id,
2836 sps_seq_parameter_set_id,
2837 sps_max_sub_layers_minus1,
2838 sps_temporal_id_nesting_flag,
2839 chroma_format_idc,
2840 separate_colour_plane_flag,
2841 bit_depth_luma: bit_depth_luma_m8 as u8 + 8,
2842 bit_depth_chroma: bit_depth_chroma_m8 as u8 + 8,
2843 width: Some(width),
2844 height: Some(height),
2845 conf_win_left_offset: cl,
2846 conf_win_right_offset: cr,
2847 conf_win_top_offset: ct,
2848 conf_win_bottom_offset: cb,
2849 log2_max_pic_order_cnt_lsb_minus4,
2850 log2_min_luma_coding_block_size_minus3,
2851 log2_diff_max_min_luma_coding_block_size,
2852 log2_min_luma_transform_block_size_minus2,
2853 log2_diff_max_min_luma_transform_block_size,
2854 max_transform_hierarchy_depth_inter,
2855 max_transform_hierarchy_depth_intra,
2856 scaling_list_enabled_flag,
2857 sps_sub_layer_ordering_info_present_flag,
2858 amp_enabled_flag,
2859 sample_adaptive_offset_enabled_flag,
2860 pcm_enabled_flag,
2861 pcm_loop_filter_disabled_flag,
2862 num_short_term_ref_pic_sets,
2863 long_term_ref_pics_present_flag,
2864 sps_temporal_mvp_enabled_flag,
2865 strong_intra_smoothing_enabled_flag,
2866 profile_idc,
2867 level_idc,
2868 tier_flag,
2869 max_dec_pic_buffering_minus1,
2870 max_num_reorder_pics,
2871 max_latency_increase_plus1,
2872 profile_compatibility_flags,
2873 general_profile_space,
2874 general_constraint_flags,
2875 })
2876}
2877
2878fn skip_hevc_scaling_list_data(br: &mut BitReader) -> Option<()> {
2883 for size_id in 0..4 {
2884 let matrix_count = if size_id == 3 { 2 } else { 6 };
2885 for _matrix_id in 0..matrix_count {
2886 let scaling_list_pred_mode_flag = br.read_bits(1)? == 1;
2887 if !scaling_list_pred_mode_flag {
2888 let _scaling_list_pred_matrix_id_delta = br.read_ue()?;
2889 } else {
2890 let coef_num: usize = (1 << (4 + (size_id << 1))).min(64);
2891 if size_id > 1 {
2892 let _scaling_list_dc_coef_minus8 = br.read_se()?;
2893 }
2894 for _ in 0..coef_num {
2895 let _scaling_list_delta_coef = br.read_se()?;
2896 }
2897 }
2898 }
2899 }
2900 Some(())
2901}
2902
2903fn skip_hevc_short_term_rps(br: &mut BitReader, st_rps_idx: u8, num_st_rps: u8) -> Option<()> {
2907 let inter_ref_pic_set_prediction_flag = if st_rps_idx != 0 {
2908 br.read_bits(1)? == 1
2909 } else {
2910 false
2911 };
2912 if inter_ref_pic_set_prediction_flag {
2913 if st_rps_idx == num_st_rps {
2914 let _delta_idx_minus1 = br.read_ue()?;
2915 }
2916 let _delta_rps_sign = br.read_bits(1)?;
2917 let _abs_delta_rps_minus1 = br.read_ue()?;
2918 for _ in 0..16 {
2923 let used = br.read_bits(1)?;
2924 if used == 0 {
2925 let _use_delta_flag = br.read_bits(1)?;
2926 }
2927 }
2928 } else {
2929 let num_negative_pics = br.read_ue()?;
2930 let num_positive_pics = br.read_ue()?;
2931 for _ in 0..num_negative_pics {
2932 let _delta_poc_s0_minus1 = br.read_ue()?;
2933 let _used_by_curr_pic_s0_flag = br.read_bits(1)?;
2934 }
2935 for _ in 0..num_positive_pics {
2936 let _delta_poc_s1_minus1 = br.read_ue()?;
2937 let _used_by_curr_pic_s1_flag = br.read_bits(1)?;
2938 }
2939 }
2940 Some(())
2941}
2942
2943pub fn parse_h265_vps(sample: &[u8]) -> Option<H265VpsInfo> {
2945 let nal = find_hevc_nal_by_type(sample, 32)?;
2946 let rbsp = remove_h264_rbsp_stuffing(nal);
2947 let mut br = BitReader::new(&rbsp);
2948 let vps_video_parameter_set_id = br.read_bits(4)? as u8;
2949 let _vps_base_layer_internal_flag = br.read_bits(1)?;
2950 let _vps_base_layer_available_flag = br.read_bits(1)?;
2951 let _vps_max_layers_minus1 = br.read_bits(6)?;
2952 let vps_max_sub_layers_minus1 = br.read_bits(3)? as u8;
2953 let vps_temporal_id_nesting_flag = br.read_bits(1)? == 1;
2954 let _vps_reserved_0xffff_16bits = br.read_bits(16)?;
2955 let _gp_space = br.read_bits(2)?;
2958 let tier_flag = br.read_bits(1)? == 1;
2959 let profile_idc = br.read_bits(5)? as u8;
2960 let _ = br.read_bits(32)?; let _ = br.read_bits(48)?; let level_idc = br.read_bits(8)? as u8;
2963 Some(H265VpsInfo {
2964 vps_video_parameter_set_id,
2965 vps_max_sub_layers_minus1,
2966 vps_temporal_id_nesting_flag,
2967 profile_idc,
2968 level_idc,
2969 tier_flag,
2970 })
2971}
2972
2973pub fn parse_h265_pps(sample: &[u8]) -> Option<H265PpsInfo> {
2975 let nal = find_hevc_nal_by_type(sample, 34)?;
2976 let rbsp = remove_h264_rbsp_stuffing(nal);
2977 let mut br = BitReader::new(&rbsp);
2978 let pps_pic_parameter_set_id = br.read_ue()? as u8;
2979 let pps_seq_parameter_set_id = br.read_ue()? as u8;
2980 let dependent_slice_segments_enabled_flag = br.read_bits(1)? == 1;
2981 let output_flag_present_flag = br.read_bits(1)? == 1;
2982 let num_extra_slice_header_bits = br.read_bits(3)? as u8;
2983 let sign_data_hiding_enabled_flag = br.read_bits(1)? == 1;
2984 let cabac_init_present_flag = br.read_bits(1)? == 1;
2985 let num_ref_idx_l0_default_active_minus1 = br.read_ue()? as u8;
2986 let num_ref_idx_l1_default_active_minus1 = br.read_ue()? as u8;
2987 let init_qp_minus26 = clamp_to_i8(br.read_se()?);
2988 let constrained_intra_pred_flag = br.read_bits(1)? == 1;
2989 let transform_skip_enabled_flag = br.read_bits(1)? == 1;
2990 let cu_qp_delta_enabled_flag = br.read_bits(1)? == 1;
2991 let diff_cu_qp_delta_depth = if cu_qp_delta_enabled_flag {
2992 br.read_ue()? as u8
2993 } else {
2994 0
2995 };
2996 let pps_cb_qp_offset = clamp_to_i8(br.read_se()?);
2997 let pps_cr_qp_offset = clamp_to_i8(br.read_se()?);
2998 let pps_slice_chroma_qp_offsets_present_flag = br.read_bits(1)? == 1;
2999 let weighted_pred_flag = br.read_bits(1)? == 1;
3000 let weighted_bipred_flag = br.read_bits(1)? == 1;
3001 let transquant_bypass_enabled_flag = br.read_bits(1)? == 1;
3002 let tiles_enabled_flag = br.read_bits(1)? == 1;
3003 let entropy_coding_sync_enabled_flag = br.read_bits(1)? == 1;
3004
3005 let mut num_tile_columns_minus1 = 0u8;
3010 let mut num_tile_rows_minus1 = 0u8;
3011 let mut uniform_spacing_flag = true;
3012 let mut loop_filter_across_tiles_enabled_flag = true;
3013 if tiles_enabled_flag {
3014 num_tile_columns_minus1 = br.read_ue().unwrap_or(0) as u8;
3015 num_tile_rows_minus1 = br.read_ue().unwrap_or(0) as u8;
3016 uniform_spacing_flag = br.read_bits(1).unwrap_or(1) == 1;
3017 if !uniform_spacing_flag {
3018 for _ in 0..num_tile_columns_minus1 {
3021 let _ = br.read_ue();
3022 }
3023 for _ in 0..num_tile_rows_minus1 {
3024 let _ = br.read_ue();
3025 }
3026 }
3027 loop_filter_across_tiles_enabled_flag = br.read_bits(1).unwrap_or(1) == 1;
3028 }
3029 let pps_loop_filter_across_slices_enabled_flag = br.read_bits(1)? == 1;
3030
3031 let deblocking_filter_control_present_flag = br.read_bits(1)? == 1;
3033 let mut deblocking_filter_override_enabled_flag = false;
3034 let mut pps_deblocking_filter_disabled_flag = false;
3035 let mut pps_beta_offset_div2 = 0i8;
3036 let mut pps_tc_offset_div2 = 0i8;
3037 if deblocking_filter_control_present_flag {
3038 deblocking_filter_override_enabled_flag = br.read_bits(1)? == 1;
3039 pps_deblocking_filter_disabled_flag = br.read_bits(1)? == 1;
3040 if !pps_deblocking_filter_disabled_flag {
3041 pps_beta_offset_div2 = clamp_to_i8(br.read_se()?);
3042 pps_tc_offset_div2 = clamp_to_i8(br.read_se()?);
3043 }
3044 }
3045
3046 let pps_scaling_list_data_present_flag = br.read_bits(1)? == 1;
3048 let lists_modification_present_flag = br.read_bits(1)? == 1;
3055 let log2_parallel_merge_level_minus2 = br.read_ue().unwrap_or(0) as u8;
3056 let slice_segment_header_extension_present_flag = br.read_bits(1)? == 1;
3057 let pps_extension_present_flag = br.read_bits(1).unwrap_or(0) == 1;
3058
3059 Some(H265PpsInfo {
3060 pps_pic_parameter_set_id,
3061 pps_seq_parameter_set_id,
3062 dependent_slice_segments_enabled_flag,
3063 output_flag_present_flag,
3064 num_extra_slice_header_bits,
3065 sign_data_hiding_enabled_flag,
3066 cabac_init_present_flag,
3067 num_ref_idx_l0_default_active_minus1,
3068 num_ref_idx_l1_default_active_minus1,
3069 init_qp_minus26,
3070 constrained_intra_pred_flag,
3071 transform_skip_enabled_flag,
3072 cu_qp_delta_enabled_flag,
3073 diff_cu_qp_delta_depth,
3074 pps_cb_qp_offset,
3075 pps_cr_qp_offset,
3076 pps_slice_chroma_qp_offsets_present_flag,
3077 weighted_pred_flag,
3078 weighted_bipred_flag,
3079 transquant_bypass_enabled_flag,
3080 tiles_enabled_flag,
3081 entropy_coding_sync_enabled_flag,
3082 num_tile_columns_minus1,
3083 num_tile_rows_minus1,
3084 uniform_spacing_flag,
3085 loop_filter_across_tiles_enabled_flag,
3086 pps_loop_filter_across_slices_enabled_flag,
3087 deblocking_filter_control_present_flag,
3088 deblocking_filter_override_enabled_flag,
3089 pps_deblocking_filter_disabled_flag,
3090 pps_beta_offset_div2,
3091 pps_tc_offset_div2,
3092 pps_scaling_list_data_present_flag,
3093 lists_modification_present_flag,
3094 log2_parallel_merge_level_minus2,
3095 slice_segment_header_extension_present_flag,
3096 pps_extension_present_flag,
3097 })
3098}
3099
3100pub fn parse_h265_slice_header(
3104 sample: &[u8],
3105 sps: &HevcSpsInfo,
3106 pps: &H265PpsInfo,
3107) -> Option<H265SliceHeader> {
3108 let (nal_unit_type, rbsp) = find_hevc_slice_nal(sample)?;
3109 let mut br = BitReader::new(&rbsp);
3110 let first_slice_segment_in_pic_flag = br.read_bits(1)? == 1;
3111 let is_irap = (16..=23).contains(&nal_unit_type);
3112 let is_idr = matches!(nal_unit_type, 19 | 20);
3113 if is_irap {
3114 let _no_output_of_prior_pics_flag = br.read_bits(1)?;
3115 }
3116 let slice_pic_parameter_set_id = br.read_ue()? as u8;
3117 let dependent_slice_segment_flag =
3118 if !first_slice_segment_in_pic_flag && pps.dependent_slice_segments_enabled_flag {
3119 br.read_bits(1)? == 1
3120 } else {
3121 false
3122 };
3123 if !first_slice_segment_in_pic_flag {
3124 return None;
3131 }
3132 let _ = dependent_slice_segment_flag;
3133 for _ in 0..pps.num_extra_slice_header_bits {
3135 let _ = br.read_bits(1)?;
3136 }
3137 let slice_type_code = br.read_ue()?;
3138 let slice_type = H265SliceType::from_ue(slice_type_code)?;
3139 if pps.output_flag_present_flag {
3140 let _pic_output_flag = br.read_bits(1)?;
3141 }
3142 if sps.separate_colour_plane_flag {
3143 let _colour_plane_id = br.read_bits(2)?;
3144 }
3145
3146 let (pic_order_cnt_lsb, short_term_ref_pic_set_sps_flag, short_term_ref_pic_set_idx) =
3147 if !is_idr {
3148 let lsb_bits = (sps.log2_max_pic_order_cnt_lsb_minus4 as usize) + 4;
3149 let lsb = br.read_bits(lsb_bits)?;
3150 let sps_flag = br.read_bits(1)? == 1;
3151 let idx = if sps_flag {
3152 if sps.num_short_term_ref_pic_sets > 1 {
3153 let bits =
3154 ((sps.num_short_term_ref_pic_sets as f64).log2().ceil() as usize).max(1);
3155 Some(br.read_bits(bits)? as u8)
3156 } else {
3157 Some(0)
3158 }
3159 } else {
3160 None
3161 };
3162 (lsb, sps_flag, idx)
3163 } else {
3164 (0, false, None)
3165 };
3166
3167 Some(H265SliceHeader {
3168 first_slice_segment_in_pic_flag,
3169 nal_unit_type,
3170 slice_pic_parameter_set_id,
3171 slice_type,
3172 pic_order_cnt_lsb,
3173 short_term_ref_pic_set_sps_flag,
3174 short_term_ref_pic_set_idx,
3175 is_irap,
3176 is_idr,
3177 })
3178}
3179
3180fn find_hevc_nal_by_type(data: &[u8], target: u8) -> Option<&[u8]> {
3182 let mut i = 0;
3183 while i + 4 < data.len() {
3184 let (start_len, nal_byte) = if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 {
3185 (3, i + 3)
3186 } else if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 1 {
3187 (4, i + 4)
3188 } else {
3189 i += 1;
3190 continue;
3191 };
3192 if nal_byte + 1 >= data.len() {
3193 return None;
3194 }
3195 let nal_unit_type = (data[nal_byte] >> 1) & 0x3F;
3196 if nal_unit_type == target {
3197 let start = nal_byte + 2; let end = find_next_start_code(&data[start..])
3199 .map(|off| start + off)
3200 .unwrap_or(data.len());
3201 return Some(&data[start..end]);
3202 }
3203 i += start_len;
3204 }
3205 None
3206}
3207
3208pub fn hevc_first_slice_nal_offset(data: &[u8]) -> Option<u32> {
3213 let mut i = 0;
3214 while i + 4 < data.len() {
3215 let (start_len, nal_byte) = if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 {
3216 (3usize, i + 3)
3217 } else if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 1 {
3218 (4usize, i + 4)
3219 } else {
3220 i += 1;
3221 continue;
3222 };
3223 if nal_byte + 1 >= data.len() {
3224 return None;
3225 }
3226 let t = (data[nal_byte] >> 1) & 0x3F;
3227 if (0..=9).contains(&t) || (16..=23).contains(&t) {
3228 return Some(nal_byte as u32);
3229 }
3230 i += start_len;
3231 }
3232 None
3233}
3234
3235pub fn h264_first_slice_nal_offset(data: &[u8]) -> Option<u32> {
3239 let mut i = 0;
3240 while i + 4 < data.len() {
3241 let (start_len, nal_byte) = if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 {
3242 (3usize, i + 3)
3243 } else if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 1 {
3244 (4usize, i + 4)
3245 } else {
3246 i += 1;
3247 continue;
3248 };
3249 if nal_byte >= data.len() {
3250 return None;
3251 }
3252 let t = data[nal_byte] & 0x1F;
3253 if matches!(t, 1 | 5 | 19) {
3254 return Some(nal_byte as u32);
3255 }
3256 i += start_len;
3257 }
3258 None
3259}
3260
3261fn find_hevc_slice_nal(data: &[u8]) -> Option<(u8, Vec<u8>)> {
3264 let mut i = 0;
3265 while i + 4 < data.len() {
3266 let (start_len, nal_byte) = if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 {
3267 (3, i + 3)
3268 } else if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 1 {
3269 (4, i + 4)
3270 } else {
3271 i += 1;
3272 continue;
3273 };
3274 if nal_byte + 1 >= data.len() {
3275 return None;
3276 }
3277 let t = (data[nal_byte] >> 1) & 0x3F;
3278 if (0..=9).contains(&t) || (16..=23).contains(&t) {
3279 let start = nal_byte + 2;
3280 let end = find_next_start_code(&data[start..])
3281 .map(|off| start + off)
3282 .unwrap_or(data.len());
3283 return Some((t, remove_h264_rbsp_stuffing(&data[start..end])));
3284 }
3285 i += start_len;
3286 }
3287 None
3288}
3289
3290pub fn parse_mpeg2_sequence_header(sample: &[u8]) -> Option<Mpeg2SeqInfo> {
3300 let seq_hdr_start = find_mpeg2_start_code(sample, 0xB3)?;
3303 let hdr_body_off = seq_hdr_start + 4;
3304 if hdr_body_off + 3 > sample.len() {
3305 return None;
3306 }
3307 let b = &sample[hdr_body_off..hdr_body_off + 3];
3308 let mut width = (((b[0] as u32) << 4) | ((b[1] as u32) >> 4)) & 0x0FFF;
3309 let mut height = (((b[1] as u32 & 0x0F) << 8) | (b[2] as u32)) & 0x0FFF;
3310
3311 let search_from = hdr_body_off + 3;
3316 if search_from < sample.len()
3317 && let Some(ext_start) = find_mpeg2_start_code(&sample[search_from..], 0xB5)
3318 {
3319 let ext_body_off = search_from + ext_start + 4;
3320 if ext_body_off + 3 <= sample.len() {
3321 let mut br = BitReader::new(&sample[ext_body_off..]);
3322 if let Some(id) = br.read_bits(4)
3323 && id == 1
3324 {
3325 let _profile_level = br.read_bits(8)?;
3333 let _progressive = br.read_bits(1)?;
3334 let _chroma = br.read_bits(2)?;
3335 let h_ext = br.read_bits(2)?;
3336 let v_ext = br.read_bits(2)?;
3337 width |= h_ext << 12;
3338 height |= v_ext << 12;
3339 }
3340 }
3341 }
3342
3343 if width == 0 || height == 0 {
3344 return None;
3345 }
3346 Some(Mpeg2SeqInfo { width, height })
3347}
3348
3349fn find_mpeg2_start_code(data: &[u8], target: u8) -> Option<usize> {
3352 let mut i = 0;
3353 while i + 4 <= data.len() {
3354 if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 && data[i + 3] == target {
3355 return Some(i);
3356 }
3357 i += 1;
3358 }
3359 None
3360}
3361
3362#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3375pub struct H264PpsInfo {
3376 pub pic_parameter_set_id: u8,
3377 pub seq_parameter_set_id: u8,
3378 pub entropy_coding_mode_flag: bool,
3379 pub bottom_field_pic_order_in_frame_present_flag: bool,
3383 pub num_slice_groups_minus1: u8,
3384 pub num_ref_idx_l0_default_active_minus1: u8,
3385 pub num_ref_idx_l1_default_active_minus1: u8,
3386 pub weighted_pred_flag: bool,
3387 pub weighted_bipred_idc: u8,
3388 pub pic_init_qp_minus26: i8,
3389 pub pic_init_qs_minus26: i8,
3390 pub chroma_qp_index_offset: i8,
3391 pub deblocking_filter_control_present_flag: bool,
3392 pub constrained_intra_pred_flag: bool,
3393 pub redundant_pic_cnt_present_flag: bool,
3394 pub transform_8x8_mode_flag: Option<bool>,
3398 pub pic_scaling_matrix_present_flag: Option<bool>,
3399 pub second_chroma_qp_index_offset: Option<i8>,
3400}
3401
3402pub fn parse_h264_pps(sample: &[u8]) -> Option<H264PpsInfo> {
3413 let pps = find_h264_nal_by_type(sample, 8)?;
3414 let rbsp = remove_h264_rbsp_stuffing(pps);
3415 let mut br = BitReader::new(&rbsp);
3416
3417 let pic_parameter_set_id = br.read_ue()? as u8;
3418 let seq_parameter_set_id = br.read_ue()? as u8;
3419 let entropy_coding_mode_flag = br.read_bits(1)? == 1;
3420 let bottom_field_pic_order_in_frame_present_flag = br.read_bits(1)? == 1;
3421
3422 let num_slice_groups_minus1 = br.read_ue()?;
3423 if num_slice_groups_minus1 > 0 {
3424 let slice_group_map_type = br.read_ue()?;
3426 match slice_group_map_type {
3427 0 => {
3428 for _ in 0..=num_slice_groups_minus1 {
3429 let _run_length_minus1 = br.read_ue()?;
3430 }
3431 }
3432 2 => {
3433 for _ in 0..num_slice_groups_minus1 {
3434 let _top_left = br.read_ue()?;
3435 let _bottom_right = br.read_ue()?;
3436 }
3437 }
3438 3..=5 => {
3439 let _slice_group_change_direction_flag = br.read_bits(1)?;
3440 let _slice_group_change_rate_minus1 = br.read_ue()?;
3441 }
3442 6 => {
3443 let pic_size_in_map_units_minus1 = br.read_ue()?;
3444 let bits = ((num_slice_groups_minus1 + 1) as f64).log2().ceil() as usize;
3445 let bits = bits.max(1);
3446 for _ in 0..=pic_size_in_map_units_minus1 {
3447 let _slice_group_id = br.read_bits(bits)?;
3448 }
3449 }
3450 _ => {}
3451 }
3452 }
3453
3454 let num_ref_idx_l0_default_active_minus1 = br.read_ue()? as u8;
3455 let num_ref_idx_l1_default_active_minus1 = br.read_ue()? as u8;
3456 let weighted_pred_flag = br.read_bits(1)? == 1;
3457 let weighted_bipred_idc = br.read_bits(2)? as u8;
3458 let pic_init_qp_minus26 = clamp_to_i8(br.read_se()?);
3459 let pic_init_qs_minus26 = clamp_to_i8(br.read_se()?);
3460 let chroma_qp_index_offset = clamp_to_i8(br.read_se()?);
3461 let deblocking_filter_control_present_flag = br.read_bits(1)? == 1;
3462 let constrained_intra_pred_flag = br.read_bits(1)? == 1;
3463 let redundant_pic_cnt_present_flag = br.read_bits(1)? == 1;
3464
3465 let (transform_8x8_mode_flag, pic_scaling_matrix_present_flag, second_chroma_qp_index_offset) =
3471 if more_rbsp_data(&br, &rbsp) {
3472 let t8 = br.read_bits(1).map(|v| v == 1);
3473 let psm = br.read_bits(1).map(|v| v == 1);
3474 if let Some(true) = psm {
3478 let count = 6 + if let Some(true) = t8 { 2 } else { 0 };
3483 for i in 0..count {
3484 if br.read_bits(1) == Some(1) {
3485 let size = if i < 6 { 16 } else { 64 };
3486 let mut last_scale: i32 = 8;
3487 let mut next_scale: i32 = 8;
3488 for _ in 0..size {
3489 if next_scale != 0 {
3490 let delta = br.read_se().unwrap_or(0);
3491 next_scale = (last_scale + delta + 256).rem_euclid(256);
3492 }
3493 if next_scale != 0 {
3494 last_scale = next_scale;
3495 }
3496 }
3497 }
3498 }
3499 }
3500 let s2 = br.read_se().map(clamp_to_i8);
3501 (t8, psm, s2)
3502 } else {
3503 (None, None, None)
3504 };
3505
3506 Some(H264PpsInfo {
3507 pic_parameter_set_id,
3508 seq_parameter_set_id,
3509 entropy_coding_mode_flag,
3510 bottom_field_pic_order_in_frame_present_flag,
3511 num_slice_groups_minus1: num_slice_groups_minus1.min(u8::MAX as u32) as u8,
3512 num_ref_idx_l0_default_active_minus1,
3513 num_ref_idx_l1_default_active_minus1,
3514 weighted_pred_flag,
3515 weighted_bipred_idc,
3516 pic_init_qp_minus26,
3517 pic_init_qs_minus26,
3518 chroma_qp_index_offset,
3519 deblocking_filter_control_present_flag,
3520 constrained_intra_pred_flag,
3521 redundant_pic_cnt_present_flag,
3522 transform_8x8_mode_flag,
3523 pic_scaling_matrix_present_flag,
3524 second_chroma_qp_index_offset,
3525 })
3526}
3527
3528fn more_rbsp_data(br: &BitReader, rbsp: &[u8]) -> bool {
3536 let pos = br.pos;
3537 let total_bits = rbsp.len() * 8;
3538 total_bits.saturating_sub(pos) > 8
3541}
3542
3543fn clamp_to_i8(v: i32) -> i8 {
3544 v.clamp(i8::MIN as i32, i8::MAX as i32) as i8
3545}
3546
3547#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3553pub enum H264SliceType {
3554 P,
3555 B,
3556 I,
3557 SP,
3558 SI,
3559}
3560
3561impl H264SliceType {
3562 fn from_ue(v: u32) -> Option<Self> {
3563 match v % 5 {
3564 0 => Some(Self::P),
3565 1 => Some(Self::B),
3566 2 => Some(Self::I),
3567 3 => Some(Self::SP),
3568 4 => Some(Self::SI),
3569 _ => None,
3570 }
3571 }
3572}
3573
3574#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3581pub struct H264SliceHeader {
3582 pub first_mb_in_slice: u32,
3583 pub slice_type: H264SliceType,
3584 pub pic_parameter_set_id: u8,
3585 pub is_idr: bool,
3589 pub frame_num: u32,
3590 pub field_pic_flag: bool,
3594 pub bottom_field_flag: bool,
3595 pub colour_plane_id: Option<u8>,
3596 pub idr_pic_id: Option<u32>,
3598 pub pic_order_cnt_lsb: Option<u32>,
3600 pub delta_pic_order_cnt_bottom: Option<i32>,
3601 pub delta_pic_order_cnt: [Option<i32>; 2],
3607}
3608
3609pub fn parse_h264_slice_header(
3617 sample: &[u8],
3618 sps: &H264SpsInfo,
3619 pps: &H264PpsInfo,
3620) -> Option<H264SliceHeader> {
3621 let (nal_type, rbsp) = find_h264_slice_nal(sample)?;
3625 let is_idr = nal_type == 5;
3626
3627 let mut br = BitReader::new(&rbsp);
3628 let first_mb_in_slice = br.read_ue()?;
3629 let slice_type_code = br.read_ue()?;
3630 let slice_type = H264SliceType::from_ue(slice_type_code)?;
3631 let pic_parameter_set_id = br.read_ue()? as u8;
3632
3633 let colour_plane_id = if sps.separate_colour_plane_flag {
3634 Some(br.read_bits(2)? as u8)
3635 } else {
3636 None
3637 };
3638
3639 let frame_num_bits = (sps.log2_max_frame_num_minus4? as usize) + 4;
3640 let frame_num = br.read_bits(frame_num_bits)?;
3641
3642 let (field_pic_flag, bottom_field_flag) = if !sps.frame_mbs_only {
3643 let f = br.read_bits(1)? == 1;
3644 let b = if f { br.read_bits(1)? == 1 } else { false };
3645 (f, b)
3646 } else {
3647 (false, false)
3648 };
3649
3650 let idr_pic_id = if is_idr { Some(br.read_ue()?) } else { None };
3651
3652 let poc_type = sps.pic_order_cnt_type?;
3653 let mut pic_order_cnt_lsb = None;
3654 let mut delta_pic_order_cnt_bottom = None;
3655 let mut delta_pic_order_cnt: [Option<i32>; 2] = [None, None];
3656 match poc_type {
3657 0 => {
3658 let bits = (sps.log2_max_pic_order_cnt_lsb_minus4? as usize) + 4;
3659 pic_order_cnt_lsb = Some(br.read_bits(bits)?);
3660 if pps.bottom_field_pic_order_in_frame_present_flag && !field_pic_flag {
3661 delta_pic_order_cnt_bottom = Some(br.read_se()?);
3662 }
3663 }
3664 1 => {
3665 let always_zero = sps.delta_pic_order_always_zero_flag.unwrap_or(false);
3666 if !always_zero {
3667 delta_pic_order_cnt[0] = Some(br.read_se()?);
3668 if pps.bottom_field_pic_order_in_frame_present_flag && !field_pic_flag {
3669 delta_pic_order_cnt[1] = Some(br.read_se()?);
3670 }
3671 }
3672 }
3673 2 => { }
3674 _ => return None,
3675 }
3676
3677 Some(H264SliceHeader {
3678 first_mb_in_slice,
3679 slice_type,
3680 pic_parameter_set_id,
3681 is_idr,
3682 frame_num,
3683 field_pic_flag,
3684 bottom_field_flag,
3685 colour_plane_id,
3686 idr_pic_id,
3687 pic_order_cnt_lsb,
3688 delta_pic_order_cnt_bottom,
3689 delta_pic_order_cnt,
3690 })
3691}
3692
3693fn find_h264_slice_nal(data: &[u8]) -> Option<(u8, Vec<u8>)> {
3696 let mut i = 0;
3697 while i + 4 < data.len() {
3698 let (start_len, nal_byte) = if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 {
3699 (3, i + 3)
3700 } else if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 1 {
3701 (4, i + 4)
3702 } else {
3703 i += 1;
3704 continue;
3705 };
3706 if nal_byte >= data.len() {
3707 return None;
3708 }
3709 let nal_unit_type = data[nal_byte] & 0x1F;
3710 if matches!(nal_unit_type, 1 | 5 | 19) {
3711 let start = nal_byte + 1;
3712 let end = find_next_start_code(&data[start..])
3713 .map(|off| start + off)
3714 .unwrap_or(data.len());
3715 let rbsp = remove_h264_rbsp_stuffing(&data[start..end]);
3716 return Some((nal_unit_type, rbsp));
3717 }
3718 i += start_len;
3719 }
3720 None
3721}
3722
3723fn find_h264_nal_by_type(data: &[u8], target_type: u8) -> Option<&[u8]> {
3727 let mut i = 0;
3728 while i + 4 < data.len() {
3729 let (start_len, nal_byte) = if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 {
3730 (3, i + 3)
3731 } else if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 1 {
3732 (4, i + 4)
3733 } else {
3734 i += 1;
3735 continue;
3736 };
3737 if nal_byte >= data.len() {
3738 return None;
3739 }
3740 let nal_unit_type = data[nal_byte] & 0x1F;
3741 if nal_unit_type == target_type {
3742 let start = nal_byte + 1;
3743 let end = find_next_start_code(&data[start..])
3744 .map(|off| start + off)
3745 .unwrap_or(data.len());
3746 return Some(&data[start..end]);
3747 }
3748 i += start_len;
3749 }
3750 None
3751}
3752
3753#[cfg(test)]
3754mod tests {
3755 use super::*;
3756
3757 #[test]
3758 fn detects_h264_baseline_yuv420p() {
3759 let sps_rbsp = vec![
3761 66, 0, 30, 0b1000_0000,
3766 ];
3767 let mut sample = vec![0, 0, 0, 1, 0x27]; sample.extend_from_slice(&sps_rbsp);
3769 let pf = detect_h264(&sample).unwrap();
3770 assert_eq!(pf, PixelFormat::Yuv420p);
3771 }
3772
3773 #[test]
3774 fn empty_samples_returns_default() {
3775 let pf = detect("h264", &[]);
3776 assert_eq!(pf, PixelFormat::Yuv420p);
3777 }
3778
3779 #[test]
3780 fn unknown_codec_returns_default() {
3781 let pf = detect("prores", &[vec![1, 2, 3]]);
3782 assert_eq!(pf, PixelFormat::Yuv420p);
3783 }
3784
3785 #[test]
3786 fn from_chroma_and_depth_420_8bit() {
3787 assert_eq!(
3788 PixelFormat::from_chroma_and_depth(1, 8),
3789 PixelFormat::Yuv420p
3790 );
3791 assert_eq!(
3792 PixelFormat::from_chroma_and_depth(1, 10),
3793 PixelFormat::Yuv420p10le
3794 );
3795 assert_eq!(
3796 PixelFormat::from_chroma_and_depth(2, 8),
3797 PixelFormat::Yuv422p
3798 );
3799 assert_eq!(
3800 PixelFormat::from_chroma_and_depth(3, 8),
3801 PixelFormat::Yuv444p
3802 );
3803 }
3804
3805 #[test]
3806 fn as_ffmpeg_str_matches_python_names() {
3807 assert_eq!(PixelFormat::Yuv420p.as_ffmpeg_str(), "yuv420p");
3808 assert_eq!(PixelFormat::Yuv420p10le.as_ffmpeg_str(), "yuv420p10le");
3809 assert_eq!(PixelFormat::Yuv444p.as_ffmpeg_str(), "yuv444p");
3810 }
3811
3812 struct BitWriter {
3822 bytes: Vec<u8>,
3823 bit_pos: usize, }
3825
3826 impl BitWriter {
3827 fn new() -> Self {
3828 Self {
3829 bytes: Vec::new(),
3830 bit_pos: 8,
3831 }
3832 }
3833 fn write_bit(&mut self, b: u8) {
3834 if self.bit_pos == 8 {
3835 self.bytes.push(0);
3836 self.bit_pos = 0;
3837 }
3838 if b != 0 {
3839 let idx = self.bytes.len() - 1;
3840 self.bytes[idx] |= 1 << (7 - self.bit_pos);
3841 }
3842 self.bit_pos += 1;
3843 }
3844 fn write_bits(&mut self, val: u64, n: usize) {
3845 for i in 0..n {
3849 let bit = ((val >> (n - 1 - i)) & 1) as u8;
3850 self.write_bit(bit);
3851 }
3852 }
3853 fn write_ue(&mut self, v: u32) {
3854 let z = if v == 0 { 0 } else { (v + 1).ilog2() as usize };
3855 for _ in 0..z {
3856 self.write_bit(0);
3857 }
3858 self.write_bit(1);
3859 if z > 0 {
3860 let suffix = (v + 1) - (1u32 << z);
3861 self.write_bits(suffix as u64, z);
3862 }
3863 }
3864 fn bytes(self) -> Vec<u8> {
3865 self.bytes
3866 }
3867 }
3868
3869 fn build_h264_baseline_sps(width_in_mbs: u32, height_in_mbs: u32) -> Vec<u8> {
3877 let mut w = BitWriter::new();
3878 w.write_bits(66, 8); w.write_bits(0, 8); w.write_bits(30, 8); w.write_ue(0); w.write_ue(0); w.write_ue(0); w.write_ue(0); w.write_ue(1); w.write_bit(0); w.write_ue(width_in_mbs - 1); w.write_ue(height_in_mbs - 1); w.write_bit(1); w.write_bit(1); w.write_bit(0); w.write_bit(0); w.write_bit(1); let mut sample = vec![0x00, 0x00, 0x00, 0x01, 0x67]; sample.extend_from_slice(&w.bytes());
3897 sample
3898 }
3899
3900 #[test]
3901 fn parse_h264_sps_baseline_1280x720() {
3902 let sample = build_h264_baseline_sps(1280 / 16, 720 / 16);
3903 let info = parse_h264_sps(&sample).expect("parse");
3904 assert_eq!(info.profile_idc, 66);
3905 assert_eq!(info.chroma_format_idc, 1); assert_eq!(info.width, Some(1280));
3907 assert_eq!(info.height, Some(720));
3908 assert!(info.frame_mbs_only);
3909 }
3910
3911 #[test]
3912 fn parse_h264_sps_baseline_640x480() {
3913 let sample = build_h264_baseline_sps(640 / 16, 480 / 16);
3914 let info = parse_h264_sps(&sample).expect("parse");
3915 assert_eq!(info.width, Some(640));
3916 assert_eq!(info.height, Some(480));
3917 }
3918
3919 #[test]
3920 fn parse_h264_sps_with_cropping_1920x1080() {
3921 let mut w = BitWriter::new();
3924 w.write_bits(66, 8);
3925 w.write_bits(0, 8);
3926 w.write_bits(40, 8);
3927 w.write_ue(0);
3928 w.write_ue(0);
3929 w.write_ue(0);
3930 w.write_ue(0);
3931 w.write_ue(1);
3932 w.write_bit(0);
3933 w.write_ue(1920 / 16 - 1); w.write_ue(1088 / 16 - 1); w.write_bit(1); w.write_bit(1); w.write_bit(1); w.write_ue(0); w.write_ue(0); w.write_ue(0); w.write_ue(4); w.write_bit(0); w.write_bit(1); let mut sample = vec![0, 0, 0, 1, 0x67];
3945 sample.extend_from_slice(&w.bytes());
3946 let info = parse_h264_sps(&sample).expect("parse");
3947 assert_eq!(info.width, Some(1920));
3948 assert_eq!(info.height, Some(1080));
3949 }
3950
3951 #[test]
3952 fn parse_h264_sps_high_profile_422_returns_chroma_even_without_dims() {
3953 let mut w = BitWriter::new();
3959 w.write_bits(122, 8); w.write_bits(0, 8);
3961 w.write_bits(40, 8);
3962 w.write_ue(0); w.write_ue(2); w.write_ue(0); w.write_ue(0); w.write_bit(0); w.write_bit(0); let mut sample = vec![0, 0, 0, 1, 0x67];
3971 sample.extend_from_slice(&w.bytes());
3972 let info = parse_h264_sps(&sample).expect("parse");
3973 assert_eq!(info.profile_idc, 122);
3974 assert_eq!(info.chroma_format_idc, 2);
3975 }
3977
3978 fn build_hevc_sps(pic_width: u32, pic_height: u32) -> Vec<u8> {
3983 build_hevc_sps_full(pic_width, pic_height, false, 0, 0, 0, 0)
3984 }
3985
3986 fn build_hevc_sps_full(
3987 pic_width: u32,
3988 pic_height: u32,
3989 conformance_window: bool,
3990 cwl: u32,
3991 cwr: u32,
3992 cwt: u32,
3993 cwb: u32,
3994 ) -> Vec<u8> {
3995 let mut w = BitWriter::new();
3996 w.write_bits(0, 4); w.write_bits(0, 3); w.write_bits(1, 1); w.write_bits(0b0_0_00001, 8); w.write_bits(0x40000000, 32); w.write_bits(0, 48); w.write_bits(93, 8); w.write_ue(0); w.write_ue(1); w.write_ue(pic_width);
4007 w.write_ue(pic_height);
4008 if conformance_window {
4009 w.write_bit(1);
4010 w.write_ue(cwl);
4011 w.write_ue(cwr);
4012 w.write_ue(cwt);
4013 w.write_ue(cwb);
4014 } else {
4015 w.write_bit(0); }
4017 w.write_ue(0); w.write_ue(0); w.write_ue(4); w.write_bit(1); w.write_ue(4); w.write_ue(0); w.write_ue(0); w.write_ue(0); w.write_ue(3); w.write_ue(0); w.write_ue(3); w.write_ue(2); w.write_ue(2); w.write_bit(0); w.write_bit(1); w.write_bit(1); w.write_bit(0); w.write_ue(0); w.write_bit(0); w.write_bit(1); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(1); let mut sample = vec![0, 0, 0, 1, 0x42, 0x01];
4043 sample.extend_from_slice(&w.bytes());
4044 sample
4045 }
4046
4047 #[test]
4048 fn parse_hevc_sps_1920x1080_no_crop() {
4049 let sample = build_hevc_sps(1920, 1080);
4050 let info = parse_hevc_sps(&sample).expect("parse");
4051 assert_eq!(info.chroma_format_idc, 1);
4052 assert_eq!(info.bit_depth_luma, 8);
4053 assert_eq!(info.width, Some(1920));
4054 assert_eq!(info.height, Some(1080));
4055 }
4056
4057 #[test]
4058 fn parse_hevc_sps_with_conformance_window() {
4059 let sample = build_hevc_sps_full(1920, 1088, true, 0, 0, 0, 4);
4062 let info = parse_hevc_sps(&sample).expect("parse");
4063 assert_eq!(info.width, Some(1920));
4064 assert_eq!(info.height, Some(1080));
4065 }
4066
4067 #[test]
4068 fn parse_mpeg2_sequence_header_no_extension_640x480() {
4069 let sample = vec![0x00, 0x00, 0x01, 0xB3, 0x28, 0x01, 0xE0, 0x13, 0xFF, 0xFF];
4073 let info = parse_mpeg2_sequence_header(&sample).expect("parse");
4074 assert_eq!(info.width, 640);
4075 assert_eq!(info.height, 480);
4076 }
4077
4078 #[test]
4079 fn parse_mpeg2_sequence_header_with_extension_upgrades_to_14bit() {
4080 let mut bytes = vec![0x00, 0x00, 0x01, 0xB3, 0x78, 0x04, 0x38, 0x13, 0xFF, 0xFF];
4087 let mut w = BitWriter::new();
4093 w.write_bits(1, 4); w.write_bits(0, 8); w.write_bit(1); w.write_bits(1, 2); w.write_bits(1, 2); w.write_bits(2, 2); w.write_bits(0, 1); bytes.extend_from_slice(&[0x00, 0x00, 0x01, 0xB5]);
4101 bytes.extend_from_slice(&w.bytes());
4102 let info = parse_mpeg2_sequence_header(&bytes).expect("parse");
4103 assert_eq!(info.width, 1920 | (1 << 12)); assert_eq!(info.height, 1080 | (2 << 12)); }
4106
4107 #[test]
4108 fn parse_mpeg2_sequence_header_none_when_no_start_code() {
4109 let sample = vec![0xFFu8; 128];
4110 assert!(parse_mpeg2_sequence_header(&sample).is_none());
4111 }
4112
4113 #[test]
4114 fn detect_dims_dispatches_by_codec() {
4115 let h264 = build_h264_baseline_sps(1280 / 16, 720 / 16);
4116 let hevc = build_hevc_sps(1920, 1080);
4117 let mpeg2 = vec![0x00, 0x00, 0x01, 0xB3, 0x28, 0x01, 0xE0, 0x13, 0xFF, 0xFF];
4118 assert_eq!(detect_dims("h264", &[h264.clone()]), Some((1280, 720)));
4119 assert_eq!(detect_dims("avc1", &[h264]), Some((1280, 720)));
4120 assert_eq!(detect_dims("h265", &[hevc.clone()]), Some((1920, 1080)));
4121 assert_eq!(detect_dims("hevc", &[hevc]), Some((1920, 1080)));
4122 assert_eq!(detect_dims("mpeg2", &[mpeg2]), Some((640, 480)));
4123 assert_eq!(detect_dims("unknown", &[vec![0u8; 8]]), None);
4124 assert_eq!(detect_dims("h264", &[]), None);
4125 }
4126
4127 fn build_h264_baseline_pps(pps_id: u32, sps_id: u32) -> Vec<u8> {
4131 let mut w = BitWriter::new();
4132 w.write_ue(pps_id); w.write_ue(sps_id); w.write_bit(0); w.write_bit(0); w.write_ue(0); w.write_ue(0); w.write_ue(0); w.write_bit(0); w.write_bits(0, 2); w.write_ue(0); w.write_ue(0); w.write_ue(0); w.write_bit(1); w.write_bit(0); w.write_bit(0); w.write_bit(1); let mut sample = vec![0x00, 0x00, 0x00, 0x01, 0x68]; sample.extend_from_slice(&w.bytes());
4150 sample
4151 }
4152
4153 #[test]
4154 fn parse_h264_pps_baseline_roundtrip() {
4155 let sample = build_h264_baseline_pps(0, 0);
4156 let info = parse_h264_pps(&sample).expect("PPS parses");
4157 assert_eq!(info.pic_parameter_set_id, 0);
4158 assert_eq!(info.seq_parameter_set_id, 0);
4159 assert!(!info.entropy_coding_mode_flag);
4160 assert!(!info.bottom_field_pic_order_in_frame_present_flag);
4161 assert_eq!(info.num_slice_groups_minus1, 0);
4162 assert_eq!(info.num_ref_idx_l0_default_active_minus1, 0);
4163 assert_eq!(info.num_ref_idx_l1_default_active_minus1, 0);
4164 assert!(!info.weighted_pred_flag);
4165 assert_eq!(info.weighted_bipred_idc, 0);
4166 assert_eq!(info.pic_init_qp_minus26, 0);
4167 assert_eq!(info.pic_init_qs_minus26, 0);
4168 assert_eq!(info.chroma_qp_index_offset, 0);
4169 assert!(info.deblocking_filter_control_present_flag);
4170 assert!(!info.constrained_intra_pred_flag);
4171 assert!(!info.redundant_pic_cnt_present_flag);
4172 }
4173
4174 #[test]
4175 fn parse_h264_pps_nonzero_ids_and_flags() {
4176 let mut w = BitWriter::new();
4177 w.write_ue(3); w.write_ue(7); w.write_bit(1); w.write_bit(1); w.write_ue(0); w.write_ue(2); w.write_ue(1); w.write_bit(1); w.write_bits(2, 2); w.write_ue(10);
4188 w.write_ue(5);
4190 w.write_ue(0);
4192 w.write_bit(0); w.write_bit(1); w.write_bit(1); w.write_bit(1); let mut sample = vec![0x00, 0x00, 0x00, 0x01, 0x68];
4197 sample.extend_from_slice(&w.bytes());
4198 let info = parse_h264_pps(&sample).expect("parse");
4199 assert_eq!(info.pic_parameter_set_id, 3);
4200 assert_eq!(info.seq_parameter_set_id, 7);
4201 assert!(info.entropy_coding_mode_flag);
4202 assert!(info.bottom_field_pic_order_in_frame_present_flag);
4203 assert_eq!(info.num_ref_idx_l0_default_active_minus1, 2);
4204 assert_eq!(info.num_ref_idx_l1_default_active_minus1, 1);
4205 assert!(info.weighted_pred_flag);
4206 assert_eq!(info.weighted_bipred_idc, 2);
4207 assert_eq!(info.pic_init_qp_minus26, -5);
4208 assert_eq!(info.pic_init_qs_minus26, 3);
4209 assert!(!info.deblocking_filter_control_present_flag);
4210 assert!(info.constrained_intra_pred_flag);
4211 assert!(info.redundant_pic_cnt_present_flag);
4212 }
4213
4214 #[test]
4215 fn parse_h264_pps_returns_none_when_no_pps_in_sample() {
4216 let sample = build_h264_baseline_sps(80, 45); assert!(parse_h264_pps(&sample).is_none());
4219 }
4220
4221 fn build_h264_idr_slice_header_rbsp() -> Vec<u8> {
4229 let mut w = BitWriter::new();
4230 w.write_ue(0); w.write_ue(7); w.write_ue(0); w.write_bits(0, 4); w.write_ue(0); w.write_bits(0, 4); w.bytes()
4239 }
4240
4241 #[test]
4242 fn parse_h264_slice_header_idr_i_slice() {
4243 let sps = parse_h264_sps(&build_h264_baseline_sps(1280 / 16, 720 / 16)).expect("sps");
4244 let pps = parse_h264_pps(&build_h264_baseline_pps(0, 0)).expect("pps");
4245 let rbsp = build_h264_idr_slice_header_rbsp();
4246 let mut sample = vec![0x00, 0x00, 0x00, 0x01, 0x65];
4248 sample.extend_from_slice(&rbsp);
4249
4250 let sh = parse_h264_slice_header(&sample, &sps, &pps).expect("slice");
4251 assert_eq!(sh.first_mb_in_slice, 0);
4252 assert_eq!(sh.slice_type, H264SliceType::I);
4253 assert_eq!(sh.pic_parameter_set_id, 0);
4254 assert!(sh.is_idr);
4255 assert_eq!(sh.frame_num, 0);
4256 assert!(!sh.field_pic_flag);
4257 assert_eq!(sh.idr_pic_id, Some(0));
4258 assert_eq!(sh.pic_order_cnt_lsb, Some(0));
4259 }
4260
4261 #[test]
4262 fn parse_h264_slice_header_returns_none_without_sps_context() {
4263 let mut w = BitWriter::new();
4268 w.write_bits(122, 8);
4269 w.write_bits(0, 8);
4270 w.write_bits(40, 8);
4271 w.write_ue(0); w.write_ue(2); w.write_ue(0);
4274 w.write_ue(0);
4275 w.write_bit(0); w.write_bit(0); let mut sample = vec![0, 0, 0, 1, 0x67];
4278 sample.extend_from_slice(&w.bytes());
4279 let sps = parse_h264_sps(&sample).expect("sps parses");
4280 assert!(sps.pic_order_cnt_type.is_none());
4281
4282 let pps = parse_h264_pps(&build_h264_baseline_pps(0, 0)).expect("pps");
4283 let rbsp = build_h264_idr_slice_header_rbsp();
4284 let mut slice_sample = vec![0x00, 0x00, 0x00, 0x01, 0x65];
4285 slice_sample.extend_from_slice(&rbsp);
4286 assert!(parse_h264_slice_header(&slice_sample, &sps, &pps).is_none());
4290 }
4291
4292 #[test]
4293 fn parse_h264_slice_type_ue_mapping_covers_both_halves() {
4294 for (code, expected) in [
4297 (0, H264SliceType::P),
4298 (5, H264SliceType::P),
4299 (1, H264SliceType::B),
4300 (6, H264SliceType::B),
4301 (2, H264SliceType::I),
4302 (7, H264SliceType::I),
4303 (3, H264SliceType::SP),
4304 (8, H264SliceType::SP),
4305 (4, H264SliceType::SI),
4306 (9, H264SliceType::SI),
4307 ] {
4308 assert_eq!(
4309 H264SliceType::from_ue(code),
4310 Some(expected),
4311 "code {}",
4312 code
4313 );
4314 }
4315 }
4316
4317 #[test]
4318 fn bit_reader_read_se_exp_golomb_mapping() {
4319 for (code, expected) in [(0u32, 0i32), (1, 1), (2, -1), (3, 2), (4, -2), (5, 3)] {
4322 let mut w = BitWriter::new();
4323 w.write_ue(code);
4324 let bytes = w.bytes();
4325 let mut br = BitReader::new(&bytes);
4326 assert_eq!(
4327 br.read_se(),
4328 Some(expected),
4329 "codeNum={} expected={}",
4330 code,
4331 expected
4332 );
4333 }
4334 }
4335}