From 71b04f4fff590e6774973d27b94280422153823a Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 11 Dec 2023 15:01:50 +0000 Subject: [PATCH 1/9] decoders: stateless: h265: set coded_resolution member This member was previously unset, set it during apply_sps(). --- src/decoder/stateless/h265.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/decoder/stateless/h265.rs b/src/decoder/stateless/h265.rs index b90d931f..ff55679a 100644 --- a/src/decoder/stateless/h265.rs +++ b/src/decoder/stateless/h265.rs @@ -379,6 +379,10 @@ where let max_dpb_size = std::cmp::min(sps.max_dpb_size(), 16); self.codec.dpb.set_max_num_pics(max_dpb_size); + self.coded_resolution = Resolution { + width: u32::from(sps.width()), + height: u32::from(sps.height()), + }; Ok(()) } From 77d993b3faac15049e2d8c09dfcde52e3b47cf27 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Thu, 30 Nov 2023 17:01:55 +0000 Subject: [PATCH 2/9] h264/5: further remove accessors Most accessors have already been removed, but some remain. Remove them. --- src/codec/h264/dpb.rs | 10 +- src/codec/h264/nalu.rs | 35 +- src/codec/h264/parser.rs | 508 +++---------- src/codec/h264/picture.rs | 10 +- src/codec/h265/parser.rs | 1083 ++++++--------------------- src/codec/h265/picture.rs | 14 +- src/decoder/stateless/h264.rs | 56 +- src/decoder/stateless/h264/vaapi.rs | 58 +- src/decoder/stateless/h265.rs | 97 ++- src/decoder/stateless/h265/vaapi.rs | 116 +-- src/utils.rs | 12 +- 11 files changed, 514 insertions(+), 1485 deletions(-) diff --git a/src/codec/h264/dpb.rs b/src/codec/h264/dpb.rs index 17cdb2bd..ecdcce72 100644 --- a/src/codec/h264/dpb.rs +++ b/src/codec/h264/dpb.rs @@ -460,7 +460,7 @@ impl Dpb { } pub fn mmco_op_1(&self, pic: &PictureData, marking: usize) -> Result<(), MmcoError> { - let marking = &pic.ref_pic_marking.inner()[marking]; + let marking = &pic.ref_pic_marking.inner[marking]; let pic_num_x = pic.pic_num - (i32::try_from(marking.difference_of_pic_nums_minus1).unwrap() + 1); @@ -480,7 +480,7 @@ impl Dpb { } pub fn mmco_op_2(&self, pic: &PictureData, marking: usize) -> Result<(), MmcoError> { - let marking = &pic.ref_pic_marking.inner()[marking]; + let marking = &pic.ref_pic_marking.inner[marking]; log::debug!( "MMCO op 2 for long_term_pic_num {}", @@ -504,7 +504,7 @@ impl Dpb { } pub fn mmco_op_3(&self, pic: &PictureData, marking: usize) -> Result<(), MmcoError> { - let marking = &pic.ref_pic_marking.inner()[marking]; + let marking = &pic.ref_pic_marking.inner[marking]; let pic_num_x = pic.pic_num - (i32::try_from(marking.difference_of_pic_nums_minus1).unwrap() + 1); @@ -604,7 +604,7 @@ impl Dpb { /// Returns the new `max_long_term_frame_idx`. pub fn mmco_op_4(&mut self, pic: &PictureData, marking: usize) -> i32 { - let marking = &pic.ref_pic_marking.inner()[marking]; + let marking = &pic.ref_pic_marking.inner[marking]; let max_long_term_frame_idx = marking.max_long_term_frame_idx_plus1 - 1; log::debug!( @@ -670,7 +670,7 @@ impl Dpb { } pub fn mmco_op_6(&mut self, pic: &mut PictureData, marking: usize) { - let marking = &pic.ref_pic_marking.inner()[marking]; + let marking = &pic.ref_pic_marking.inner[marking]; let long_term_frame_idx = i32::try_from(marking.long_term_frame_idx).unwrap(); log::debug!("MMCO op 6, long_term_frame_idx: {}", long_term_frame_idx); diff --git a/src/codec/h264/nalu.rs b/src/codec/h264/nalu.rs index a00ed7b8..d4e80369 100644 --- a/src/codec/h264/nalu.rs +++ b/src/codec/h264/nalu.rs @@ -19,14 +19,14 @@ pub trait Header: Sized { #[derive(Debug)] pub struct Nalu<'a, U> { - header: U, + pub header: U, /// The mapping that backs this NALU. Possibly shared with the other NALUs /// in the Access Unit. - data: &'a [u8], + pub data: &'a [u8], - size: usize, - offset: usize, - sc_offset: usize, + pub size: usize, + pub offset: usize, + pub sc_offset: usize, } impl<'a, U> Nalu<'a, U> @@ -98,31 +98,6 @@ where .windows(3) .position(|window| window == [0x00, 0x00, 0x01]) } - - /// Get a reference to the nalu's header. - pub fn header(&self) -> &U { - &self.header - } - - /// Get a reference to the nalu's data. - pub fn data(&self) -> &'a [u8] { - self.data - } - - /// Get a reference to the nalu's size. - pub fn size(&self) -> usize { - self.size - } - - /// Get a reference to the nalu's offset. - pub fn offset(&self) -> usize { - self.offset - } - - /// Get a reference to the nalu's sc offset. - pub fn sc_offset(&self) -> usize { - self.sc_offset - } } impl<'a, U> AsRef<[u8]> for Nalu<'a, U> { diff --git a/src/codec/h264/parser.rs b/src/codec/h264/parser.rs index 9ad3b6b4..ec06df34 100644 --- a/src/codec/h264/parser.rs +++ b/src/codec/h264/parser.rs @@ -85,82 +85,34 @@ pub enum NaluType { #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct RefPicListModification { - modification_of_pic_nums_idc: u8, + pub modification_of_pic_nums_idc: u8, /* if modification_of_pic_nums_idc == 0 || 1 */ - abs_diff_pic_num_minus1: u32, + pub abs_diff_pic_num_minus1: u32, /* if modification_of_pic_nums_idc == 2 */ - long_term_pic_num: u32, + pub long_term_pic_num: u32, /* if modification_of_pic_nums_idc == 4 || 5 */ - abs_diff_view_idx_minus1: u32, -} - -impl RefPicListModification { - pub fn modification_of_pic_nums_idc(&self) -> u8 { - self.modification_of_pic_nums_idc - } - pub fn abs_diff_pic_num_minus1(&self) -> u32 { - self.abs_diff_pic_num_minus1 - } - pub fn long_term_pic_num(&self) -> u32 { - self.long_term_pic_num - } - pub fn abs_diff_view_idx_minus1(&self) -> u32 { - self.abs_diff_view_idx_minus1 - } + pub abs_diff_view_idx_minus1: u32, } #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct PredWeightTable { - luma_log2_weight_denom: u8, - chroma_log2_weight_denom: u8, + pub luma_log2_weight_denom: u8, + pub chroma_log2_weight_denom: u8, - luma_weight_l0: [i16; 32], - luma_offset_l0: [i8; 32], + pub luma_weight_l0: [i16; 32], + pub luma_offset_l0: [i8; 32], /* if seq->ChromaArrayType != 0 */ - chroma_weight_l0: [[i16; 2]; 32], - chroma_offset_l0: [[i8; 2]; 32], + pub chroma_weight_l0: [[i16; 2]; 32], + pub chroma_offset_l0: [[i8; 2]; 32], /* if slice->slice_type % 5 == 1 */ - luma_weight_l1: [i16; 32], - luma_offset_l1: [i16; 32], + pub luma_weight_l1: [i16; 32], + pub luma_offset_l1: [i16; 32], /* and if seq->ChromaArrayType != 0 */ - chroma_weight_l1: [[i16; 2]; 32], - chroma_offset_l1: [[i8; 2]; 32], -} - -impl PredWeightTable { - pub fn luma_log2_weight_denom(&self) -> u8 { - self.luma_log2_weight_denom - } - pub fn chroma_log2_weight_denom(&self) -> u8 { - self.chroma_log2_weight_denom - } - pub fn luma_weight_l0(&self) -> [i16; 32] { - self.luma_weight_l0 - } - pub fn luma_offset_l0(&self) -> [i8; 32] { - self.luma_offset_l0 - } - pub fn chroma_weight_l0(&self) -> [[i16; 2]; 32] { - self.chroma_weight_l0 - } - pub fn chroma_offset_l0(&self) -> [[i8; 2]; 32] { - self.chroma_offset_l0 - } - pub fn luma_weight_l1(&self) -> [i16; 32] { - self.luma_weight_l1 - } - pub fn luma_offset_l1(&self) -> [i16; 32] { - self.luma_offset_l1 - } - pub fn chroma_weight_l1(&self) -> [[i16; 2]; 32] { - self.chroma_weight_l1 - } - pub fn chroma_offset_l1(&self) -> [[i8; 2]; 32] { - self.chroma_offset_l1 - } + pub chroma_weight_l1: [[i16; 2]; 32], + pub chroma_offset_l1: [[i8; 2]; 32], } #[derive(Clone, Debug, Default, PartialEq, Eq)] @@ -196,7 +148,7 @@ pub struct RefPicMarkingInner { pub struct RefPicMarking { /// Specifies how the previously-decoded pictures in the decoded picture /// buffer are treated after decoding of an IDR picture. See Annex C. - no_output_of_prior_pics_flag: bool, + pub no_output_of_prior_pics_flag: bool, /// If unset, specifies that the MaxLongTermFrameIdx variable is set equal /// to "no long-term frame indices" and that the IDR picture is marked as @@ -204,29 +156,14 @@ pub struct RefPicMarking { /// MaxLongTermFrameIdx variable is set equal to 0 and that the current IDR /// picture is marked "used for long-term reference" and is assigned /// LongTermFrameIdx equal to 0. - long_term_reference_flag: bool, + pub long_term_reference_flag: bool, /// Selects the reference picture marking mode of the currently decoded /// picture as specified in Table 7-8. - adaptive_ref_pic_marking_mode_flag: bool, + pub adaptive_ref_pic_marking_mode_flag: bool, /// An Vec with additional data used in the marking process. - inner: Vec, -} - -impl RefPicMarking { - pub fn no_output_of_prior_pics_flag(&self) -> bool { - self.no_output_of_prior_pics_flag - } - pub fn long_term_reference_flag(&self) -> bool { - self.long_term_reference_flag - } - pub fn adaptive_ref_pic_marking_mode_flag(&self) -> bool { - self.adaptive_ref_pic_marking_mode_flag - } - pub fn inner(&self) -> &Vec { - &self.inner - } + pub inner: Vec, } #[derive(Clone, Debug, Default, PartialEq, Eq)] @@ -393,21 +330,9 @@ impl SliceHeader { /// consecutively in the raster scan within a particular slice group pub struct Slice<'a> { /// The slice header. - header: SliceHeader, + pub header: SliceHeader, /// The NAL unit backing this slice. - nalu: Nalu<'a>, -} - -impl<'a> Slice<'a> { - /// Get a reference to the slice's header. - pub fn header(&self) -> &SliceHeader { - &self.header - } - - /// Get a reference to the slice's nalu. - pub fn nalu(&self) -> &Nalu<'a> { - &self.nalu - } + pub nalu: Nalu<'a>, } #[derive(N, Clone, Copy, Debug, PartialEq, Eq)] @@ -773,9 +698,8 @@ impl Sps { let mut max_dpb_frames = std::cmp::max(max_dpb_frames, self.max_num_ref_frames as usize); - if self.vui_parameters_present_flag && self.vui_parameters.bitstream_restriction_flag() { - max_dpb_frames = - std::cmp::max(1, self.vui_parameters.max_dec_frame_buffering() as usize); + if self.vui_parameters_present_flag && self.vui_parameters.bitstream_restriction_flag { + max_dpb_frames = std::cmp::max(1, self.vui_parameters.max_dec_frame_buffering as usize); } max_dpb_frames @@ -783,10 +707,10 @@ impl Sps { pub fn max_num_order_frames(&self) -> u32 { let vui = &self.vui_parameters; - let present = self.vui_parameters_present_flag && vui.bitstream_restriction_flag(); + let present = self.vui_parameters_present_flag && vui.bitstream_restriction_flag; if present { - vui.max_num_reorder_frames() + vui.max_num_reorder_frames } else { let profile = self.profile_idc; if (profile == 44 @@ -864,96 +788,63 @@ pub struct HrdParams { /// Plus 1 specifies the number of alternative CPB specifications in the /// bitstream. The value of `cpb_cnt_minus1` shall be in the range of 0 to 31, /// inclusive - cpb_cnt_minus1: u8, + pub cpb_cnt_minus1: u8, /// Together with `bit_rate_value_minus1[ SchedSelIdx ]` specifies the /// maximum input bit rate of the `SchedSelIdx`-th CPB. - bit_rate_scale: u8, + pub bit_rate_scale: u8, /// Together with `cpb_size_value_minus1[ SchedSelIdx ]` specifies the CPB /// size of the SchedSelIdx-th CPB. - cpb_size_scale: u8, + pub cpb_size_scale: u8, /// `[ SchedSelIdx ]` (together with bit_rate_scale) specifies the maximum /// input bit rate for the SchedSelIdx-th CPB. - bit_rate_value_minus1: [u32; 32], + pub bit_rate_value_minus1: [u32; 32], /// `[ SchedSelIdx ]` is used together with cpb_size_scale to specify the /// SchedSelIdx-th CPB size. - cpb_size_value_minus1: [u32; 32], + pub cpb_size_value_minus1: [u32; 32], /// `[ SchedSelIdx ]` equal to 0 specifies that to decode this bitstream by /// the HRD using the `SchedSelIdx`-th CPB specification, the hypothetical /// stream delivery scheduler (HSS) operates in an intermittent bit rate /// mode. `cbr_flag[ SchedSelIdx ]` equal to 1 specifies that the HSS operates /// in a constant bit rate (CBR) mode - cbr_flag: [bool; 32], + pub cbr_flag: [bool; 32], /// Specifies the length in bits of the `initial_cpb_removal_delay[ /// SchedSelIdx ]` and `initial_cpb_removal_delay_offset[ SchedSelIdx ]` syntax /// elements of the buffering period SEI message. - initial_cpb_removal_delay_length_minus1: u8, + pub initial_cpb_removal_delay_length_minus1: u8, /// Specifies the length in bits of the `cpb_removal_delay` syntax element. - cpb_removal_delay_length_minus1: u8, + pub cpb_removal_delay_length_minus1: u8, /// Specifies the length in bits of the `dpb_output_delay` syntax element. - dpb_output_delay_length_minus1: u8, + pub dpb_output_delay_length_minus1: u8, /// If greater than 0, specifies the length in bits of the `time_offset` /// syntax element. `time_offset_length` equal to 0 specifies that the /// `time_offset` syntax element is not present - time_offset_length: u8, -} - -impl HrdParams { - pub fn cpb_cnt_minus1(&self) -> u8 { - self.cpb_cnt_minus1 - } - pub fn bit_rate_scale(&self) -> u8 { - self.bit_rate_scale - } - pub fn cpb_size_scale(&self) -> u8 { - self.cpb_size_scale - } - pub fn bit_rate_value_minus1(&self) -> [u32; 32] { - self.bit_rate_value_minus1 - } - pub fn cpb_size_value_minus1(&self) -> [u32; 32] { - self.cpb_size_value_minus1 - } - pub fn cbr_flag(&self) -> [bool; 32] { - self.cbr_flag - } - pub fn initial_cpb_removal_delay_length_minus1(&self) -> u8 { - self.initial_cpb_removal_delay_length_minus1 - } - pub fn cpb_removal_delay_length_minus1(&self) -> u8 { - self.cpb_removal_delay_length_minus1 - } - pub fn dpb_output_delay_length_minus1(&self) -> u8 { - self.dpb_output_delay_length_minus1 - } - pub fn time_offset_length(&self) -> u8 { - self.time_offset_length - } + pub time_offset_length: u8, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct VuiParams { /// Specifies whether `aspect_ratio_idc` is present. - aspect_ratio_info_present_flag: bool, + pub aspect_ratio_info_present_flag: bool, /// Specifies the value of the sample aspect ratio of the luma samples. /// Table E-1 shows the meaning of the code. When aspect_ratio_idc indicates /// Extended_SAR, the sample aspect ratio is represented by sar_width : /// sar_height. When the aspect_ratio_idc syntax element is not present, /// aspect_ratio_idc value shall be inferred to be equal to 0 - aspect_ratio_idc: u8, + pub aspect_ratio_idc: u8, /* if aspect_ratio_idc == 255 */ /// Indicates the horizontal size of the sample aspect ratio (in arbitrary /// units) - sar_width: u16, + pub sar_width: u16, /// Indicates the vertical size of the sample aspect ratio (in the same /// arbitrary units as sar_width). - sar_height: u16, + pub sar_height: u16, /// If true specifies that the overscan_appropriate_flag is present. Else, /// the preferred display method for the video signal is unspecified - overscan_info_present_flag: bool, + pub overscan_info_present_flag: bool, /* if overscan_info_present_flag */ /// If true, indicates that the cropped decoded pictures output are suitable /// for display using overscan. Else, indicates that the cropped decoded @@ -961,80 +852,80 @@ pub struct VuiParams { /// region out to the edges of the cropping rectangle of the picture, such /// that the cropped decoded pictures output should not be displayed using /// overscan. - overscan_appropriate_flag: bool, + pub overscan_appropriate_flag: bool, /// Specifies that video_format, video_full_range_flag and /// colour_description_present_flag are present - video_signal_type_present_flag: bool, + pub video_signal_type_present_flag: bool, /// Indicates the representation of the pictures as specified in Table E-2, /// before being coded in accordance with this Recommendation | /// International Standard. When the video_format syntax element is not /// present, video_format value shall be inferred to be equal to 5. - video_format: u8, + pub video_format: u8, /// Indicates the black level and range of the luma and chroma signals as /// derived from E′Y, E′PB, and E′PR or E′ R, E′G, and E′B real-valued /// component signals. - video_full_range_flag: bool, + pub video_full_range_flag: bool, /// Specifies that colour_primaries, transfer_characteristics and /// matrix_coefficients are present. - colour_description_present_flag: bool, + pub colour_description_present_flag: bool, /// Indicates the chromaticity coordinates of the source primaries as /// specified in Table E-3 in terms of the CIE 1931 definition of x and y as /// specified by ISO 11664-1. - colour_primaries: u8, + pub colour_primaries: u8, /// Retains same meaning as in the specification. - transfer_characteristics: u8, + pub transfer_characteristics: u8, /// Describes the matrix coefficients used in deriving luma and chroma /// signals from the green, blue, and red, or Y, Z, and X primaries, as /// specified in Table E-5. - matrix_coefficients: u8, + pub matrix_coefficients: u8, /// Specifies that chroma_sample_loc_type_top_field and /// chroma_sample_loc_type_bottom_field are present - chroma_loc_info_present_flag: bool, + pub chroma_loc_info_present_flag: bool, /// Specify the location of chroma samples. See the spec for more details. - chroma_sample_loc_type_top_field: u8, + pub chroma_sample_loc_type_top_field: u8, /// Specify the location of chroma samples. See the spec for more details. - chroma_sample_loc_type_bottom_field: u8, + pub chroma_sample_loc_type_bottom_field: u8, /// Specifies that num_units_in_tick, time_scale and fixed_frame_rate_flag /// are present in the bitstream - timing_info_present_flag: bool, + pub timing_info_present_flag: bool, /* if timing_info_present_flag */ /// The number of time units of a clock operating at the frequency /// time_scale Hz that corresponds to one increment (called a clock tick) of /// a clock tick counter - num_units_in_tick: u32, + pub num_units_in_tick: u32, /// The number of time units that pass in one second. For example, a time /// coordinate system that measures time using a 27 MHz clock has a /// time_scale of 27 000 000. time_scale shall be greater than 0. - time_scale: u32, + pub time_scale: u32, /// Retains the same meaning as the specification. - fixed_frame_rate_flag: bool, + pub fixed_frame_rate_flag: bool, /// Specifies that NAL HRD parameters (pertaining to Type II bitstream /// conformance) are present. - nal_hrd_parameters_present_flag: bool, + pub nal_hrd_parameters_present_flag: bool, /* if nal_hrd_parameters_present_flag */ /// The NAL HDR parameters - nal_hrd_parameters: HrdParams, + pub nal_hrd_parameters: HrdParams, /// Specifies that VCL HRD parameters (pertaining to all bitstream /// conformance) are present. - vcl_hrd_parameters_present_flag: bool, + pub vcl_hrd_parameters_present_flag: bool, /* if vcl_hrd_parameters_present_flag */ /// The VCL HRD parameters - vcl_hrd_parameters: HrdParams, + pub vcl_hrd_parameters: HrdParams, /// Specifies the HRD operational mode as specified in Annex C. - low_delay_hrd_flag: bool, + pub low_delay_hrd_flag: bool, /// Specifies that picture timing SEI messages (clause D.2.3) are present /// that include the pic_struct syntax element. - pic_struct_present_flag: bool, + pub pic_struct_present_flag: bool, /// Specifies that the following coded video sequence bitstream restriction /// parameters are present - bitstream_restriction_flag: bool, + pub bitstream_restriction_flag: bool, /* if bitstream_restriction_flag */ /// If false, indicates that no sample outside the picture boundaries and no /// sample at a fractional sample position for which the sample value is @@ -1044,19 +935,19 @@ pub struct VuiParams { /// the motion_vectors_over_pic_boundaries_flag syntax element is not /// present, motion_vectors_over_pic_boundaries_flag value shall be inferred /// to be true. - motion_vectors_over_pic_boundaries_flag: bool, + pub motion_vectors_over_pic_boundaries_flag: bool, /// Indicates a number of bytes not exceeded by the sum of the sizes of the /// VCL NAL units associated with any coded picture in the coded video /// sequence. - max_bytes_per_pic_denom: u32, + pub max_bytes_per_pic_denom: u32, /// Indicates an upper bound for the number of coded bits of /// macroblock_layer( ) data for any macroblock in any picture of the coded /// video sequence - max_bits_per_mb_denom: u32, + pub max_bits_per_mb_denom: u32, /// Retains the same meaning as the specification. - log2_max_mv_length_horizontal: u32, + pub log2_max_mv_length_horizontal: u32, /// Retains the same meaning as the specification. - log2_max_mv_length_vertical: u32, + pub log2_max_mv_length_vertical: u32, /// Indicates an upper bound for the number of frames buffers, in the /// decoded picture buffer (DPB), that are required for storing frames, /// complementary field pairs, and non-paired fields before output. It is a @@ -1077,7 +968,7 @@ pub struct VuiParams { /// Otherwise (profile_idc is not equal to 44, 86, 100, 110, 122, or 244 or /// constraint_set3_flag is equal to 0), the value of max_num_reorder_frames /// shall be inferred to be equal to MaxDpbFrames. - max_num_reorder_frames: u32, + pub max_num_reorder_frames: u32, /// Specifies the required size of the HRD decoded picture buffer (DPB) in /// units of frame buffers. It is a requirement of bitstream conformance /// that the coded video sequence shall not require a decoded picture buffer @@ -1099,112 +990,7 @@ pub struct VuiParams { /// Otherwise (profile_idc is not equal to 44, 86, 100, 110, 122, or 244 or /// constraint_set3_flag is equal to 0), the value of /// max_dec_frame_buffering shall be inferred to be equal to MaxDpbFrames. - max_dec_frame_buffering: u32, -} - -impl VuiParams { - pub fn aspect_ratio_info_present_flag(&self) -> bool { - self.aspect_ratio_info_present_flag - } - pub fn aspect_ratio_idc(&self) -> u8 { - self.aspect_ratio_idc - } - pub fn sar_width(&self) -> u16 { - self.sar_width - } - pub fn sar_height(&self) -> u16 { - self.sar_height - } - pub fn overscan_info_present_flag(&self) -> bool { - self.overscan_info_present_flag - } - pub fn overscan_appropriate_flag(&self) -> bool { - self.overscan_appropriate_flag - } - pub fn video_signal_type_present_flag(&self) -> bool { - self.video_signal_type_present_flag - } - pub fn video_format(&self) -> u8 { - self.video_format - } - pub fn video_full_range_flag(&self) -> bool { - self.video_full_range_flag - } - pub fn colour_description_present_flag(&self) -> bool { - self.colour_description_present_flag - } - pub fn colour_primaries(&self) -> u8 { - self.colour_primaries - } - pub fn transfer_characteristics(&self) -> u8 { - self.transfer_characteristics - } - pub fn matrix_coefficients(&self) -> u8 { - self.matrix_coefficients - } - pub fn chroma_loc_info_present_flag(&self) -> bool { - self.chroma_loc_info_present_flag - } - pub fn chroma_sample_loc_type_top_field(&self) -> u8 { - self.chroma_sample_loc_type_top_field - } - pub fn chroma_sample_loc_type_bottom_field(&self) -> u8 { - self.chroma_sample_loc_type_bottom_field - } - pub fn timing_info_present_flag(&self) -> bool { - self.timing_info_present_flag - } - pub fn num_units_in_tick(&self) -> u32 { - self.num_units_in_tick - } - pub fn time_scale(&self) -> u32 { - self.time_scale - } - pub fn fixed_frame_rate_flag(&self) -> bool { - self.fixed_frame_rate_flag - } - pub fn nal_hrd_parameters_present_flag(&self) -> bool { - self.nal_hrd_parameters_present_flag - } - pub fn nal_hrd_parameters(&self) -> &HrdParams { - &self.nal_hrd_parameters - } - pub fn vcl_hrd_parameters_present_flag(&self) -> bool { - self.vcl_hrd_parameters_present_flag - } - pub fn vcl_hrd_parameters(&self) -> &HrdParams { - &self.vcl_hrd_parameters - } - pub fn low_delay_hrd_flag(&self) -> bool { - self.low_delay_hrd_flag - } - pub fn pic_struct_present_flag(&self) -> bool { - self.pic_struct_present_flag - } - pub fn bitstream_restriction_flag(&self) -> bool { - self.bitstream_restriction_flag - } - pub fn motion_vectors_over_pic_boundaries_flag(&self) -> bool { - self.motion_vectors_over_pic_boundaries_flag - } - pub fn max_bytes_per_pic_denom(&self) -> u32 { - self.max_bytes_per_pic_denom - } - pub fn max_bits_per_mb_denom(&self) -> u32 { - self.max_bits_per_mb_denom - } - pub fn log2_max_mv_length_horizontal(&self) -> u32 { - self.log2_max_mv_length_horizontal - } - pub fn log2_max_mv_length_vertical(&self) -> u32 { - self.log2_max_mv_length_vertical - } - pub fn max_num_reorder_frames(&self) -> u32 { - self.max_num_reorder_frames - } - pub fn max_dec_frame_buffering(&self) -> u32 { - self.max_dec_frame_buffering - } + pub max_dec_frame_buffering: u32, } impl Default for VuiParams { @@ -1254,10 +1040,10 @@ impl Default for VuiParams { #[derive(Debug, PartialEq, Eq)] pub struct Pps { /// Identifies the picture parameter set that is referred to in the slice header. - pic_parameter_set_id: u8, + pub pic_parameter_set_id: u8, /// Refers to the active sequence parameter set. - seq_parameter_set_id: u8, + pub seq_parameter_set_id: u8, /// Selects the entropy decoding method to be applied for the syntax /// elements for which two descriptors appear in the syntax tables as @@ -1266,7 +1052,7 @@ pub struct Pps { /// see clause 9.1 or CAVLC, see clause 9.2). Otherwise /// (`entropy_coding_mode_flag` is true), the method specified by the right /// descriptor in the syntax table is applied (CABAC, see clause 9.3). - entropy_coding_mode_flag: bool, + pub entropy_coding_mode_flag: bool, /// If true, specifies that the syntax elements delta_pic_order_cnt_bottom /// (when `pic_order_cnt_type` is equal to 0) or `delta_pic_order_cnt[1]` @@ -1275,55 +1061,55 @@ pub struct Pps { /// slice headers for coded frames as specified in clause 7.3.3. Otherwise, /// specifies that the syntax elements `delta_pic_order_cnt_bottom` and /// `delta_pic_order_cnt[1]` are not present in the slice headers. - bottom_field_pic_order_in_frame_present_flag: bool, + pub bottom_field_pic_order_in_frame_present_flag: bool, /// Plus 1 specifies the number of slice groups for a picture. When /// `num_slice_groups_minus1` is equal to 0, all slices of the picture /// belong to the same slice group. The allowed range of /// `num_slice_groups_minus1` is specified in Annex A. - num_slice_groups_minus1: u32, + pub num_slice_groups_minus1: u32, /// Specifies how `num_ref_idx_l0_active_minus1` is inferred for P, SP, and /// B slices with `num_ref_idx_active_override_flag` not set. - num_ref_idx_l0_default_active_minus1: u8, + pub num_ref_idx_l0_default_active_minus1: u8, /// Specifies how `num_ref_idx_l1_active_minus1` is inferred for B slices /// with `num_ref_idx_active_override_flag` not set. - num_ref_idx_l1_default_active_minus1: u8, + pub num_ref_idx_l1_default_active_minus1: u8, /// If not set, specifies that the default weighted prediction shall be /// applied to P and SP slices. If set, specifies that explicit weighted /// prediction shall be applied to P and SP slices. - weighted_pred_flag: bool, + pub weighted_pred_flag: bool, /// `weighted_bipred_idc` equal to 0 specifies that the default weighted /// prediction shall be applied to B slices. `weighted_bipred_idc` equal to /// 1 specifies that explicit weighted prediction shall be applied to B /// slices. `weighted_bipred_idc` equal to 2 specifies that implicit /// weighted prediction shall be applied to B slices - weighted_bipred_idc: u8, + pub weighted_bipred_idc: u8, /// Specifies the initial value minus 26 of SliceQPY for each slice. The /// initial value is modified at the slice layer when a non-zero value of /// `slice_qp_delta` is decoded, and is modified further when a non-zero /// value of `mb_qp_delta` is decoded at the macroblock layer. - pic_init_qp_minus26: i8, + pub pic_init_qp_minus26: i8, /// Specifies the initial value minus 26 of SliceQSY for all macroblocks in /// SP or SI slices. The initial value is modified at the slice layer when a /// non-zero value of `slice_qs_delta` is decoded. - pic_init_qs_minus26: i8, + pub pic_init_qs_minus26: i8, /// Specifies the offset that shall be added to QP Y and QSY for addressing /// the table of QPC values for the Cb chroma component. - chroma_qp_index_offset: i8, + pub chroma_qp_index_offset: i8, /// If set, specifies that a set of syntax elements controlling the /// characteristics of the deblocking filter is present in the slice header. /// If not set, specifies that the set of syntax elements controlling the /// characteristics of the deblocking filter is not present in the slice /// headers and their inferred values are in effect. - deblocking_filter_control_present_flag: bool, + pub deblocking_filter_control_present_flag: bool, /// If not set, specifies that intra prediction allows usage of residual /// data and decoded samples of neighbouring macroblocks coded using Inter @@ -1332,7 +1118,7 @@ pub struct Pps { /// intra prediction, in which case prediction of macroblocks coded using /// Intra macroblock prediction modes only uses residual data and decoded /// samples from I or SI macroblock types. - constrained_intra_pred_flag: bool, + pub constrained_intra_pred_flag: bool, /// If not set, specifies that the `redundant_pic_cnt` syntax element is not /// present in slice headers, coded slice data partition B NAL units, and @@ -1344,97 +1130,34 @@ pub struct Pps { /// NAL units that refer (either directly or by association with a /// corresponding coded slice data partition A NAL unit) to the picture /// parameter set. - redundant_pic_cnt_present_flag: bool, + pub redundant_pic_cnt_present_flag: bool, /// If set, specifies that the 8x8 transform decoding process may be in use /// (see clause 8.5). If not set, specifies that the 8x8 transform decoding /// process is not in use. - transform_8x8_mode_flag: bool, + pub transform_8x8_mode_flag: bool, /// If set, specifies that parameters are present to modify the scaling /// lists specified in the sequence parameter set. If not set, specifies /// that the scaling lists used for the picture shall be inferred to be /// equal to those specified by the sequence parameter set. - pic_scaling_matrix_present_flag: bool, + pub pic_scaling_matrix_present_flag: bool, /// 4x4 Scaling list as read with 7.3.2.1.1.1 - scaling_lists_4x4: [[u8; 16]; 6], + pub scaling_lists_4x4: [[u8; 16]; 6], /// 8x8 Scaling list as read with 7.3.2.1.1.1 - scaling_lists_8x8: [[u8; 64]; 6], + pub scaling_lists_8x8: [[u8; 64]; 6], /// Specifies the offset that shall be added to QPY and QSY for addressing /// the table of QPC values for the Cr chroma component. When /// `second_chroma_qp_index_offset` is not present, it shall be inferred to be /// equal to `chroma_qp_index_offset`. - second_chroma_qp_index_offset: i8, + pub second_chroma_qp_index_offset: i8, /// The SPS referenced by this PPS. pub sps: Rc, } -impl Pps { - pub fn pic_parameter_set_id(&self) -> u8 { - self.pic_parameter_set_id - } - pub fn seq_parameter_set_id(&self) -> u8 { - self.seq_parameter_set_id - } - pub fn entropy_coding_mode_flag(&self) -> bool { - self.entropy_coding_mode_flag - } - pub fn bottom_field_pic_order_in_frame_present_flag(&self) -> bool { - self.bottom_field_pic_order_in_frame_present_flag - } - pub fn num_slice_groups_minus1(&self) -> u32 { - self.num_slice_groups_minus1 - } - pub fn num_ref_idx_l0_default_active_minus1(&self) -> u8 { - self.num_ref_idx_l0_default_active_minus1 - } - pub fn num_ref_idx_l1_default_active_minus1(&self) -> u8 { - self.num_ref_idx_l1_default_active_minus1 - } - pub fn weighted_pred_flag(&self) -> bool { - self.weighted_pred_flag - } - pub fn weighted_bipred_idc(&self) -> u8 { - self.weighted_bipred_idc - } - pub fn pic_init_qp_minus26(&self) -> i8 { - self.pic_init_qp_minus26 - } - pub fn pic_init_qs_minus26(&self) -> i8 { - self.pic_init_qs_minus26 - } - pub fn chroma_qp_index_offset(&self) -> i8 { - self.chroma_qp_index_offset - } - pub fn deblocking_filter_control_present_flag(&self) -> bool { - self.deblocking_filter_control_present_flag - } - pub fn constrained_intra_pred_flag(&self) -> bool { - self.constrained_intra_pred_flag - } - pub fn redundant_pic_cnt_present_flag(&self) -> bool { - self.redundant_pic_cnt_present_flag - } - pub fn transform_8x8_mode_flag(&self) -> bool { - self.transform_8x8_mode_flag - } - pub fn pic_scaling_matrix_present_flag(&self) -> bool { - self.pic_scaling_matrix_present_flag - } - pub fn scaling_lists_4x4(&self) -> [[u8; 16]; 6] { - self.scaling_lists_4x4 - } - pub fn scaling_lists_8x8(&self) -> [[u8; 64]; 6] { - self.scaling_lists_8x8 - } - pub fn second_chroma_qp_index_offset(&self) -> i8 { - self.second_chroma_qp_index_offset - } -} - #[derive(Debug, Default)] pub struct Parser { active_spses: BTreeMap>, @@ -1770,17 +1493,17 @@ impl Parser { /// /// Returns a reference to the new SPS. pub fn parse_sps(&mut self, nalu: &Nalu) -> anyhow::Result<&Rc> { - if !matches!(nalu.header().type_, NaluType::Sps) { + if !matches!(nalu.header.type_, NaluType::Sps) { return Err(anyhow!( "Invalid NALU type, expected {:?}, got {:?}", NaluType::Sps, - nalu.header().type_ + nalu.header.type_ )); } let data = nalu.as_ref(); // Skip the header - let mut r = NaluReader::new(&data[nalu.header().len()..]); + let mut r = NaluReader::new(&data[nalu.header.len()..]); let mut sps = Sps { profile_idc: r.read_bits(8)?, constraint_set0_flag: r.read_bit()?, @@ -1939,17 +1662,17 @@ impl Parser { } pub fn parse_pps(&mut self, nalu: &Nalu) -> anyhow::Result<&Pps> { - if !matches!(nalu.header().type_, NaluType::Pps) { + if !matches!(nalu.header.type_, NaluType::Pps) { return Err(anyhow!( "Invalid NALU type, expected {:?}, got {:?}", NaluType::Pps, - nalu.header().type_ + nalu.header.type_ )); } let data = nalu.as_ref(); // Skip the header - let mut r = NaluReader::new(&data[nalu.header().len()..]); + let mut r = NaluReader::new(&data[nalu.header.len()..]); let pic_parameter_set_id = r.read_ue_max(MAX_PPS_COUNT as u32 - 1)?; let seq_parameter_set_id = r.read_ue_max(MAX_SPS_COUNT as u32 - 1)?; let sps = self.get_sps(seq_parameter_set_id).context( @@ -2204,7 +1927,7 @@ impl Parser { ) -> anyhow::Result<()> { let rpm = &mut header.dec_ref_pic_marking; - if nalu.header().idr_pic_flag { + if nalu.header.idr_pic_flag { rpm.no_output_of_prior_pics_flag = r.read_bit()?; rpm.long_term_reference_flag = r.read_bit()?; } else { @@ -2247,7 +1970,7 @@ impl Parser { pub fn parse_slice_header<'a>(&self, nalu: Nalu<'a>) -> anyhow::Result> { if !matches!( - nalu.header().type_, + nalu.header.type_, NaluType::Slice | NaluType::SliceDpa | NaluType::SliceDpb @@ -2257,13 +1980,13 @@ impl Parser { ) { return Err(anyhow!( "Invalid NALU type: {:?} is not a slice NALU", - nalu.header().type_ + nalu.header.type_ )); } let data = nalu.as_ref(); // Skip the header - let mut r = NaluReader::new(&data[nalu.header().len()..]); + let mut r = NaluReader::new(&data[nalu.header.len()..]); let mut header = SliceHeader { first_mb_in_slice: r.read_ue()?, @@ -2301,7 +2024,7 @@ impl Parser { header.max_pic_num = sps.max_frame_num(); } - if nalu.header().idr_pic_flag { + if nalu.header.idr_pic_flag { header.idr_pic_id = r.read_ue_max(0xffff)?; } @@ -2355,7 +2078,7 @@ impl Parser { return Err(anyhow!("Broken Data")); } - if let NaluType::SliceExt = nalu.header().type_ { + if let NaluType::SliceExt = nalu.header.type_ { return Err(anyhow!("Stream contain unsupported/unimplemented NALs")); } @@ -2367,7 +2090,7 @@ impl Parser { Parser::parse_pred_weight_table(&mut r, sps, &mut header)?; } - if nalu.header().ref_idc != 0 { + if nalu.header.ref_idc != 0 { Parser::parse_dec_ref_pic_marking(&mut r, &nalu, &mut header)?; } @@ -2399,7 +2122,7 @@ impl Parser { } let epb = r.num_epb(); - header.header_bit_size = (nalu.size() - epb) * 8 - r.num_bits_left(); + header.header_bit_size = (nalu.size - epb) * 8 - r.num_bits_left(); header.n_emulation_prevention_bytes = epb; @@ -2417,26 +2140,9 @@ impl Parser { #[derive(Debug)] pub struct NaluHeader { - ref_idc: u8, - type_: NaluType, - idr_pic_flag: bool, -} - -impl NaluHeader { - /// Get a reference to the nalu header's ref idc. - pub fn ref_idc(&self) -> u8 { - self.ref_idc - } - - /// Get a reference to the nalu header's type. - pub fn nalu_type(&self) -> NaluType { - self.type_ - } - - /// Get a reference to the nalu header's idr pic flag. - pub fn idr_pic_flag(&self) -> bool { - self.idr_pic_flag - } + pub ref_idc: u8, + pub type_: NaluType, + pub idr_pic_flag: bool, } impl Header for NaluHeader { @@ -2517,7 +2223,7 @@ mod tests { let mut parser = Parser::default(); while let Ok(nalu) = Nalu::next(&mut cursor) { - match nalu.header().type_ { + match nalu.header.type_ { NaluType::Slice | NaluType::SliceDpa | NaluType::SliceDpb @@ -2824,7 +2530,7 @@ mod tests { let mut parser = Parser::default(); while let Ok(nalu) = Nalu::next(&mut cursor) { - assert_eq!(nalu.header().type_, NaluType::Sps); + assert_eq!(nalu.header.type_, NaluType::Sps); parser.parse_sps(&nalu).unwrap_err(); } } diff --git a/src/codec/h264/picture.rs b/src/codec/h264/picture.rs index de6d6062..212f1da8 100644 --- a/src/codec/h264/picture.rs +++ b/src/codec/h264/picture.rs @@ -115,10 +115,10 @@ impl PictureData { } pub fn new_from_slice(slice: &Slice, sps: &Sps, timestamp: u64) -> Self { - let hdr = slice.header(); - let nalu_hdr = slice.nalu().header(); + let hdr = &slice.header; + let nalu_hdr = &slice.nalu.header; - let is_idr = if nalu_hdr.idr_pic_flag() { + let is_idr = if nalu_hdr.idr_pic_flag { IsIdr::Yes { idr_pic_id: hdr.idr_pic_id, } @@ -136,7 +136,7 @@ impl PictureData { Field::Frame }; - let reference = if nalu_hdr.ref_idc() != 0 { + let reference = if nalu_hdr.ref_idc != 0 { Reference::ShortTerm } else { Reference::None @@ -193,7 +193,7 @@ impl PictureData { delta_pic_order_cnt1, pic_num: i32::from(pic_num), frame_num: i32::from(hdr.frame_num), - nal_ref_idc: nalu_hdr.ref_idc(), + nal_ref_idc: nalu_hdr.ref_idc, is_idr, reference, field, diff --git a/src/codec/h265/parser.rs b/src/codec/h265/parser.rs index 51e72fae..856c1319 100644 --- a/src/codec/h265/parser.rs +++ b/src/codec/h265/parser.rs @@ -609,19 +609,19 @@ impl Default for SpsSccExtension { #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct Sps { /// Specifies the value of the vps_video_parameter_set_id of the active VPS. - video_parameter_set_id: u8, + pub video_parameter_set_id: u8, /// `max_sub_layers_minus1` plus 1 specifies the maximum number of temporal /// sub-layers that may be present in each CVS referring to the SPS. pub max_sub_layers_minus1: u8, /// When sps_max_sub_layers_minus1 is greater than 0, specifies whether /// inter prediction is additionally restricted for CVSs referring to the /// SPS. - temporal_id_nesting_flag: bool, + pub temporal_id_nesting_flag: bool, /// profile_tier_level() data. pub profile_tier_level: ProfileTierLevel, /// Provides an identifier for the SPS for reference by other syntax /// elements. - seq_parameter_set_id: u8, + pub seq_parameter_set_id: u8, /// Specifies the chroma sampling relative to the luma sampling as specified /// in clause 6.2. pub chroma_format_idc: u8, @@ -636,15 +636,15 @@ pub struct Sps { /// When true, indicates that the conformance cropping window offset /// parameters follow next in the SPS. When false, indicates that the /// conformance cropping window offset parameters are not present. - conformance_window_flag: bool, + pub conformance_window_flag: bool, /* if conformance_window_flag */ /// Specify the samples of the pictures in the CVS that are output from the /// decoding process, in terms of a rectangular region specified in picture /// coordinates for output. - conf_win_left_offset: u32, - conf_win_right_offset: u32, - conf_win_top_offset: u32, - conf_win_bottom_offset: u32, + pub conf_win_left_offset: u32, + pub conf_win_right_offset: u32, + pub conf_win_top_offset: u32, + pub conf_win_bottom_offset: u32, /// Specifies the bit depth of the samples of the luma array BitDepthY and /// the value of the luma quantization parameter range offset QpBdOffsetY. @@ -662,7 +662,7 @@ pub struct Sps { /// that the values of `max_dec_pic_ buffering_minus1[ max_sub_layers_minus1 /// ]`, `max_num_reorder_pics[ max_sub_layers_minus1 ]` and max_ /// `latency_increase_plus1[ max_sub_layers_minus1 ]` apply to all sub-layers. - sub_layer_ordering_info_present_flag: bool, + pub sub_layer_ordering_info_present_flag: bool, /// `max_dec_pic_buffering_minus1[ i ]` plus 1 specifies the maximum required /// size of the decoded picture buffer for the CVS in units of picture /// storage buffers when HighestTid is equal to i. @@ -768,13 +768,13 @@ pub struct Sps { /// `lt_ref_pic_poc_lsb_sps[ i ]` specifies the picture order count modulo /// MaxPicOrderCntLsb of the i-th candidate long-term reference picture /// specified in the SPS. - lt_ref_pic_poc_lsb_sps: [u32; MAX_LONG_TERM_REF_PIC_SETS], + pub lt_ref_pic_poc_lsb_sps: [u32; MAX_LONG_TERM_REF_PIC_SETS], /// `used_by_curr_pic_lt_sps_flag[ i ]` equal to false specifies that the i-th /// candidate long-term reference picture specified in the SPS is not used /// for reference by a picture that includes in its long-term reference /// picture set (RPS) the i-th candidate long-term reference picture /// specified in the SPS. - used_by_curr_pic_lt_sps_flag: [bool; MAX_LONG_TERM_REF_PIC_SETS], + pub used_by_curr_pic_lt_sps_flag: [bool; MAX_LONG_TERM_REF_PIC_SETS], /// When set, specifies that slice_temporal_mvp_enabled_flag is present in /// the slice headers of non-IDR pictures in the CVS. When not set, /// specifies that slice_temporal_mvp_enabled_flag is not present in slice @@ -789,49 +789,49 @@ pub struct Sps { /// specified in Annex E is present. When not set, specifies that the /// vui_parameters( ) syntax structure as specified in Annex E is not /// present. - vui_parameters_present_flag: bool, + pub vui_parameters_present_flag: bool, /// The vui_parameters() data. - vui_parameters: VuiParams, + pub vui_parameters: VuiParams, /// When set, specifies that the syntax elements sps_range_extension_flag, /// sps_multilayer_extension_flag, sps_3d_extension_flag, /// sps_scc_extension_flag, and sps_extension_4bits are present in the SPS /// RBSP syntax structure. When not set, specifies that these syntax /// elements are not present. - extension_present_flag: bool, + pub extension_present_flag: bool, - range_extension_flag: bool, + pub range_extension_flag: bool, /// The sps_range_extension() data. pub range_extension: SpsRangeExtension, /// When set, specifies that the sps_scc_extension( ) syntax structure is /// present in the SPS RBSP syntax structure. When not set, specifies that /// this syntax structure is not present - scc_extension_flag: bool, + pub scc_extension_flag: bool, /// The sps_scc_extension() data. pub scc_extension: SpsSccExtension, // Internal H265 variables. Computed from the bitstream. /// Equivalent to MinCbLog2SizeY in the specification. - min_cb_log2_size_y: u32, + pub min_cb_log2_size_y: u32, /// Equivalent to CtbLog2SizeY in the specification. - ctb_log2_size_y: u32, + pub ctb_log2_size_y: u32, /// Equivalent to CtbSizeY in the specification. - ctb_size_y: u32, + pub ctb_size_y: u32, /// Equivalent to PicHeightInCtbsY in the specification. - pic_height_in_ctbs_y: u32, + pub pic_height_in_ctbs_y: u32, /// Equivalent to PicWidthInCtbsY in the specification. - pic_width_in_ctbs_y: u32, + pub pic_width_in_ctbs_y: u32, /// Equivalent to PicSizeInCtbsY in the specification. - pic_size_in_ctbs_y: u32, + pub pic_size_in_ctbs_y: u32, /// Equivalent to ChromaArrayType in the specification. - chroma_array_type: u8, + pub chroma_array_type: u8, /// Equivalent to WpOffsetHalfRangeY in the specification. - wp_offset_half_range_y: u32, + pub wp_offset_half_range_y: u32, /// Equivalent to WpOffsetHalfRangeC in the specification. pub wp_offset_half_range_c: u32, /// Equivalent to MaxTbLog2SizeY in the specification. - max_tb_log2_size_y: u32, + pub max_tb_log2_size_y: u32, /// Equivalent to PicSizeInSamplesY in the specification. - pic_size_in_samples_y: u32, + pub pic_size_in_samples_y: u32, } impl Sps { @@ -1123,7 +1123,7 @@ pub struct Pps { /// are not distributed uniformly across the picture but signalled /// explicitly using the syntax elements `column_width_minus1[ i ]` and /// `row_height_minus1[ i ]`. - uniform_spacing_flag: bool, + pub uniform_spacing_flag: bool, /// `column_width_minus1[ i ]` plus 1 specifies the width of the i-th tile /// column in units of CTBs. pub column_width_minus1: [u32; 19], @@ -1147,7 +1147,7 @@ pub struct Pps { /// When set, specifies the presence of deblocking filter control syntax /// elements in the PPS. When not set, specifies the absence of deblocking /// filter control syntax elements in the PPS. - deblocking_filter_control_present_flag: bool, + pub deblocking_filter_control_present_flag: bool, /// When set, specifies the presence of deblocking_filter_override_flag in /// the slice headers for pictures referring to the PPS. When not set, /// specifies the absence of deblocking_filter_override_flag in the slice @@ -1203,11 +1203,11 @@ pub struct Pps { /// pps_scc_extension_flag, and pps_extension_4bits are present in the /// picture parameter set RBSP syntax structure. When not set, specifies /// that these syntax elements are not present. - extension_present_flag: bool, + pub extension_present_flag: bool, /// When setspecifies that the pps_range_extension( ) syntax structure is /// present in the PPS RBSP syntax structure. When not set, specifies that /// this syntax structure is not present. - range_extension_flag: bool, + pub range_extension_flag: bool, /// The range extension data. pub range_extension: PpsRangeExtension, @@ -1217,7 +1217,7 @@ pub struct Pps { // Internal variables. /// Equivalent to QpBdOffsetY in the specification. - qp_bd_offset_y: u32, + pub qp_bd_offset_y: u32, /// The nuh_temporal_id_plus1 - 1 of the associated NALU. pub temporal_id: u8, @@ -1276,49 +1276,22 @@ impl Default for Pps { } } -// TODO #[derive(Clone, Debug, PartialEq, Eq)] pub struct ScalingLists { /// plus 8 specifies the value of the variable `ScalingFactor[ 2 ][ matrixId /// ] [ 0 ][ 0 ]` for the scaling list for the 16x16 size. - scaling_list_dc_coef_minus8_16x16: [i16; 6], + pub scaling_list_dc_coef_minus8_16x16: [i16; 6], /// plus 8 specifies the value of the variable `ScalingFactor[ 3 ][ matrixId /// ][ 0 ][ 0 ]` for the scaling list for the 32x32 size. - scaling_list_dc_coef_minus8_32x32: [i16; 6], + pub scaling_list_dc_coef_minus8_32x32: [i16; 6], /// The 4x4 scaling list. - scaling_list_4x4: [[u8; 16]; 6], + pub scaling_list_4x4: [[u8; 16]; 6], /// The 8x8 scaling list. - scaling_list_8x8: [[u8; 64]; 6], + pub scaling_list_8x8: [[u8; 64]; 6], /// The 16x16 scaling list. - scaling_list_16x16: [[u8; 64]; 6], + pub scaling_list_16x16: [[u8; 64]; 6], /// The 32x32 scaling list. - scaling_list_32x32: [[u8; 64]; 6], -} - -impl ScalingLists { - pub fn scaling_list_dc_coef_minus8_16x16(&self) -> [i16; 6] { - self.scaling_list_dc_coef_minus8_16x16 - } - - pub fn scaling_list_dc_coef_minus8_32x32(&self) -> [i16; 6] { - self.scaling_list_dc_coef_minus8_32x32 - } - - pub fn scaling_list_4x4(&self) -> [[u8; 16]; 6] { - self.scaling_list_4x4 - } - - pub fn scaling_list_8x8(&self) -> [[u8; 64]; 6] { - self.scaling_list_8x8 - } - - pub fn scaling_list_16x16(&self) -> [[u8; 64]; 6] { - self.scaling_list_16x16 - } - - pub fn scaling_list_32x32(&self) -> [[u8; 64]; 6] { - self.scaling_list_32x32 - } + pub scaling_list_32x32: [[u8; 64]; 6], } impl Default for ScalingLists { @@ -1334,78 +1307,58 @@ impl Default for ScalingLists { } } -// TODO #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct RefPicListModification { /// Whenset, indicates that reference picture list 0 is specified explicitly /// by a list of `list_entry_l0[ i ]` values. When not set, indicates that /// reference picture list 0 is determined implicitly. - ref_pic_list_modification_flag_l0: bool, + pub ref_pic_list_modification_flag_l0: bool, /// `list_entry_l0[ i ]` specifies the index of the reference picture in /// RefPicListTemp0 to be placed at the current position of reference /// picture list 0. - list_entry_l0: Vec, + pub list_entry_l0: Vec, /// Whenset, indicates that reference picture list 1 is specified explicitly /// by a list of `list_entry_l1[ i ]` values. When not set, indicates that /// reference picture list 1 is determined implicitly. - ref_pic_list_modification_flag_l1: bool, + pub ref_pic_list_modification_flag_l1: bool, /// `list_entry_l1[ i ]` specifies the index of the reference picture in /// RefPicListTemp1 to be placed at the current position of reference /// picture list 1. - list_entry_l1: Vec, + pub list_entry_l1: Vec, } -impl RefPicListModification { - pub fn ref_pic_list_modification_flag_l0(&self) -> bool { - self.ref_pic_list_modification_flag_l0 - } - - pub fn list_entry_l0(&self) -> &[u32] { - self.list_entry_l0.as_ref() - } - - pub fn ref_pic_list_modification_flag_l1(&self) -> bool { - self.ref_pic_list_modification_flag_l1 - } - - pub fn list_entry_l1(&self) -> &[u32] { - self.list_entry_l1.as_ref() - } -} - -// TODO #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct PredWeightTable { /// The base 2 logarithm of the denominator for all luma weighting factors. - luma_log2_weight_denom: u8, + pub luma_log2_weight_denom: u8, /// The difference of the base 2 logarithm of the denominator for all chroma /// weighting factors. - delta_chroma_log2_weight_denom: i8, + pub delta_chroma_log2_weight_denom: i8, /// `luma_weight_l0_flag[ i ]` set specifies that weighting factors for the /// luma component of list 0 prediction using `RefPicList0[ i ]` are present. /// `luma_weight_l0_flag[ i ]` not set specifies that these weighting factors /// are not present. - luma_weight_l0_flag: [bool; 15], + pub luma_weight_l0_flag: [bool; 15], /// `chroma_weight_l0_flag[ i ]` set specifies that weighting factors for the /// chroma prediction values of list 0 prediction using `RefPicList0[ i ]` are /// present. `chroma_weight_l0_flag[ i ]` not set specifies that these /// weighting factors are not present. - chroma_weight_l0_flag: [bool; 15], + pub chroma_weight_l0_flag: [bool; 15], /// `delta_luma_weight_l0[ i ]` is the difference of the weighting factor /// applied to the luma prediction value for list 0 prediction using /// `RefPicList0[ i ]`. - delta_luma_weight_l0: [i8; 15], + pub delta_luma_weight_l0: [i8; 15], /// `luma_offset_l0[ i ]` is the additive offset applied to the luma /// prediction value for list 0 prediction using `RefPicList0[ i ]`. - luma_offset_l0: [i8; 15], + pub luma_offset_l0: [i8; 15], /// `delta_chroma_weight_l0[ i ][ j ]` is the difference of the weighting /// factor applied to the chroma prediction values for list 0 prediction /// using `RefPicList0[ i ]` with j equal to 0 for Cb and j equal to 1 for Cr. - delta_chroma_weight_l0: [[i8; 2]; 15], + pub delta_chroma_weight_l0: [[i8; 2]; 15], /// `delta_chroma_offset_l0[ i ][ j ]` is the difference of the additive /// offset applied to the chroma prediction values for list 0 prediction /// using `RefPicList0[ i ]` with j equal to 0 for Cb and j equal to 1 for Cr. - delta_chroma_offset_l0: [[i16; 2]; 15], + pub delta_chroma_offset_l0: [[i16; 2]; 15], // `luma_weight_l1_flag[ i ]`, `chroma_weight_l1_flag[ i ]`, // `delta_luma_weight_l1[ i ]`, `luma_offset_l1[ i ]`, delta_chroma_weight_l1[ i @@ -1414,162 +1367,53 @@ pub struct PredWeightTable { // `delta_luma_weight_l0[ i ]`, `luma_offset_l0[ i ]`, `delta_chroma_weight_l0[ i // ][ j ]` and `delta_chroma_offset_l0[ i ][ j ]`, respectively, with `l0`, `L0`, // `list 0` and `List0` replaced by `l1`, `L1`, `list 1` and `List1`, respectively. - luma_weight_l1_flag: [bool; 15], - chroma_weight_l1_flag: [bool; 15], - delta_luma_weight_l1: [i8; 15], - luma_offset_l1: [i8; 15], + pub luma_weight_l1_flag: [bool; 15], + pub chroma_weight_l1_flag: [bool; 15], + pub delta_luma_weight_l1: [i8; 15], + pub luma_offset_l1: [i8; 15], - delta_chroma_weight_l1: [[i8; 2]; 15], - delta_chroma_offset_l1: [[i16; 2]; 15], + pub delta_chroma_weight_l1: [[i8; 2]; 15], + pub delta_chroma_offset_l1: [[i16; 2]; 15], // Calculated. /// Same as ChromaLog2WeightDenom in the specification. - chroma_log2_weight_denom: u8, + pub chroma_log2_weight_denom: u8, } -impl PredWeightTable { - pub fn luma_log2_weight_denom(&self) -> u8 { - self.luma_log2_weight_denom - } - - pub fn delta_chroma_log2_weight_denom(&self) -> i8 { - self.delta_chroma_log2_weight_denom - } - - pub fn luma_weight_l0_flag(&self) -> [bool; 15] { - self.luma_weight_l0_flag - } - - pub fn chroma_weight_l0_flag(&self) -> [bool; 15] { - self.chroma_weight_l0_flag - } - - pub fn delta_luma_weight_l0(&self) -> [i8; 15] { - self.delta_luma_weight_l0 - } - - pub fn luma_offset_l0(&self) -> [i8; 15] { - self.luma_offset_l0 - } - - pub fn delta_chroma_weight_l0(&self) -> [[i8; 2]; 15] { - self.delta_chroma_weight_l0 - } - - pub fn delta_chroma_offset_l0(&self) -> [[i16; 2]; 15] { - self.delta_chroma_offset_l0 - } - - pub fn luma_weight_l1_flag(&self) -> [bool; 15] { - self.luma_weight_l1_flag - } - - pub fn chroma_weight_l1_flag(&self) -> [bool; 15] { - self.chroma_weight_l1_flag - } - - pub fn delta_luma_weight_l1(&self) -> [i8; 15] { - self.delta_luma_weight_l1 - } - - pub fn luma_offset_l1(&self) -> [i8; 15] { - self.luma_offset_l1 - } - - pub fn delta_chroma_weight_l1(&self) -> [[i8; 2]; 15] { - self.delta_chroma_weight_l1 - } - - pub fn delta_chroma_offset_l1(&self) -> [[i16; 2]; 15] { - self.delta_chroma_offset_l1 - } - - pub fn chroma_log2_weight_denom(&self) -> u8 { - self.chroma_log2_weight_denom - } -} - -// TODO #[derive(Clone, Debug, PartialEq, Eq)] pub struct ShortTermRefPicSet { /// When set, specifies that the stRpsIdx-th candidate short-term RPS is /// predicted from another candidate short-term RPS, which is referred to as /// the source candidate short-term RPS. - inter_ref_pic_set_prediction_flag: bool, + pub inter_ref_pic_set_prediction_flag: bool, /// delta_idx_minus1 plus 1 specifies the difference between the value of /// stRpsIdx and the index, into the list of the candidate short-term RPSs /// specified in the SPS, of the source candidate short-term RPS. - delta_idx_minus1: u8, + pub delta_idx_minus1: u8, /// delta_rps_sign and abs_delta_rps_minus1 together specify the value of /// the variable deltaRps. - delta_rps_sign: bool, + pub delta_rps_sign: bool, /// delta_rps_sign and abs_delta_rps_minus1 together specify the value of /// the variable deltaRps. - abs_delta_rps_minus1: u16, + pub abs_delta_rps_minus1: u16, /// specifies the number of entries in the stRpsIdx-th candidate short-term /// RPS that have picture order count values less than the picture order /// count value of the current picture. - num_negative_pics: u8, + pub num_negative_pics: u8, /// specifies the number of entries in the stRpsIdx-th candidate short-term /// RPS that have picture order count values greater than the picture order /// count value of the current picture. - num_positive_pics: u8, + pub num_positive_pics: u8, /// Same as UsedByCurrPicS0 in the specification. - used_by_curr_pic_s0: [bool; MAX_SHORT_TERM_REF_PIC_SETS], + pub used_by_curr_pic_s0: [bool; MAX_SHORT_TERM_REF_PIC_SETS], /// Same as UsedByCurrPicS1 in the specification. - used_by_curr_pic_s1: [bool; MAX_SHORT_TERM_REF_PIC_SETS], + pub used_by_curr_pic_s1: [bool; MAX_SHORT_TERM_REF_PIC_SETS], /// Same as DeltaPocS0 in the specification. - delta_poc_s0: [i32; MAX_SHORT_TERM_REF_PIC_SETS], + pub delta_poc_s0: [i32; MAX_SHORT_TERM_REF_PIC_SETS], /// Same as DeltaPocS1 in the specification. - delta_poc_s1: [i32; MAX_SHORT_TERM_REF_PIC_SETS], + pub delta_poc_s1: [i32; MAX_SHORT_TERM_REF_PIC_SETS], /// Same as NumDeltaPocs in the specification. - num_delta_pocs: u32, -} - -impl ShortTermRefPicSet { - pub fn inter_ref_pic_set_prediction_flag(&self) -> bool { - self.inter_ref_pic_set_prediction_flag - } - - pub fn delta_idx_minus1(&self) -> u8 { - self.delta_idx_minus1 - } - - pub fn delta_rps_sign(&self) -> bool { - self.delta_rps_sign - } - - pub fn abs_delta_rps_minus1(&self) -> u16 { - self.abs_delta_rps_minus1 - } - - pub fn num_negative_pics(&self) -> u8 { - self.num_negative_pics - } - - pub fn num_positive_pics(&self) -> u8 { - self.num_positive_pics - } - - pub fn used_by_curr_pic_s0(&self) -> [bool; MAX_SHORT_TERM_REF_PIC_SETS] { - self.used_by_curr_pic_s0 - } - - pub fn used_by_curr_pic_s1(&self) -> [bool; MAX_SHORT_TERM_REF_PIC_SETS] { - self.used_by_curr_pic_s1 - } - - pub fn delta_poc_s0(&self) -> [i32; MAX_SHORT_TERM_REF_PIC_SETS] { - self.delta_poc_s0 - } - - pub fn delta_poc_s1(&self) -> [i32; MAX_SHORT_TERM_REF_PIC_SETS] { - self.delta_poc_s1 - } - - pub fn num_delta_pocs(&self) -> u32 { - self.num_delta_pocs - } + pub num_delta_pocs: u32, } impl Default for ShortTermRefPicSet { @@ -1590,7 +1434,6 @@ impl Default for ShortTermRefPicSet { } } -// TODO #[derive(N, Clone, Copy, Debug, PartialEq, Eq)] /// See table 7-7 in the specification. pub enum SliceType { @@ -1622,40 +1465,39 @@ impl Default for SliceType { } } -// TODO #[derive(Clone, Debug, PartialEq, Eq)] pub struct SliceHeader { /// When set, specifies that the slice segment is the first slice segment of /// the picture in decoding order. When not set, specifies that the slice /// segment is not the first slice segment of the picture in decoding order. - first_slice_segment_in_pic_flag: bool, + pub first_slice_segment_in_pic_flag: bool, /// Affects the output of previously-decoded pictures in the decoded picture /// buffer after the decoding of an IDR or a BLA picture that is not the /// first picture in the bitstream as specified in Annex C. - no_output_of_prior_pics_flag: bool, + pub no_output_of_prior_pics_flag: bool, /// Specifies the value of pps_pic_parameter_set_id for the PPS in use. - pic_parameter_set_id: u8, + pub pic_parameter_set_id: u8, /// When set, specifies that the value of each slice segment header syntax /// element that is not present is inferred to be equal to the value of the /// corresponding slice segment header syntax element in the slice header. - dependent_slice_segment_flag: bool, + pub dependent_slice_segment_flag: bool, /// Specifies the address of the first CTB in the slice segment, in CTB /// raster scan of a picture. - segment_address: u32, + pub segment_address: u32, /// Specifies the coding type of the slice according to Table 7-7. - type_: SliceType, + pub type_: SliceType, /// Affects the decoded picture output and removal processes as specified in /// Annex C. - pic_output_flag: bool, + pub pic_output_flag: bool, /// Specifies the colour plane associated with the current slice RBSP when /// separate_colour_plane_flag is set. The value of colour_plane_id shall be /// in the range of 0 to 2, inclusive. colour_plane_id values 0, 1 and 2 /// correspond to the Y, Cb and Cr planes, respectively. - colour_plane_id: u8, + pub colour_plane_id: u8, /// Specifies the picture order count modulo MaxPicOrderCntLsb for the /// current picture. The length of the slice_pic_order_cnt_lsb syntax /// element is log2_max_pic_order_cnt_lsb_minus4 + 4 bits. - pic_order_cnt_lsb: u16, + pub pic_order_cnt_lsb: u16, /// When set, specifies that the short-term RPS of the current picture is /// derived based on one of the st_ref_pic_set( ) syntax structures in the /// active SPS that is identified by the syntax element @@ -1663,373 +1505,155 @@ pub struct SliceHeader { /// that the short-term RPS of the current picture is derived based on the /// st_ref_pic_set( ) syntax structure that is directly included in the /// slice headers of the current picture. - short_term_ref_pic_set_sps_flag: bool, + pub short_term_ref_pic_set_sps_flag: bool, /// The st_ref_pic_set() data. - short_term_ref_pic_set: ShortTermRefPicSet, + pub short_term_ref_pic_set: ShortTermRefPicSet, /// Specifies the index, into the list of the st_ref_pic_set( ) syntax /// structures included in the active SPS, of the st_ref_pic_set( ) syntax /// structure that is used for derivation of the short-term RPS of the /// current picture. - short_term_ref_pic_set_idx: u8, + pub short_term_ref_pic_set_idx: u8, /// Specifies the number of entries in the long-term RPS of the current /// picture that are derived based on the candidate long-term reference /// pictures specified in the active SPS. - num_long_term_sps: u8, + pub num_long_term_sps: u8, /// Specifies the number of entries in the long-term RPS of the current /// picture that are directly signalled in the slice header. - num_long_term_pics: u8, + pub num_long_term_pics: u8, /// `lt_idx_sps[ i ]` specifies an index, into the list of candidate long-term /// reference pictures specified in the active SPS, of the i-th entry in the /// long-term RPS of the current picture. - lt_idx_sps: [u8; 16], + pub lt_idx_sps: [u8; 16], /// Same as PocLsbLt in the specification. - poc_lsb_lt: [u32; 16], + pub poc_lsb_lt: [u32; 16], /// Same as UsedByCurrPicLt in the specification. - used_by_curr_pic_lt: [bool; 16], + pub used_by_curr_pic_lt: [bool; 16], /// When set, specifies that that `delta_poc_msb_cycle_lt[i]` is present. - delta_poc_msb_present_flag: [bool; 16], + pub delta_poc_msb_present_flag: [bool; 16], /// Same as DeltaPocMsbCycleLt in the specification. - delta_poc_msb_cycle_lt: [u32; 16], + pub delta_poc_msb_cycle_lt: [u32; 16], /// Specifies whether temporal motion vector predictors can be used for /// inter prediction. If slice_temporal_mvp_enabled_flag is not set, the /// syntax elements of the current picture shall be constrained such that no /// temporal motion vector predictor is used in decoding of the current /// picture. Otherwise (slice_temporal_mvp_enabled_flag is set), temporal /// motion vector predictors may be used in decoding of the current picture. - temporal_mvp_enabled_flag: bool, + pub temporal_mvp_enabled_flag: bool, /// When set, specifies that SAO is enabled for the luma component in the /// current slice; slice_sao_luma_flag not set specifies that SAO is /// disabled for the luma component in the current slice. - sao_luma_flag: bool, + pub sao_luma_flag: bool, /// When set, specifies that SAO is enabled for the chroma component in the /// current slice; When not set, specifies that SAO is disabled for the /// chroma component in the current slice. - sao_chroma_flag: bool, + pub sao_chroma_flag: bool, /// When set, specifies that the syntax element num_ref_idx_l0_active_minus1 /// is present for P and B slices and that the syntax element /// num_ref_idx_l1_active_minus1 is present for B slices. When not set, /// specifies that the syntax elements num_ref_idx_l0_active_minus1 and /// num_ref_idx_l1_active_minus1 are not present. - num_ref_idx_active_override_flag: bool, + pub num_ref_idx_active_override_flag: bool, /// Specifies the maximum reference index for /// reference picture list 0 that may be used to decode the slice. - num_ref_idx_l0_active_minus1: u8, + pub num_ref_idx_l0_active_minus1: u8, /// Specifies the maximum reference index for reference picture list 1 that /// may be used to decode the slice. - num_ref_idx_l1_active_minus1: u8, + pub num_ref_idx_l1_active_minus1: u8, /// The RefPicListModification data. - ref_pic_list_modification: RefPicListModification, + pub ref_pic_list_modification: RefPicListModification, /// When set, indicates that the mvd_coding( x0, y0, 1 ) syntax structure is /// not parsed and `MvdL1[ x0 ]`[ y0 `][ compIdx ]` is set equal to 0 for /// compIdx = 0..1. When not set, indicates that the mvd_coding( x0, y0, 1 ) /// syntax structure is parsed. - mvd_l1_zero_flag: bool, + pub mvd_l1_zero_flag: bool, /// Specifies the method for determining the initialization table used in /// the initialization process for context variables. - cabac_init_flag: bool, + pub cabac_init_flag: bool, /// When set, specifies that the collocated picture used for temporal motion /// vector prediction is derived from reference picture list 0. When not /// set, specifies that the collocated picture used for temporal motion /// vector prediction is derived from reference picture list 1. - collocated_from_l0_flag: bool, + pub collocated_from_l0_flag: bool, /// Specifies the reference index of the collocated picture used for /// temporal motion vector prediction. - collocated_ref_idx: u8, + pub collocated_ref_idx: u8, /// The PredWeightTable data. - pred_weight_table: PredWeightTable, + pub pred_weight_table: PredWeightTable, /// Specifies the maximum number of merging motion vector prediction (MVP) /// candidates supported in the slice subtracted from 5. - five_minus_max_num_merge_cand: u8, + pub five_minus_max_num_merge_cand: u8, /// Specifies that the resolution of motion vectors for inter prediction in /// the current slice is integer. When not set, specifies /// that the resolution of motion vectors for inter prediction in the /// current slice that refer to pictures other than the current picture is /// fractional with quarter-sample precision in units of luma samples. - use_integer_mv_flag: bool, + pub use_integer_mv_flag: bool, /// Specifies the initial value of QpY to be used for the coding blocks in /// the slice until modified by the value of CuQpDeltaVal in the coding unit /// layer. - qp_delta: i8, + pub qp_delta: i8, /// Specifies a difference to be added to the value of pps_cb_qp_offset when /// determining the value of the Qp′Cb quantization parameter. - cb_qp_offset: i8, + pub cb_qp_offset: i8, /// Specifies a difference to be added to the value of pps_cb_qr_offset when /// determining the value of the Qp′Cr quantization parameter. - cr_qp_offset: i8, + pub cr_qp_offset: i8, /// Specifies offsets to the quantization parameter values qP derived in /// clause 8.6.2 for luma, Cb, and Cr components, respectively. - slice_act_y_qp_offset: i8, + pub slice_act_y_qp_offset: i8, /// Specifies offsets to the quantization parameter values qP derived in /// clause 8.6.2 for luma, Cb, and Cr components, respectively. - slice_act_cb_qp_offset: i8, + pub slice_act_cb_qp_offset: i8, /// Specifies offsets to the quantization parameter values qP derived in /// clause 8.6.2 for luma, Cb, and Cr components, respectively. - slice_act_cr_qp_offset: i8, + pub slice_act_cr_qp_offset: i8, /// When set, specifies that the cu_chroma_qp_offset_flag may be present in /// the transform unit syntax. When not set, specifies that the /// cu_chroma_qp_offset_flag is not present in the transform unit syntax. - cu_chroma_qp_offset_enabled_flag: bool, + pub cu_chroma_qp_offset_enabled_flag: bool, /// When set, specifies that deblocking parameters are present in the slice /// header. When not set, specifies that deblocking parameters are not /// present in the slice header. - deblocking_filter_override_flag: bool, + pub deblocking_filter_override_flag: bool, /// When set, specifies that the operation of the deblocking filter is not /// applied for the current slice. When not set, specifies that the /// operation of the deblocking filter is applied for the current slice. - deblocking_filter_disabled_flag: bool, + pub deblocking_filter_disabled_flag: bool, /// Specifies the deblocking parameter offsets for β and tC (divided by 2) /// for the current slice. - beta_offset_div2: i8, + pub beta_offset_div2: i8, /// Specifies the deblocking parameter offsets for β and tC (divided by 2) /// for the current slice. - tc_offset_div2: i8, + pub tc_offset_div2: i8, /// When set, specifies that in-loop filtering operations may be performed /// across the left and upper boundaries of the current slice. When not /// set, specifies that in-loop operations are not performed across left and /// upper boundaries of the current slice. The in-loop filtering operations /// include the deblocking filter and sample adaptive offset filter. - loop_filter_across_slices_enabled_flag: bool, + pub loop_filter_across_slices_enabled_flag: bool, /// Specifies the number of `entry_point_offset_minus1[ i ]` syntax elements /// in the slice header. - num_entry_point_offsets: u32, + pub num_entry_point_offsets: u32, /// offset_len_minus1 plus 1 specifies the length, in bits, of the /// `entry_point_offset_minus1[ i ]` syntax elements. - offset_len_minus1: u8, + pub offset_len_minus1: u8, /// `entry_point_offset_minus1[ i ]` plus 1 specifies the i-th entry point /// offset in bytes, and is represented by offset_len_minus1 plus 1 bits. /// The slice segment data that follow the slice segment header consists of /// num_entry_point_offsets + 1 subsets, with subset index values ranging /// from 0 to num_entry_point_offsets, inclusive. See the specification for /// more details. - entry_point_offset_minus1: [u32; 32], + pub entry_point_offset_minus1: [u32; 32], /// Same as NumPicTotalCurr in the specification. - num_pic_total_curr: u32, + pub num_pic_total_curr: u32, // Size of slice_header() in bits. - header_bit_size: u32, + pub header_bit_size: u32, // Number of emulation prevention bytes (EPB) in this slice_header(). - n_emulation_prevention_bytes: u32, + pub n_emulation_prevention_bytes: u32, /// Same as CurrRpsIdx in the specification. - curr_rps_idx: u8, + pub curr_rps_idx: u8, /// Number of bits taken by st_ref_pic_set minus Emulation Prevention Bytes. - st_rps_bits: u32, -} - -impl SliceHeader { - pub fn first_slice_segment_in_pic_flag(&self) -> bool { - self.first_slice_segment_in_pic_flag - } - - pub fn no_output_of_prior_pics_flag(&self) -> bool { - self.no_output_of_prior_pics_flag - } - - pub fn pic_parameter_set_id(&self) -> u8 { - self.pic_parameter_set_id - } - - pub fn dependent_slice_segment_flag(&self) -> bool { - self.dependent_slice_segment_flag - } - - pub fn segment_address(&self) -> u32 { - self.segment_address - } - - pub fn type_(&self) -> SliceType { - self.type_ - } - - pub fn pic_output_flag(&self) -> bool { - self.pic_output_flag - } - - pub fn colour_plane_id(&self) -> u8 { - self.colour_plane_id - } - - pub fn pic_order_cnt_lsb(&self) -> u16 { - self.pic_order_cnt_lsb - } - - pub fn short_term_ref_pic_set_sps_flag(&self) -> bool { - self.short_term_ref_pic_set_sps_flag - } - - pub fn short_term_ref_pic_sets(&self) -> &ShortTermRefPicSet { - &self.short_term_ref_pic_set - } - - pub fn short_term_ref_pic_set_idx(&self) -> u8 { - self.short_term_ref_pic_set_idx - } - - pub fn num_long_term_sps(&self) -> u8 { - self.num_long_term_sps - } - - pub fn num_long_term_pics(&self) -> u8 { - self.num_long_term_pics - } - - pub fn lt_idx_sps(&self) -> [u8; 16] { - self.lt_idx_sps - } - - pub fn poc_lsb_lt(&self) -> [u32; 16] { - self.poc_lsb_lt - } - - pub fn used_by_curr_pic_lt(&self) -> [bool; 16] { - self.used_by_curr_pic_lt - } - - pub fn delta_poc_msb_present_flag(&self) -> [bool; 16] { - self.delta_poc_msb_present_flag - } - - pub fn delta_poc_msb_cycle_lt(&self) -> [u32; 16] { - self.delta_poc_msb_cycle_lt - } - - pub fn temporal_mvp_enabled_flag(&self) -> bool { - self.temporal_mvp_enabled_flag - } - - pub fn sao_luma_flag(&self) -> bool { - self.sao_luma_flag - } - - pub fn sao_chroma_flag(&self) -> bool { - self.sao_chroma_flag - } - - pub fn num_ref_idx_active_override_flag(&self) -> bool { - self.num_ref_idx_active_override_flag - } - - pub fn num_ref_idx_l0_active_minus1(&self) -> u8 { - self.num_ref_idx_l0_active_minus1 - } - - pub fn num_ref_idx_l1_active_minus1(&self) -> u8 { - self.num_ref_idx_l1_active_minus1 - } - - pub fn ref_pic_list_modification(&self) -> &RefPicListModification { - &self.ref_pic_list_modification - } - - pub fn mvd_l1_zero_flag(&self) -> bool { - self.mvd_l1_zero_flag - } - - pub fn cabac_init_flag(&self) -> bool { - self.cabac_init_flag - } - - pub fn collocated_from_l0_flag(&self) -> bool { - self.collocated_from_l0_flag - } - - pub fn collocated_ref_idx(&self) -> u8 { - self.collocated_ref_idx - } - - pub fn pred_weight_table(&self) -> &PredWeightTable { - &self.pred_weight_table - } - - pub fn five_minus_max_num_merge_cand(&self) -> u8 { - self.five_minus_max_num_merge_cand - } - - pub fn use_integer_mv_flag(&self) -> bool { - self.use_integer_mv_flag - } - - pub fn qp_delta(&self) -> i8 { - self.qp_delta - } - - pub fn cb_qp_offset(&self) -> i8 { - self.cb_qp_offset - } - - pub fn cr_qp_offset(&self) -> i8 { - self.cr_qp_offset - } - - pub fn slice_act_y_qp_offset(&self) -> i8 { - self.slice_act_y_qp_offset - } - - pub fn slice_act_cb_qp_offset(&self) -> i8 { - self.slice_act_cb_qp_offset - } - - pub fn slice_act_cr_qp_offset(&self) -> i8 { - self.slice_act_cr_qp_offset - } - - pub fn cu_chroma_qp_offset_enabled_flag(&self) -> bool { - self.cu_chroma_qp_offset_enabled_flag - } - - pub fn deblocking_filter_override_flag(&self) -> bool { - self.deblocking_filter_override_flag - } - - pub fn deblocking_filter_disabled_flag(&self) -> bool { - self.deblocking_filter_disabled_flag - } - - pub fn beta_offset_div2(&self) -> i8 { - self.beta_offset_div2 - } - - pub fn tc_offset_div2(&self) -> i8 { - self.tc_offset_div2 - } - - pub fn loop_filter_across_slices_enabled_flag(&self) -> bool { - self.loop_filter_across_slices_enabled_flag - } - - pub fn num_entry_point_offsets(&self) -> u32 { - self.num_entry_point_offsets - } - - pub fn offset_len_minus1(&self) -> u8 { - self.offset_len_minus1 - } - - pub fn entry_point_offset_minus1(&self) -> [u32; 32] { - self.entry_point_offset_minus1 - } - - pub fn num_pic_total_curr(&self) -> u32 { - self.num_pic_total_curr - } - - pub fn header_bit_size(&self) -> u32 { - self.header_bit_size - } - - pub fn n_emulation_prevention_bytes(&self) -> u32 { - self.n_emulation_prevention_bytes - } - - pub fn curr_rps_idx(&self) -> u8 { - self.curr_rps_idx - } - - pub fn short_term_ref_pic_set(&self) -> &ShortTermRefPicSet { - &self.short_term_ref_pic_set - } - - pub fn st_rps_bits(&self) -> u32 { - self.st_rps_bits - } + pub st_rps_bits: u32, } impl Default for SliceHeader { @@ -2096,22 +1720,12 @@ impl Default for SliceHeader { /// consecutively in the raster scan within a particular slice group pub struct Slice<'a> { /// The slice header. - header: SliceHeader, + pub header: SliceHeader, /// The NAL unit backing this slice. - nalu: Nalu<'a>, + pub nalu: Nalu<'a>, } impl<'a> Slice<'a> { - /// Get a reference to the slice's header. - pub fn header(&self) -> &SliceHeader { - &self.header - } - - /// Get a reference to the slice's nalu. - pub fn nalu(&self) -> &Nalu { - &self.nalu - } - /// Sets the header for dependent slices by copying from an independent /// slice. pub fn replace_header(&mut self, header: SliceHeader) -> anyhow::Result<()> { @@ -2154,7 +1768,6 @@ impl<'a> Slice<'a> { } } -// TODO #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct SublayerHrdParameters { // NOTE: The value of CpbCnt is cpb_cnt_minus1[i] + 1, and cpb_cnt_minus1 @@ -2162,69 +1775,50 @@ pub struct SublayerHrdParameters { /// `bit_rate_value_minus1[ i ]` (together with bit_rate_scale) specifies the /// maximum input bit rate for the i-th CPB when the CPB operates at the /// access unit level - bit_rate_value_minus1: [u32; 32], + pub bit_rate_value_minus1: [u32; 32], /// `cpb_size_value_minus1[ i ]` is used together with cpb_size_scale to /// specify the i-th CPB size when the CPB operates at the access unit /// level. - cpb_size_value_minus1: [u32; 32], + pub cpb_size_value_minus1: [u32; 32], /// `cpb_size_du_value_minus1[ i ]` is used together with cpb_size_du_scale to /// specify the i-th CPB size when the CPB operates at sub-picture level. - cpb_size_du_value_minus1: [u32; 32], + pub cpb_size_du_value_minus1: [u32; 32], /// `bit_rate_du_value_minus1[ i ]` (together with bit_rate_scale) specifies /// the maximum input bit rate for the i-th CPB when the CPB operates at the /// sub-picture level. - bit_rate_du_value_minus1: [u32; 32], + pub bit_rate_du_value_minus1: [u32; 32], /// `cbr_flag[ i ]` not set specifies that to decode this CVS by the HRD using /// the i-th CPB specification. - cbr_flag: [bool; 32], + pub cbr_flag: [bool; 32], } -impl SublayerHrdParameters { - pub fn cpb_size_value_minus1(&self) -> [u32; 32] { - self.cpb_size_value_minus1 - } - - pub fn cpb_size_du_value_minus1(&self) -> [u32; 32] { - self.cpb_size_du_value_minus1 - } - - pub fn bit_rate_du_value_minus1(&self) -> [u32; 32] { - self.bit_rate_du_value_minus1 - } - - pub fn cbr_flag(&self) -> [bool; 32] { - self.cbr_flag - } -} - -// TODO #[derive(Clone, Debug, PartialEq, Eq)] pub struct HrdParams { /// When set, specifies that NAL HRD parameters (pertaining to the Type II /// bitstream conformance point) are present in the hrd_parameters( ) syntax /// structure. When not set, specifies that NAL HRD parameters are not /// present in the hrd_parameters( ) syntax structure. - nal_hrd_parameters_present_flag: bool, + pub nal_hrd_parameters_present_flag: bool, /// When set, specifies that VCL HRD parameters (pertaining to the Type I /// bitstream conformance point) are present in the hrd_parameters( ) syntax /// structure. When not set, specifies that VCL HRD parameters are not /// present in the hrd_parameters( ) syntax structure. - vcl_hrd_parameters_present_flag: bool, + pub vcl_hrd_parameters_present_flag: bool, /// When set, specifies that sub-picture level HRD parameters are present /// and the HRD may operate at access unit level or sub-picture level. When /// not set, specifies that sub-picture level HRD parameters are not present /// and the HRD operates at access unit level. - sub_pic_hrd_params_present_flag: bool, + pub sub_pic_hrd_params_present_flag: bool, /// Used to specify the clock sub-tick. A clock sub-tick is the minimum /// interval of time that can be represented in the coded data when /// sub_pic_hrd_params_present_flag is set. - tick_divisor_minus2: u8, + pub tick_divisor_minus2: u8, /// du_cpb_removal_delay_increment_length_minus1 plus 1 specifies the /// length, in bits, of the `du_cpb_removal_delay_increment_minus1[ i ]` and /// du_common_cpb_removal_delay_increment_minus1 syntax elements of the /// picture timing SEI message and the du_spt_cpb_removal_delay_increment /// syntax element in the decoding unit information SEI message. - du_cpb_removal_delay_increment_length_minus1: u8, + pub du_cpb_removal_delay_increment_length_minus1: u8, /// When set, specifies that sub-picture level CPB removal delay parameters /// are present in picture timing SEI messages and no decoding unit /// information SEI message is available (in the CVS or provided through @@ -2232,147 +1826,65 @@ pub struct HrdParams { /// specifies that sub-picture level CPB removal delay parameters are /// present in decoding unit information SEI messages and picture timing SEI /// messages do not include sub-picture level CPB removal delay parameters. - sub_pic_cpb_params_in_pic_timing_sei_flag: bool, + pub sub_pic_cpb_params_in_pic_timing_sei_flag: bool, /// dpb_output_delay_du_length_minus1 plus 1 specifies the length, in bits, /// of the pic_dpb_output_du_delay syntax element in the picture timing SEI /// message and the pic_spt_dpb_output_du_delay syntax element in the /// decoding unit information SEI message. - dpb_output_delay_du_length_minus1: u8, + pub dpb_output_delay_du_length_minus1: u8, /// Together with `bit_rate_value_minus1[ i ]`, specifies the maximum input /// bit rate of the i-th CPB. - bit_rate_scale: u8, + pub bit_rate_scale: u8, /// Together with `cpb_size_du_value_minus1[ i ]`, specifies the CPB size of /// the i-th CPB when the CPB operates at sub-picture level. - cpb_size_scale: u8, + pub cpb_size_scale: u8, /// Together with `cpb_size_du_value_minus1[ i ]`, specifies the CPB size of /// the i-th CPB when the CPB operates at sub-picture level. - cpb_size_du_scale: u8, + pub cpb_size_du_scale: u8, /// initial_cpb_removal_delay_length_minus1 plus 1 specifies the length, in /// bits, of the `nal_initial_cpb_removal_delay[ i ]`, /// `nal_initial_cpb_removal_offset[ i ]`, `vcl_initial_cpb_removal_delay[ i ]` /// and `vcl_initial_cpb_removal_offset[ i ]` syntax elements of the buffering /// period SEI message. - initial_cpb_removal_delay_length_minus1: u8, + pub initial_cpb_removal_delay_length_minus1: u8, /// au_cpb_removal_delay_length_minus1 plus 1 specifies the length, in bits, /// of the cpb_delay_offset syntax element in the buffering period SEI /// message and the au_cpb_removal_delay_minus1 syntax element in the /// picture timing SEI message. - au_cpb_removal_delay_length_minus1: u8, + pub au_cpb_removal_delay_length_minus1: u8, /// dpb_output_delay_length_minus1 plus 1 specifies the length, in bits, of /// the dpb_delay_offset syntax element in the buffering period SEI message /// and the pic_dpb_output_delay syntax element in the picture timing SEI /// message. - dpb_output_delay_length_minus1: u8, + pub dpb_output_delay_length_minus1: u8, /// `fixed_pic_rate_general_flag[ i ]` set indicates that, when HighestTid is /// equal to i, the temporal distance between the HRD output times of /// consecutive pictures in output order is constrained as specified in the /// specification. `fixed_pic_rate_general_flag[ i ]` not set indicates that /// this constraint may not apply. - fixed_pic_rate_general_flag: [bool; 7], + pub fixed_pic_rate_general_flag: [bool; 7], /// `fixed_pic_rate_within_cvs_flag[ i ]` set indicates that, when HighestTid /// is equal to i, the temporal distance between the HRD output times of /// consecutive pictures in output order is constrained as specified in the /// specification. `fixed_pic_rate_within_cvs_flag[ i ]` not set indicates /// that this constraint may not apply. - fixed_pic_rate_within_cvs_flag: [bool; 7], + pub fixed_pic_rate_within_cvs_flag: [bool; 7], /// `elemental_duration_in_tc_minus1[ i ]` plus 1 (when present) specifies, /// when HighestTid is equal to i, the temporal distance, in clock ticks, /// between the elemental units that specify the HRD output times of /// consecutive pictures in output order as specified in the specification. - elemental_duration_in_tc_minus1: [u32; 7], + pub elemental_duration_in_tc_minus1: [u32; 7], /// `low_delay_hrd_flag[ i ]` specifies the HRD operational mode, when /// HighestTid is equal to i, as specified in Annex C or clause F.13. - low_delay_hrd_flag: [bool; 7], + pub low_delay_hrd_flag: [bool; 7], /// `cpb_cnt_minus1[ i ]` plus 1 specifies the number of alternative CPB /// specifications in the bitstream of the CVS when HighestTid is equal to /// i. - cpb_cnt_minus1: [u32; 7], + pub cpb_cnt_minus1: [u32; 7], /// The NAL HRD data. - nal_hrd: [SublayerHrdParameters; 7], + pub nal_hrd: [SublayerHrdParameters; 7], /// The VCL HRD data. - vcl_hrd: [SublayerHrdParameters; 7], -} - -impl HrdParams { - pub fn nal_hrd_parameters_present_flag(&self) -> bool { - self.nal_hrd_parameters_present_flag - } - - pub fn vcl_hrd_parameters_present_flag(&self) -> bool { - self.vcl_hrd_parameters_present_flag - } - - pub fn sub_pic_hrd_params_present_flag(&self) -> bool { - self.sub_pic_hrd_params_present_flag - } - - pub fn tick_divisor_minus2(&self) -> u8 { - self.tick_divisor_minus2 - } - - pub fn du_cpb_removal_delay_increment_length_minus1(&self) -> u8 { - self.du_cpb_removal_delay_increment_length_minus1 - } - - pub fn sub_pic_cpb_params_in_pic_timing_sei_flag(&self) -> bool { - self.sub_pic_cpb_params_in_pic_timing_sei_flag - } - - pub fn dpb_output_delay_du_length_minus1(&self) -> u8 { - self.dpb_output_delay_du_length_minus1 - } - - pub fn bit_rate_scale(&self) -> u8 { - self.bit_rate_scale - } - - pub fn cpb_size_scale(&self) -> u8 { - self.cpb_size_scale - } - - pub fn cpb_size_du_scale(&self) -> u8 { - self.cpb_size_du_scale - } - - pub fn initial_cpb_removal_delay_length_minus1(&self) -> u8 { - self.initial_cpb_removal_delay_length_minus1 - } - - pub fn au_cpb_removal_delay_length_minus1(&self) -> u8 { - self.au_cpb_removal_delay_length_minus1 - } - - pub fn dpb_output_delay_length_minus1(&self) -> u8 { - self.dpb_output_delay_length_minus1 - } - - pub fn fixed_pic_rate_general_flag(&self) -> [bool; 7] { - self.fixed_pic_rate_general_flag - } - - pub fn fixed_pic_rate_within_cvs_flag(&self) -> [bool; 7] { - self.fixed_pic_rate_within_cvs_flag - } - - pub fn elemental_duration_in_tc_minus1(&self) -> [u32; 7] { - self.elemental_duration_in_tc_minus1 - } - - pub fn low_delay_hrd_flag(&self) -> [bool; 7] { - self.low_delay_hrd_flag - } - - pub fn cpb_cnt_minus1(&self) -> [u32; 7] { - self.cpb_cnt_minus1 - } - - pub fn nal_hrd(&self) -> &[SublayerHrdParameters; 7] { - &self.nal_hrd - } - - pub fn vcl_hrd(&self) -> &[SublayerHrdParameters; 7] { - &self.vcl_hrd - } + pub vcl_hrd: [SublayerHrdParameters; 7], } impl Default for HrdParams { @@ -2402,117 +1914,116 @@ impl Default for HrdParams { } } -// TODO #[derive(Clone, Debug, PartialEq, Eq)] pub struct VuiParams { /// When set, specifies that aspect_ratio_idc is present. When not set, /// specifies that aspect_ratio_idc is not present. - aspect_ratio_info_present_flag: bool, + pub aspect_ratio_info_present_flag: bool, /// Specifies the value of the sample aspect ratio of the luma samples. - aspect_ratio_idc: u32, + pub aspect_ratio_idc: u32, /// Indicates the horizontal size of the sample aspect ratio (in arbitrary /// units). - sar_width: u32, + pub sar_width: u32, /// Indicates the vertical size of the sample aspect ratio (in arbitrary /// units). - sar_height: u32, + pub sar_height: u32, /// When set, specifies that the overscan_appropriate_flag is present. When /// not set, the preferred display method for the video signal is /// unspecified. - overscan_info_present_flag: bool, + pub overscan_info_present_flag: bool, /// When set indicates that the cropped decoded pictures output are suitable /// for display using overscan. When not set, indicates that the cropped /// decoded pictures output contain visually important information in the /// entire region out to the edges of the conformance cropping window of the /// picture, such that the cropped decoded pictures output should not be /// displayed using overscan. - overscan_appropriate_flag: bool, + pub overscan_appropriate_flag: bool, /// When set, specifies that video_format, video_full_range_flag and /// colour_description_present_flag are present. When not set, specify that /// video_format, video_full_range_flag and colour_description_present_flag /// are not present. - video_signal_type_present_flag: bool, + pub video_signal_type_present_flag: bool, /// Indicates the representation of the pictures as specified in Table E.2, /// before being coded in accordance with this Specification. - video_format: u8, + pub video_format: u8, /// Indicates the black level and range of the luma and chroma signals as /// derived from E′Y, E′PB, and E′PR or E′R, E′G, and E′B real-valued /// component signals. - video_full_range_flag: bool, + pub video_full_range_flag: bool, /// When set, specifies that colour_primaries, transfer_characteristics, and /// matrix_coeffs are present. When not set, specifies that /// colour_primaries, transfer_characteristics, and matrix_coeffs are not /// present. - colour_description_present_flag: bool, + pub colour_description_present_flag: bool, /// Indicates the chromaticity coordinates of the source primaries as /// specified in Table E.3 in terms of the CIE 1931 definition of x and y as /// specified in ISO 11664-1. - colour_primaries: u32, + pub colour_primaries: u32, /// See table E.4 in the specification. - transfer_characteristics: u32, + pub transfer_characteristics: u32, /// Describes the matrix coefficients used in deriving luma and chroma /// signals from the green, blue, and red, or Y, Z, and X primaries, as /// specified in Table E.5. - matrix_coeffs: u32, + pub matrix_coeffs: u32, /// When true, specifies that chroma_sample_loc_type_top_field and /// chroma_sample_loc_type_bottom_field are present. When false, specifies /// that chroma_sample_loc_type_top_field and /// chroma_sample_loc_type_bottom_field are not present. - chroma_loc_info_present_flag: bool, + pub chroma_loc_info_present_flag: bool, /// See the specification for more details. - chroma_sample_loc_type_top_field: u32, + pub chroma_sample_loc_type_top_field: u32, /// See the specification for more details. - chroma_sample_loc_type_bottom_field: u32, + pub chroma_sample_loc_type_bottom_field: u32, /// When true, indicates that the value of all decoded chroma samples is /// equal to 1 << ( BitDepthC − 1 ). When false, provides no indication of /// decoded chroma sample values. - neutral_chroma_indication_flag: bool, + pub neutral_chroma_indication_flag: bool, /// When true, indicates that the CVS conveys pictures that represent /// fields, and specifies that a picture timing SEI message shall be present /// in every access unit of the current CVS. When false, indicates that the /// CVS conveys pictures that represent frames and that a picture timing SEI /// message may or may not be present in any access unit of the current CVS. - field_seq_flag: bool, + pub field_seq_flag: bool, /// When true, specifies that picture timing SEI messages are present for /// every picture and include the pic_struct, source_scan_type and /// duplicate_flag syntax elements. When false, specifies that the /// pic_struct syntax element is not present in picture timing SEI messages. - frame_field_info_present_flag: bool, + pub frame_field_info_present_flag: bool, /// When true, indicates that the default display window parameters follow /// next in the VUI. When false, indicates that the default display window /// parameters are not present. - default_display_window_flag: bool, + pub default_display_window_flag: bool, /// Specifies the samples of the pictures in the CVS that are within the /// default display window, in terms of a rectangular region specified in /// picture coordinates for display. - def_disp_win_left_offset: u32, + pub def_disp_win_left_offset: u32, /// Specifies the samples of the pictures in the CVS that are within the /// default display window, in terms of a rectangular region specified in /// picture coordinates for display. - def_disp_win_right_offset: u32, + pub def_disp_win_right_offset: u32, /// Specifies the samples of the pictures in the CVS that are within the /// default display window, in terms of a rectangular region specified in /// picture coordinates for display. - def_disp_win_top_offset: u32, + pub def_disp_win_top_offset: u32, /// Specifies the samples of the pictures in the CVS that are within the /// default display window, in terms of a rectangular region specified in /// picture coordinates for display. - def_disp_win_bottom_offset: u32, + pub def_disp_win_bottom_offset: u32, /// When set, specifies that vui_num_units_in_tick, vui_time_scale, /// vui_poc_proportional_to_timing_flag and vui_hrd_parameters_present_flag /// are present in the vui_parameters( ) syntax structure. When not set, /// specifies that vui_num_units_in_tick, vui_time_scale, /// vui_poc_proportional_to_timing_flag and vui_hrd_parameters_present_flag /// are not present in the vui_parameters( ) syntax structure - timing_info_present_flag: bool, + pub timing_info_present_flag: bool, /// The number of time units of a clock operating at the frequency /// vui_time_scale Hz that corresponds to one increment (called a clock /// tick) of a clock tick counter. - num_units_in_tick: u32, + pub num_units_in_tick: u32, /// Is the number of time units that pass in one second. For example, a time /// coordinate system that measures time using a 27 MHz clock has a /// vui_time_scale of 27 000 000. - time_scale: u32, + pub time_scale: u32, /// When set, indicates that the picture order count value for each picture /// in the CVS that is not the first picture in the CVS, in decoding order, /// is proportional to the output time of the picture relative to the output @@ -2521,220 +2032,58 @@ pub struct VuiParams { /// first picture in the CVS, in decoding order, may or may not be /// proportional to the output time of the picture relative to the output /// time of the first picture in the CVS. - poc_proportional_to_timing_flag: bool, + pub poc_proportional_to_timing_flag: bool, /// vui_num_ticks_poc_diff_one_minus1 plus 1 specifies the number of clock /// ticks corresponding to a difference of picture order count values equal /// to 1. - num_ticks_poc_diff_one_minus1: u32, + pub num_ticks_poc_diff_one_minus1: u32, /// When set, specifies that the syntax structure hrd_parameters( ) is /// present in the vui_parameters( ) syntax structure. When not set, /// specifies that the syntax structure hrd_parameters( ) is not present in /// the vui_parameters( ) syntax structure. - hrd_parameters_present_flag: bool, + pub hrd_parameters_present_flag: bool, /// The hrd_parameters() data. - hrd: HrdParams, + pub hrd: HrdParams, /// When set, specifies that the bitstream restriction parameters for the /// CVS are present. When not set, specifies that the bitstream restriction /// parameters for the CVS are not present. - bitstream_restriction_flag: bool, + pub bitstream_restriction_flag: bool, /// When set, indicates that each PPS that is active in the CVS has the same /// value of the syntax elements num_tile_columns_minus1, /// num_tile_rows_minus1, uniform_spacing_flag, `column_width_minus1[ i ]`, /// `row_height_minus1[ i ]` and loop_filter_across_tiles_enabled_flag, when /// present. When not set, indicates that tiles syntax elements in different /// PPSs may or may not have the same value - tiles_fixed_structure_flag: bool, + pub tiles_fixed_structure_flag: bool, /// When not set, indicates that no sample outside the picture boundaries /// and no sample at a fractional sample position for which the sample value /// is derived using one or more samples outside the picture boundaries is /// used for inter prediction of any sample. When set, indicates that one /// or more samples outside the picture boundaries may be used in inter /// prediction. - motion_vectors_over_pic_boundaries_flag: bool, + pub motion_vectors_over_pic_boundaries_flag: bool, /// When set, indicates that all P and B slices (when present) that belong /// to the same picture have an identical reference picture list 0 and that /// all B slices (when present) that belong to the same picture have an /// identical reference picture list 1. - restricted_ref_pic_lists_flag: bool, + pub restricted_ref_pic_lists_flag: bool, /// When not equal to 0, establishes a bound on the maximum possible size of /// distinct coded spatial segmentation regions in the pictures of the CVS. - min_spatial_segmentation_idc: u32, + pub min_spatial_segmentation_idc: u32, /// Indicates a number of bytes not exceeded by the sum of the sizes of the /// VCL NAL units associated with any coded picture in the CVS. - max_bytes_per_pic_denom: u32, + pub max_bytes_per_pic_denom: u32, /// Indicates an upper bound for the number of coded bits of coding_unit( ) /// data for anycoding block in any picture of the CVS. - max_bits_per_min_cu_denom: u32, + pub max_bits_per_min_cu_denom: u32, /// Indicate the maximum absolute value of a decoded horizontal and vertical /// motion vector component, respectively, in quarter luma sample units, for /// all pictures in the CVS. - log2_max_mv_length_horizontal: u32, + pub log2_max_mv_length_horizontal: u32, /// Indicate the maximum absolute value of a decoded horizontal and vertical /// motion vector component, respectively, in quarter luma sample units, for /// all pictures in the CVS. - log2_max_mv_length_vertical: u32, -} - -impl VuiParams { - pub fn aspect_ratio_info_present_flag(&self) -> bool { - self.aspect_ratio_info_present_flag - } - - pub fn aspect_ratio_idc(&self) -> u32 { - self.aspect_ratio_idc - } - - pub fn sar_width(&self) -> u32 { - self.sar_width - } - - pub fn sar_height(&self) -> u32 { - self.sar_height - } - - pub fn overscan_info_present_flag(&self) -> bool { - self.overscan_info_present_flag - } - - pub fn overscan_appropriate_flag(&self) -> bool { - self.overscan_appropriate_flag - } - - pub fn video_signal_type_present_flag(&self) -> bool { - self.video_signal_type_present_flag - } - - pub fn video_format(&self) -> u8 { - self.video_format - } - - pub fn video_full_range_flag(&self) -> bool { - self.video_full_range_flag - } - - pub fn colour_description_present_flag(&self) -> bool { - self.colour_description_present_flag - } - - pub fn colour_primaries(&self) -> u32 { - self.colour_primaries - } - - pub fn transfer_characteristics(&self) -> u32 { - self.transfer_characteristics - } - - pub fn matrix_coeffs(&self) -> u32 { - self.matrix_coeffs - } - - pub fn chroma_loc_info_present_flag(&self) -> bool { - self.chroma_loc_info_present_flag - } - - pub fn chroma_sample_loc_type_top_field(&self) -> u32 { - self.chroma_sample_loc_type_top_field - } - - pub fn chroma_sample_loc_type_bottom_field(&self) -> u32 { - self.chroma_sample_loc_type_bottom_field - } - - pub fn neutral_chroma_indication_flag(&self) -> bool { - self.neutral_chroma_indication_flag - } - - pub fn field_seq_flag(&self) -> bool { - self.field_seq_flag - } - - pub fn frame_field_info_present_flag(&self) -> bool { - self.frame_field_info_present_flag - } - - pub fn default_display_window_flag(&self) -> bool { - self.default_display_window_flag - } - - pub fn def_disp_win_left_offset(&self) -> u32 { - self.def_disp_win_left_offset - } - - pub fn def_disp_win_right_offset(&self) -> u32 { - self.def_disp_win_right_offset - } - - pub fn def_disp_win_top_offset(&self) -> u32 { - self.def_disp_win_top_offset - } - - pub fn def_disp_win_bottom_offset(&self) -> u32 { - self.def_disp_win_bottom_offset - } - - pub fn timing_info_present_flag(&self) -> bool { - self.timing_info_present_flag - } - - pub fn num_units_in_tick(&self) -> u32 { - self.num_units_in_tick - } - - pub fn time_scale(&self) -> u32 { - self.time_scale - } - - pub fn poc_proportional_to_timing_flag(&self) -> bool { - self.poc_proportional_to_timing_flag - } - - pub fn num_ticks_poc_diff_one_minus1(&self) -> u32 { - self.num_ticks_poc_diff_one_minus1 - } - - pub fn hrd_parameters_present_flag(&self) -> bool { - self.hrd_parameters_present_flag - } - - pub fn hrd(&self) -> &HrdParams { - &self.hrd - } - - pub fn bitstream_restriction_flag(&self) -> bool { - self.bitstream_restriction_flag - } - - pub fn tiles_fixed_structure_flag(&self) -> bool { - self.tiles_fixed_structure_flag - } - - pub fn motion_vectors_over_pic_boundaries_flag(&self) -> bool { - self.motion_vectors_over_pic_boundaries_flag - } - - pub fn restricted_ref_pic_lists_flag(&self) -> bool { - self.restricted_ref_pic_lists_flag - } - - pub fn min_spatial_segmentation_idc(&self) -> u32 { - self.min_spatial_segmentation_idc - } - - pub fn max_bytes_per_pic_denom(&self) -> u32 { - self.max_bytes_per_pic_denom - } - - pub fn max_bits_per_min_cu_denom(&self) -> u32 { - self.max_bits_per_min_cu_denom - } - - pub fn log2_max_mv_length_horizontal(&self) -> u32 { - self.log2_max_mv_length_horizontal - } - - pub fn log2_max_mv_length_vertical(&self) -> u32 { - self.log2_max_mv_length_vertical - } + pub log2_max_mv_length_vertical: u32, } impl Default for VuiParams { @@ -2794,16 +2143,16 @@ pub struct Parser { impl Parser { /// Parse a VPS NALU. pub fn parse_vps(&mut self, nalu: &Nalu) -> anyhow::Result<&Vps> { - if !matches!(nalu.header().type_, NaluType::VpsNut) { + if !matches!(nalu.header.type_, NaluType::VpsNut) { return Err(anyhow!( "Invalid NALU type, expected {:?}, got {:?}", NaluType::VpsNut, - nalu.header().type_ + nalu.header.type_ )); } let data = nalu.as_ref(); - let header = nalu.header(); + let header = &nalu.header; let hdr_len = header.len(); // Skip the header let mut r = NaluReader::new(&data[hdr_len..]); @@ -3663,16 +3012,16 @@ impl Parser { /// Parse a SPS NALU. pub fn parse_sps(&mut self, nalu: &Nalu) -> anyhow::Result<&Sps> { - if !matches!(nalu.header().type_, NaluType::SpsNut) { + if !matches!(nalu.header.type_, NaluType::SpsNut) { return Err(anyhow!( "Invalid NALU type, expected {:?}, got {:?}", NaluType::SpsNut, - nalu.header().type_ + nalu.header.type_ )); } let data = nalu.as_ref(); - let header = nalu.header(); + let header = &nalu.header; let hdr_len = header.len(); // Skip the header let mut r = NaluReader::new(&data[hdr_len..]); @@ -3865,7 +3214,7 @@ impl Parser { sps.seq_parameter_set_id, sps.width(), sps.height(), - nalu.size() + nalu.size ); let key = sps.seq_parameter_set_id; @@ -3960,16 +3309,16 @@ impl Parser { /// Parse a PPS NALU. pub fn parse_pps(&mut self, nalu: &Nalu) -> anyhow::Result<&Pps> { - if !matches!(nalu.header().type_, NaluType::PpsNut) { + if !matches!(nalu.header.type_, NaluType::PpsNut) { return Err(anyhow!( "Invalid NALU type, expected {:?}, got {:?}", NaluType::PpsNut, - nalu.header().type_ + nalu.header.type_ )); } let data = nalu.as_ref(); - let header = nalu.header(); + let header = &nalu.header; let hdr_len = header.len(); // Skip the header let mut r = NaluReader::new(&data[hdr_len..]); @@ -4127,12 +3476,12 @@ impl Parser { r.skip_bits(4)?; // pps_extension_4bits } - pps.temporal_id = nalu.header().nuh_temporal_id_plus1 - 1; + pps.temporal_id = nalu.header.nuh_temporal_id_plus1 - 1; log::debug!( "Parsed PPS({}), NAL size was {}", pps.pic_parameter_set_id, - nalu.size() + nalu.size ); let key = pps.pic_parameter_set_id; @@ -4284,7 +3633,7 @@ impl Parser { /// Parses a slice header from a slice NALU. pub fn parse_slice_header<'a>(&mut self, nalu: Nalu<'a>) -> anyhow::Result> { if !matches!( - nalu.header().type_, + nalu.header.type_, NaluType::TrailN | NaluType::TrailR | NaluType::TsaN @@ -4304,12 +3653,12 @@ impl Parser { ) { return Err(anyhow!( "Invalid NALU type: {:?} is not a slice NALU", - nalu.header().type_ + nalu.header.type_ )); } let data = nalu.as_ref(); - let nalu_header = nalu.header(); + let nalu_header = &nalu.header; let hdr_len = nalu_header.len(); // Skip the header let mut r = NaluReader::new(&data[hdr_len..]); @@ -4319,7 +3668,7 @@ impl Parser { ..Default::default() }; - if nalu.header().type_.is_irap() { + if nalu.header.type_.is_irap() { hdr.no_output_of_prior_pics_flag = r.read_bit()?; } @@ -4681,14 +4030,14 @@ impl Parser { r.skip_bits(num_bits)?; let epb = r.num_epb(); - hdr.header_bit_size = ((nalu.size() - epb) * 8 - r.num_bits_left()) as u32; + hdr.header_bit_size = ((nalu.size - epb) * 8 - r.num_bits_left()) as u32; hdr.n_emulation_prevention_bytes = epb as u32; log::debug!( "Parsed slice {:?}, NAL size was {}", nalu_header.type_, - nalu.size() + nalu.size ); Ok(Slice { header: hdr, nalu }) @@ -4736,7 +4085,7 @@ mod tests { include_bytes!("test_data/test-25fps-h265-slice-data-1.bin"); fn dispatch_parse_call(parser: &mut Parser, nalu: Nalu) -> anyhow::Result<()> { - match nalu.header().type_ { + match nalu.header.type_ { NaluType::TrailN | NaluType::TrailR | NaluType::TsaN @@ -4776,7 +4125,7 @@ mod tests { ) -> Option> { let mut cursor = Cursor::new(bitstream); while let Ok(nalu) = Nalu::::next(&mut cursor) { - if nalu.header().type_ == nalu_type { + if nalu.header.type_ == nalu_type { if nskip == 0 { return Some(nalu); } else { @@ -4997,7 +4346,7 @@ mod tests { // Just like the Chromium test, do an IDR slice, then a non IDR slice. let slice_nalu = find_nalu_by_type(STREAM_BEAR, NaluType::IdrWRadl, 0).unwrap(); let slice = parser.parse_slice_header(slice_nalu).unwrap(); - let hdr = slice.header(); + let hdr = &slice.header; assert!(hdr.first_slice_segment_in_pic_flag); assert!(!hdr.no_output_of_prior_pics_flag); assert_eq!(hdr.pic_parameter_set_id, 0); @@ -5010,7 +4359,7 @@ mod tests { let slice_nalu = find_nalu_by_type(STREAM_BEAR, NaluType::TrailR, 0).unwrap(); let slice = parser.parse_slice_header(slice_nalu).unwrap(); - let hdr = slice.header(); + let hdr = &slice.header; assert!(hdr.first_slice_segment_in_pic_flag); assert_eq!(hdr.pic_parameter_set_id, 0); assert!(!hdr.dependent_slice_segment_flag); @@ -5282,7 +4631,7 @@ mod tests { let slice_nalu = find_nalu_by_type(STREAM_TEST25FPS, NaluType::IdrNLp, 0).unwrap(); let slice = parser.parse_slice_header(slice_nalu).unwrap(); - let hdr = slice.header(); + let hdr = &slice.header; assert!(hdr.first_slice_segment_in_pic_flag); assert!(!hdr.no_output_of_prior_pics_flag); @@ -5330,7 +4679,7 @@ mod tests { // Next slice let slice_nalu = find_nalu_by_type(STREAM_TEST25FPS, NaluType::TrailR, 0).unwrap(); let slice = parser.parse_slice_header(slice_nalu).unwrap(); - let hdr = slice.header(); + let hdr = &slice.header; assert!(hdr.first_slice_segment_in_pic_flag); assert!(!hdr.no_output_of_prior_pics_flag); @@ -5375,18 +4724,18 @@ mod tests { assert_eq!(hdr.offset_len_minus1, 10); assert_eq!(hdr.num_pic_total_curr, 1); - assert_eq!(slice.nalu.size(), 2983); + assert_eq!(slice.nalu.size, 2983); // Subtract 2 bytes to account for the header size. - assert_eq!(hdr.header_bit_size() - 16, 96); + assert_eq!(hdr.header_bit_size - 16, 96); assert_eq!(slice.nalu.as_ref(), STREAM_TEST_25_FPS_SLICE_1); // Next slice let slice_nalu = find_nalu_by_type(STREAM_TEST25FPS, NaluType::TrailR, 1).unwrap(); let slice = parser.parse_slice_header(slice_nalu).unwrap(); - let hdr = slice.header(); + let hdr = &slice.header; - assert_eq!(slice.nalu.size(), 290); + assert_eq!(slice.nalu.size, 290); // Subtract 2 bytes to account for the header size. - assert_eq!(hdr.header_bit_size() - 16, 80); + assert_eq!(hdr.header_bit_size - 16, 80); } } diff --git a/src/codec/h265/picture.rs b/src/codec/h265/picture.rs index 8f2aa817..a2a40116 100644 --- a/src/codec/h265/picture.rs +++ b/src/codec/h265/picture.rs @@ -55,15 +55,15 @@ impl PictureData { max_pic_order_cnt_lsb: i32, _timestamp: u64, ) -> Self { - let hdr = slice.header(); - let nalu_type = slice.nalu().header().type_; + let hdr = &slice.header; + let nalu_type = slice.nalu.header.type_; let is_irap = nalu_type.is_irap(); // We assume HandleCraAsBlafFLag == 0, as it is only set through // external means, which we do not provide. let mut pic_order_cnt_msb = 0; - let slice_pic_order_cnt_lsb: i32 = hdr.pic_order_cnt_lsb().into(); + let slice_pic_order_cnt_lsb: i32 = hdr.pic_order_cnt_lsb.into(); // Compute the output flags: // The value of NoRaslOutputFlag is equal to 1 for each IDR access @@ -76,10 +76,10 @@ impl PictureData { || (nalu_type.is_cra() && first_picture_in_bitstream) || first_picture_after_eos; - let pic_output_flag = if slice.nalu().header().type_.is_rasl() && no_rasl_output_flag { + let pic_output_flag = if slice.nalu.header.type_.is_rasl() && no_rasl_output_flag { false } else { - hdr.pic_output_flag() + hdr.pic_output_flag }; // Compute the Picture Order Count. See 8.3.1 Decoding Process for @@ -119,7 +119,7 @@ impl PictureData { let no_output_of_prior_pics_flag = if nalu_type.is_irap() && no_rasl_output_flag && !first_picture_in_bitstream { - nalu_type.is_cra() || hdr.no_output_of_prior_pics_flag() + nalu_type.is_cra() || hdr.no_output_of_prior_pics_flag } else { false }; @@ -139,7 +139,7 @@ impl PictureData { reference: Default::default(), pic_latency_cnt: 0, needed_for_output: false, - short_term_ref_pic_set_size_bits: hdr.st_rps_bits(), + short_term_ref_pic_set_size_bits: hdr.st_rps_bits, } } diff --git a/src/decoder/stateless/h264.rs b/src/decoder/stateless/h264.rs index e70da199..71c39fc6 100644 --- a/src/decoder/stateless/h264.rs +++ b/src/decoder/stateless/h264.rs @@ -566,7 +566,7 @@ where } } - if !slice.header().field_pic_flag { + if !slice.header.field_pic_flag { if let Some(prev_field) = prev_field { let field = prev_field.0.borrow().field; return Err(anyhow!( @@ -582,14 +582,14 @@ where Some(prev_field) => { let prev_field_pic = prev_field.0.borrow(); - if prev_field_pic.frame_num != i32::from(slice.header().frame_num) { + if prev_field_pic.frame_num != i32::from(slice.header.frame_num) { return Err(anyhow!( "The previous field differs in frame_num value wrt. the current field. {:?} vs {:?}", prev_field_pic.frame_num, - slice.header().frame_num + slice.header.frame_num )); } else { - let cur_field = if slice.header().bottom_field_flag { + let cur_field = if slice.header.bottom_field_flag { Field::Bottom } else { Field::Top @@ -1132,7 +1132,7 @@ where fn handle_memory_management_ops(&mut self, pic: &mut PictureData) -> anyhow::Result<()> { let markings = pic.ref_pic_marking.clone(); - for (i, marking) in markings.inner().iter().enumerate() { + for (i, marking) in markings.inner.iter().enumerate() { match marking.memory_management_control_operation { 0 => break, 1 => self.codec.dpb.mmco_op_1(pic, i)?, @@ -1176,7 +1176,7 @@ where if matches!(pic.is_idr, IsIdr::Yes { .. }) { self.codec.dpb.mark_all_as_unused_for_ref(); - if pic.ref_pic_marking.long_term_reference_flag() { + if pic.ref_pic_marking.long_term_reference_flag { pic.set_reference(Reference::LongTerm, false); pic.long_term_frame_idx = 0; self.codec.max_long_term_frame_idx = 0; @@ -1188,7 +1188,7 @@ where return Ok(()); } - if pic.ref_pic_marking.adaptive_ref_pic_marking_mode_flag() { + if pic.ref_pic_marking.adaptive_ref_pic_marking_mode_flag { self.handle_memory_management_ops(pic)?; } else { self.codec.sliding_window_marking(pic, pps)?; @@ -1429,7 +1429,7 @@ where let pps = self .codec .parser - .get_pps(slice.header().pic_parameter_set_id) + .get_pps(slice.header.pic_parameter_set_id) .context("Invalid SPS in init_current_pic")?; let sps = Rc::clone(&pps.sps); @@ -1450,7 +1450,7 @@ where // The current picture is an IDR picture and // no_output_of_prior_pics_flag is not equal to 1 and is not // inferred to be equal to 1, as specified in clause C.4.4. - if !pic.ref_pic_marking.no_output_of_prior_pics_flag() { + if !pic.ref_pic_marking.no_output_of_prior_pics_flag { self.drain()?; } else { // C.4.4 When no_output_of_prior_pics_flag is equal to 1 or is @@ -1463,7 +1463,7 @@ where self.codec .dpb - .update_pic_nums(i32::from(slice.header().frame_num), max_frame_num, &pic); + .update_pic_nums(i32::from(slice.header.frame_num), max_frame_num, &pic); Ok(pic) } @@ -1474,13 +1474,13 @@ where timestamp: u64, slice: &Slice, ) -> Result, DecodeError> { - let nalu_hdr = slice.nalu().header(); + let nalu_hdr = &slice.nalu.header; - if nalu_hdr.idr_pic_flag() { + if nalu_hdr.idr_pic_flag { self.codec.prev_ref_pic_info.frame_num = 0; } - let hdr = slice.header(); + let hdr = &slice.header; let frame_num = i32::from(hdr.frame_num); let pps = Rc::clone( @@ -1527,7 +1527,7 @@ where pps.sps.as_ref(), pps.as_ref(), &self.codec.dpb, - slice.header(), + &slice.header, )?; Ok(CurrentPicState { @@ -1568,8 +1568,8 @@ where ref_idx_lx: &mut usize, ) -> anyhow::Result<()> { let pic_num_lx_no_wrap; - let abs_diff_pic_num = rplm.abs_diff_pic_num_minus1() as i32 + 1; - let modification_of_pic_nums_idc = rplm.modification_of_pic_nums_idc(); + let abs_diff_pic_num = rplm.abs_diff_pic_num_minus1 as i32 + 1; + let modification_of_pic_nums_idc = rplm.modification_of_pic_nums_idc; if modification_of_pic_nums_idc == 0 { if *pic_num_lx_pred - abs_diff_pic_num < 0 { @@ -1586,7 +1586,7 @@ where } else { anyhow::bail!( "unexpected value for modification_of_pic_nums_idc {:?}", - rplm.modification_of_pic_nums_idc() + rplm.modification_of_pic_nums_idc ); } @@ -1635,7 +1635,7 @@ where rplm: &RefPicListModification, ref_idx_lx: &mut usize, ) -> anyhow::Result<()> { - let long_term_pic_num = rplm.long_term_pic_num(); + let long_term_pic_num = rplm.long_term_pic_num; let handle = dpb .find_long_term_with_long_term_pic_num(long_term_pic_num as i32) @@ -1705,7 +1705,7 @@ where let mut ref_idx_lx = 0; for modification in rplm { - let idc = modification.modification_of_pic_nums_idc(); + let idc = modification.modification_of_pic_nums_idc; match idc { 0 | 1 => { @@ -1785,7 +1785,7 @@ where let pps = self .codec .parser - .get_pps(slice.header().pic_parameter_set_id) + .get_pps(slice.header.pic_parameter_set_id) .context("Invalid PPS")?; cur_pic.pps = Rc::clone(pps); @@ -1798,7 +1798,7 @@ where let RefPicLists { ref_pic_list0, ref_pic_list1, - } = self.create_ref_pic_lists(&cur_pic.pic, slice.header(), &cur_pic.ref_pic_lists)?; + } = self.create_ref_pic_lists(&cur_pic.pic, &slice.header, &cur_pic.ref_pic_lists)?; self.backend.decode_slice( &mut cur_pic.backend_pic, @@ -1825,7 +1825,7 @@ where } fn process_nalu(&mut self, timestamp: u64, nalu: Nalu) -> Result<(), DecodeError> { - match nalu.header().nalu_type() { + match nalu.header.type_ { NaluType::Sps => { self.codec.parser.parse_sps(&nalu)?; } @@ -1849,8 +1849,8 @@ where if (self.codec.dpb.interlaced() && matches!(cur_pic.pic.field, Field::Frame) && !cur_pic.pic.is_second_field() - && cur_pic.pic.field != slice.header().field()) - || (slice.header().first_mb_in_slice == 0) => + && cur_pic.pic.field != slice.header.field()) + || (slice.header.first_mb_in_slice == 0) => { self.finish_picture(cur_pic)?; self.begin_picture(timestamp, &slice)? @@ -1881,7 +1881,7 @@ where let mut cursor = Cursor::new(bitstream); let nalu = Nalu::next(&mut cursor)?; - if nalu.header().nalu_type() == NaluType::Sps { + if nalu.header.type_ == NaluType::Sps { let sps = self.codec.parser.parse_sps(&nalu)?.clone(); if matches!(self.decoding_state, DecodingState::AwaitingStreamInfo) { // If more SPS come along we will renegotiate in begin_picture(). @@ -1895,20 +1895,20 @@ where while let Ok(nalu) = Nalu::next(&mut cursor) { // In the Reset state we can resume decoding from any key frame. - if matches!(nalu.header().nalu_type(), NaluType::SliceIdr) { + if matches!(nalu.header.type_, NaluType::SliceIdr) { self.decoding_state = DecodingState::Decoding; break; } } } - let nalu_len = nalu.offset() + nalu.size(); + let nalu_len = nalu.offset + nalu.size; match &mut self.decoding_state { // Process parameter sets, but skip input until we get information // from the stream. DecodingState::AwaitingStreamInfo | DecodingState::Reset => { - if matches!(nalu.header().nalu_type(), NaluType::Pps) { + if matches!(nalu.header.type_, NaluType::Pps) { self.process_nalu(timestamp, nalu)?; } } diff --git a/src/decoder/stateless/h264/vaapi.rs b/src/decoder/stateless/h264/vaapi.rs index e020dc4c..8f11aa91 100644 --- a/src/decoder/stateless/h264/vaapi.rs +++ b/src/decoder/stateless/h264/vaapi.rs @@ -199,11 +199,11 @@ fn build_iq_matrix(pps: &Pps) -> BufferType { let mut scaling_list8x8 = [[0; 64]; 2]; (0..6).for_each(|i| { - super::get_raster_from_zigzag_4x4(pps.scaling_lists_4x4()[i], &mut scaling_list4x4[i]); + super::get_raster_from_zigzag_4x4(pps.scaling_lists_4x4[i], &mut scaling_list4x4[i]); }); (0..2).for_each(|i| { - super::get_raster_from_zigzag_8x8(pps.scaling_lists_8x8()[i], &mut scaling_list8x8[i]); + super::get_raster_from_zigzag_8x8(pps.scaling_lists_8x8[i], &mut scaling_list8x8[i]); }); BufferType::IQMatrix(IQMatrix::H264(IQMatrixBufferH264::new( @@ -276,15 +276,15 @@ fn build_pic_param( let picture_height_in_mbs_minus1 = ((sps.pic_height_in_map_units_minus1 + 1) << interlaced) - 1; let pic_fields = libva::H264PicFields::new( - pps.entropy_coding_mode_flag() as u32, - pps.weighted_pred_flag() as u32, - pps.weighted_bipred_idc() as u32, - pps.transform_8x8_mode_flag() as u32, + pps.entropy_coding_mode_flag as u32, + pps.weighted_pred_flag as u32, + pps.weighted_bipred_idc as u32, + pps.transform_8x8_mode_flag as u32, hdr.field_pic_flag as u32, - pps.constrained_intra_pred_flag() as u32, - pps.bottom_field_pic_order_in_frame_present_flag() as u32, - pps.deblocking_filter_control_present_flag() as u32, - pps.redundant_pic_cnt_present_flag() as u32, + pps.constrained_intra_pred_flag as u32, + pps.bottom_field_pic_order_in_frame_present_flag as u32, + pps.deblocking_filter_control_present_flag as u32, + pps.redundant_pic_cnt_present_flag as u32, (current_picture.nal_ref_idc != 0) as u32, ); @@ -308,10 +308,10 @@ fn build_pic_param( 0, /* FMO not supported by VA */ 0, /* FMO not supported by VA */ 0, /* FMO not supported by VA */ - pps.pic_init_qp_minus26(), - pps.pic_init_qs_minus26(), - pps.chroma_qp_index_offset(), - pps.second_chroma_qp_index_offset(), + pps.pic_init_qp_minus26, + pps.pic_init_qs_minus26, + pps.chroma_qp_index_offset, + pps.second_chroma_qp_index_offset, &pic_fields, hdr.frame_num, ); @@ -379,9 +379,9 @@ fn build_slice_param( let mut fill_l0 = false; let mut fill_l1 = false; - if pps.weighted_pred_flag() && (hdr.slice_type.is_p() || hdr.slice_type.is_sp()) { + if pps.weighted_pred_flag && (hdr.slice_type.is_p() || hdr.slice_type.is_sp()) { fill_l0 = true; - } else if pps.weighted_bipred_idc() == 1 && hdr.slice_type.is_b() { + } else if pps.weighted_bipred_idc == 1 && hdr.slice_type.is_b() { fill_l0 = true; fill_l1 = true; } @@ -390,16 +390,16 @@ fn build_slice_param( luma_weight_l0_flag = true; for i in 0..=hdr.num_ref_idx_l0_active_minus1 as usize { - luma_weight_l0[i] = pwt.luma_weight_l0()[i]; - luma_offset_l0[i] = i16::from(pwt.luma_offset_l0()[i]); + luma_weight_l0[i] = pwt.luma_weight_l0[i]; + luma_offset_l0[i] = i16::from(pwt.luma_offset_l0[i]); } chroma_weight_l0_flag = sps.chroma_array_type != 0; if chroma_weight_l0_flag { for i in 0..=hdr.num_ref_idx_l0_active_minus1 as usize { for j in 0..2 { - chroma_weight_l0[i][j] = pwt.chroma_weight_l0()[i][j]; - chroma_offset_l0[i][j] = i16::from(pwt.chroma_offset_l0()[i][j]); + chroma_weight_l0[i][j] = pwt.chroma_weight_l0[i][j]; + chroma_offset_l0[i][j] = i16::from(pwt.chroma_offset_l0[i][j]); } } } @@ -409,18 +409,18 @@ fn build_slice_param( luma_weight_l1_flag = true; luma_weight_l1[..(hdr.num_ref_idx_l1_active_minus1 as usize + 1)].clone_from_slice( - &pwt.luma_weight_l1()[..(hdr.num_ref_idx_l1_active_minus1 as usize + 1)], + &pwt.luma_weight_l1[..(hdr.num_ref_idx_l1_active_minus1 as usize + 1)], ); luma_offset_l1[..(hdr.num_ref_idx_l1_active_minus1 as usize + 1)].clone_from_slice( - &pwt.luma_offset_l1()[..(hdr.num_ref_idx_l1_active_minus1 as usize + 1)], + &pwt.luma_offset_l1[..(hdr.num_ref_idx_l1_active_minus1 as usize + 1)], ); chroma_weight_l1_flag = sps.chroma_array_type != 0; if chroma_weight_l1_flag { for i in 0..=hdr.num_ref_idx_l1_active_minus1 as usize { for j in 0..2 { - chroma_weight_l1[i][j] = pwt.chroma_weight_l1()[i][j]; - chroma_offset_l1[i][j] = i16::from(pwt.chroma_offset_l1()[i][j]); + chroma_weight_l1[i][j] = pwt.chroma_weight_l1[i][j]; + chroma_offset_l1[i][j] = i16::from(pwt.chroma_offset_l1[i][j]); } } } @@ -443,8 +443,8 @@ fn build_slice_param( hdr.slice_beta_offset_div2, ref_list_0, ref_list_1, - pwt.luma_log2_weight_denom(), - pwt.chroma_log2_weight_denom(), + pwt.luma_log2_weight_denom, + pwt.chroma_log2_weight_denom, luma_weight_l0_flag as u8, luma_weight_l0, luma_offset_l0, @@ -520,8 +520,8 @@ impl StatelessH264DecoderBackend for Vaapi let slice_param = context .create_buffer(build_slice_param( - slice.header(), - slice.nalu().size(), + &slice.header, + slice.nalu.size, ref_pic_list0, ref_pic_list1, sps, @@ -532,7 +532,7 @@ impl StatelessH264DecoderBackend for Vaapi picture.add_buffer(slice_param); let slice_data = context - .create_buffer(BufferType::SliceData(Vec::from(slice.nalu().as_ref()))) + .create_buffer(BufferType::SliceData(Vec::from(slice.nalu.as_ref()))) .context("while creating slice data buffer")?; picture.add_buffer(slice_data); diff --git a/src/decoder/stateless/h265.rs b/src/decoder/stateless/h265.rs index ff55679a..ff667863 100644 --- a/src/decoder/stateless/h265.rs +++ b/src/decoder/stateless/h265.rs @@ -388,22 +388,22 @@ where // See 8.3.2, Note 2. fn st_ref_pic_set<'a>(hdr: &'a SliceHeader, sps: &'a Sps) -> &'a ShortTermRefPicSet { - if hdr.curr_rps_idx() == sps.num_short_term_ref_pic_sets { - hdr.short_term_ref_pic_set() + if hdr.curr_rps_idx == sps.num_short_term_ref_pic_sets { + &hdr.short_term_ref_pic_set } else { - &sps.short_term_ref_pic_set[usize::from(hdr.curr_rps_idx())] + &sps.short_term_ref_pic_set[usize::from(hdr.curr_rps_idx)] } } // See 8.3.2. fn decode_rps(&mut self, slice: &Slice, cur_pic: &PictureData) -> anyhow::Result<()> { - let hdr = slice.header(); + let hdr = &slice.header; if cur_pic.nalu_type.is_irap() && cur_pic.no_rasl_output_flag { self.codec.dpb.mark_all_as_unused_for_ref(); } - if slice.nalu().header().type_.is_idr() { + if slice.nalu.header.type_.is_idr() { self.codec.rps.poc_st_curr_before = Default::default(); self.codec.rps.poc_st_curr_after = Default::default(); self.codec.rps.poc_st_foll = Default::default(); @@ -425,10 +425,10 @@ where let curr_st_rps = Self::st_ref_pic_set(hdr, sps); let mut j = 0; let mut k = 0; - for i in 0..usize::from(curr_st_rps.num_negative_pics()) { - let poc = cur_pic.pic_order_cnt_val + curr_st_rps.delta_poc_s0()[i]; + for i in 0..usize::from(curr_st_rps.num_negative_pics) { + let poc = cur_pic.pic_order_cnt_val + curr_st_rps.delta_poc_s0[i]; - if curr_st_rps.used_by_curr_pic_s0()[i] { + if curr_st_rps.used_by_curr_pic_s0[i] { self.codec.rps.poc_st_curr_before[j] = poc; j += 1; } else { @@ -440,10 +440,10 @@ where self.codec.rps.num_poc_st_curr_before = j as _; let mut j = 0; - for i in 0..usize::from(curr_st_rps.num_positive_pics()) { - let poc = cur_pic.pic_order_cnt_val + curr_st_rps.delta_poc_s1()[i]; + for i in 0..usize::from(curr_st_rps.num_positive_pics) { + let poc = cur_pic.pic_order_cnt_val + curr_st_rps.delta_poc_s1[i]; - if curr_st_rps.used_by_curr_pic_s1()[i] { + if curr_st_rps.used_by_curr_pic_s1[i] { self.codec.rps.poc_st_curr_after[j] = poc; j += 1; } else { @@ -457,26 +457,26 @@ where let mut j = 0; let mut k = 0; - for i in 0..usize::from(hdr.num_long_term_sps() + hdr.num_long_term_pics()) { - let mut poc_lt = hdr.poc_lsb_lt()[i] as i32; - if hdr.delta_poc_msb_present_flag()[i] { + for i in 0..usize::from(hdr.num_long_term_sps + hdr.num_long_term_pics) { + let mut poc_lt = hdr.poc_lsb_lt[i] as i32; + if hdr.delta_poc_msb_present_flag[i] { poc_lt += cur_pic.pic_order_cnt_val; let delta_poc = - hdr.delta_poc_msb_cycle_lt()[i] as i32 * self.codec.max_pic_order_cnt_lsb; + hdr.delta_poc_msb_cycle_lt[i] as i32 * self.codec.max_pic_order_cnt_lsb; poc_lt -= delta_poc; poc_lt -= cur_pic.pic_order_cnt_val & (self.codec.max_pic_order_cnt_lsb - 1); } - if hdr.used_by_curr_pic_lt()[i] { + if hdr.used_by_curr_pic_lt[i] { self.codec.rps.poc_lt_curr[j] = poc_lt; self.codec.rps.curr_delta_poc_msb_present_flag[j] = - hdr.delta_poc_msb_present_flag()[i]; + hdr.delta_poc_msb_present_flag[i]; j += 1; } else { self.codec.rps.poc_lt_foll[k] = poc_lt; self.codec.rps.foll_delta_poc_msb_present_flag[k] = - hdr.delta_poc_msb_present_flag()[i]; + hdr.delta_poc_msb_present_flag[i]; k += 1; } } @@ -648,14 +648,14 @@ where let mut ref_pic_lists = ReferencePicLists::default(); // I slices do not use inter prediction. - if !hdr.type_().is_p() && !hdr.type_().is_b() { + if !hdr.type_.is_p() && !hdr.type_.is_b() { return Ok(ref_pic_lists); } let pps = self .codec .parser - .get_pps(hdr.pic_parameter_set_id()) + .get_pps(hdr.pic_parameter_set_id) .context("Invalid PPS in build_ref_pic_lists")?; if self.codec.rps.num_poc_st_curr_before == 0 @@ -671,11 +671,11 @@ where return Ok(ref_pic_lists); } - let rplm = hdr.ref_pic_list_modification(); + let rplm = &hdr.ref_pic_list_modification; let num_rps_curr_temp_list0 = std::cmp::max( - u32::from(hdr.num_ref_idx_l0_active_minus1()) + 1, - hdr.num_pic_total_curr(), + u32::from(hdr.num_ref_idx_l0_active_minus1) + 1, + hdr.num_pic_total_curr, ); // This could be simplified using a Vec, but lets not change the @@ -726,9 +726,9 @@ where } // Equation 8-9 - for r_idx in 0..=usize::from(hdr.num_ref_idx_l0_active_minus1()) { - let entry = if rplm.ref_pic_list_modification_flag_l0() { - let idx = rplm.list_entry_l0()[r_idx]; + for r_idx in 0..=usize::from(hdr.num_ref_idx_l0_active_minus1) { + let entry = if rplm.ref_pic_list_modification_flag_l0 { + let idx = rplm.list_entry_l0[r_idx]; ref_pic_list_temp0[idx as usize].clone() } else { ref_pic_list_temp0[r_idx].clone() @@ -738,20 +738,20 @@ where } if pps.scc_extension.curr_pic_ref_enabled_flag - && !rplm.ref_pic_list_modification_flag_l0() - && num_rps_curr_temp_list0 > (u32::from(hdr.num_ref_idx_l0_active_minus1()) + 1) + && !rplm.ref_pic_list_modification_flag_l0 + && num_rps_curr_temp_list0 > (u32::from(hdr.num_ref_idx_l0_active_minus1) + 1) { ref_pic_lists.ref_pic_list0[r_idx as usize] = Some(RefPicListEntry::CurrentPicture(cur_pic.clone())); } - if hdr.type_().is_b() { + if hdr.type_.is_b() { let mut ref_pic_list_temp1: [Option>; MAX_DPB_SIZE] = Default::default(); let num_rps_curr_temp_list1 = std::cmp::max( - u32::from(hdr.num_ref_idx_l1_active_minus1()) + 1, - hdr.num_pic_total_curr(), + u32::from(hdr.num_ref_idx_l1_active_minus1) + 1, + hdr.num_pic_total_curr, ); // Equation 8-10 @@ -796,9 +796,9 @@ where } // Equation 8-11 - for r_idx in 0..=usize::from(hdr.num_ref_idx_l1_active_minus1()) { - let entry = if rplm.ref_pic_list_modification_flag_l1() { - let idx = rplm.list_entry_l1()[r_idx]; + for r_idx in 0..=usize::from(hdr.num_ref_idx_l1_active_minus1) { + let entry = if rplm.ref_pic_list_modification_flag_l1 { + let idx = rplm.list_entry_l1[r_idx]; ref_pic_list_temp1[idx as usize].clone() } else { ref_pic_list_temp1[r_idx].clone() @@ -929,7 +929,7 @@ where let pps = self .codec .parser - .get_pps(slice.header().pic_parameter_set_id()) + .get_pps(slice.header.pic_parameter_set_id) .context("Invalid PPS in handle_picture")?; let pps_id = pps.pic_parameter_set_id; @@ -1017,7 +1017,7 @@ where fn handle_slice(&mut self, pic: &mut CurrentPicState, slice: &Slice) -> anyhow::Result<()> { // A dependent slice may refer to a previous SPS which // is not the one currently in use. - self.update_current_set_ids(slice.header().pic_parameter_set_id())?; + self.update_current_set_ids(slice.header.pic_parameter_set_id)?; let sps = self .codec @@ -1033,7 +1033,7 @@ where &self.codec.negotiation_info, )); - pic.ref_pic_lists = self.build_ref_pic_lists(slice.header(), &pic.pic)?; + pic.ref_pic_lists = self.build_ref_pic_lists(&slice.header, &pic.pic)?; self.backend.decode_slice( &mut pic.backend_pic, @@ -1128,11 +1128,11 @@ where fn process_nalu(&mut self, timestamp: u64, nalu: Nalu) -> Result<(), DecodeError> { log::debug!( "Processing NALU {:?}, length is {}", - nalu.header().type_, - nalu.size() + nalu.header.type_, + nalu.size ); - match nalu.header().type_ { + match nalu.header.type_ { NaluType::VpsNut => { self.codec.parser.parse_vps(&nalu)?; } @@ -1152,7 +1152,7 @@ where NaluType::PpsNut => { if self.codec.parser.parse_pps(&nalu).is_err() { - let data = &nalu.data()[nalu.sc_offset()..nalu.offset() + nalu.size()]; + let data = &nalu.data[nalu.sc_offset..nalu.offset + nalu.size]; self.codec.pending_pps.push(Vec::from(data)) } } @@ -1175,14 +1175,13 @@ where | NaluType::CraNut => { let mut slice = self.codec.parser.parse_slice_header(nalu)?; - let first_slice_segment_in_pic_flag = - slice.header().first_slice_segment_in_pic_flag(); + let first_slice_segment_in_pic_flag = slice.header.first_slice_segment_in_pic_flag; - if slice.header().dependent_slice_segment_flag() { + if slice.header.dependent_slice_segment_flag { let previous_independent_header = self.codec.last_independent_slice_header.as_ref().ok_or(anyhow!("Cannot process an dependent slice without first processing and independent one"))?.clone(); slice.replace_header(previous_independent_header)?; } else { - self.codec.last_independent_slice_header = Some(slice.header().clone()); + self.codec.last_independent_slice_header = Some(slice.header.clone()); } let cur_pic = match self.codec.current_pic.take() { @@ -1240,7 +1239,7 @@ where let mut cursor = Cursor::new(bitstream); let nalu = Nalu::next(&mut cursor)?; - if nalu.header().type_ == NaluType::SpsNut { + if nalu.header.type_ == NaluType::SpsNut { let sps = self.codec.parser.parse_sps(&nalu)?.clone(); if matches!(self.decoding_state, DecodingState::AwaitingStreamInfo) { // If more SPS come along we will renegotiate in begin_picture(). @@ -1254,21 +1253,21 @@ where while let Ok(nalu) = Nalu::next(&mut cursor) { // In the Reset state we can resume decoding from any key frame. - if nalu.header().type_.is_idr() { + if nalu.header.type_.is_idr() { self.decoding_state = DecodingState::Decoding; break; } } } - let nalu_len = nalu.offset() + nalu.size(); + let nalu_len = nalu.offset + nalu.size; match &mut self.decoding_state { // Process parameter sets, but skip input until we get information // from the stream. DecodingState::AwaitingStreamInfo | DecodingState::Reset => { if matches!( - nalu.header().type_, + nalu.header.type_, NaluType::VpsNut | NaluType::SpsNut | NaluType::PpsNut ) { self.process_nalu(timestamp, nalu)?; diff --git a/src/decoder/stateless/h265/vaapi.rs b/src/decoder/stateless/h265/vaapi.rs index 0969273d..40650baf 100644 --- a/src/decoder/stateless/h265/vaapi.rs +++ b/src/decoder/stateless/h265/vaapi.rs @@ -486,14 +486,14 @@ fn build_iq_matrix(sps: &Sps, pps: &Pps) -> BufferType { for i in (0..6).step_by(3) { for j in 0..64 { - scaling_list_32x32[i / 3][j] = scaling_lists.scaling_list_32x32()[i][j]; + scaling_list_32x32[i / 3][j] = scaling_lists.scaling_list_32x32[i][j]; } } let mut scaling_list_dc_32x32 = [0; 2]; for i in (0..6).step_by(3) { scaling_list_dc_32x32[i / 3] = - (scaling_lists.scaling_list_dc_coef_minus8_32x32()[i] + 8) as u8; + (scaling_lists.scaling_list_dc_coef_minus8_32x32[i] + 8) as u8; } let mut scaling_list_4x4 = [[0; 16]; 6]; @@ -503,17 +503,17 @@ fn build_iq_matrix(sps: &Sps, pps: &Pps) -> BufferType { (0..6).for_each(|i| { super::get_raster_from_up_right_diagonal_4x4( - scaling_lists.scaling_list_4x4()[i], + scaling_lists.scaling_list_4x4[i], &mut scaling_list_4x4[i], ); super::get_raster_from_up_right_diagonal_8x8( - scaling_lists.scaling_list_8x8()[i], + scaling_lists.scaling_list_8x8[i], &mut scaling_list_8x8[i], ); super::get_raster_from_up_right_diagonal_8x8( - scaling_lists.scaling_list_16x16()[i], + scaling_lists.scaling_list_16x16[i], &mut scaling_list_16x16[i], ); }); @@ -531,7 +531,7 @@ fn build_iq_matrix(sps: &Sps, pps: &Pps) -> BufferType { scaling_list_16x16, scaling_list_32x32_r, scaling_lists - .scaling_list_dc_coef_minus8_16x16() + .scaling_list_dc_coef_minus8_16x16 .map(|x| (x + 8) as u8), scaling_list_dc_32x32, ))) @@ -681,7 +681,7 @@ impl StatelessH265DecoderBackend for Vaapi ref_pic_list1: &[Option>; 16], ) -> crate::decoder::stateless::StatelessBackendResult<()> { self.submit_last_slice(picture)?; - let hdr = slice.header(); + let hdr = &slice.header; let va_references = &picture.va_references; let ref_pic_list0 = build_slice_ref_pic_list(ref_pic_list0, va_references); @@ -689,26 +689,26 @@ impl StatelessH265DecoderBackend for Vaapi let long_slice_flags = libva::HevcLongSliceFlags::new( 0, - hdr.dependent_slice_segment_flag() as u32, - hdr.type_() as u32, - hdr.colour_plane_id() as u32, - hdr.sao_luma_flag() as u32, - hdr.sao_chroma_flag() as u32, - hdr.mvd_l1_zero_flag() as u32, - hdr.cabac_init_flag() as u32, - hdr.temporal_mvp_enabled_flag() as u32, - hdr.deblocking_filter_disabled_flag() as u32, - hdr.collocated_from_l0_flag() as u32, - hdr.loop_filter_across_slices_enabled_flag() as u32, + hdr.dependent_slice_segment_flag as u32, + hdr.type_ as u32, + hdr.colour_plane_id as u32, + hdr.sao_luma_flag as u32, + hdr.sao_chroma_flag as u32, + hdr.mvd_l1_zero_flag as u32, + hdr.cabac_init_flag as u32, + hdr.temporal_mvp_enabled_flag as u32, + hdr.deblocking_filter_disabled_flag as u32, + hdr.collocated_from_l0_flag as u32, + hdr.loop_filter_across_slices_enabled_flag as u32, ); - let collocated_ref_idx = if hdr.temporal_mvp_enabled_flag() { - hdr.collocated_ref_idx() + let collocated_ref_idx = if hdr.temporal_mvp_enabled_flag { + hdr.collocated_ref_idx } else { 0xff }; - let pwt = hdr.pred_weight_table(); + let pwt = &hdr.pred_weight_table; let mut delta_luma_weight_l0: [i8; 15usize] = Default::default(); let mut luma_offset_l0: [i8; 15usize] = Default::default(); @@ -720,24 +720,24 @@ impl StatelessH265DecoderBackend for Vaapi let mut chroma_offset_l1: [[i8; 2usize]; 15usize] = Default::default(); for i in 0..15 { - delta_luma_weight_l0[i] = pwt.delta_luma_weight_l0()[i]; - luma_offset_l0[i] = pwt.luma_offset_l0()[i]; + delta_luma_weight_l0[i] = pwt.delta_luma_weight_l0[i]; + luma_offset_l0[i] = pwt.luma_offset_l0[i]; - if hdr.type_().is_b() { - delta_luma_weight_l1[i] = pwt.delta_luma_weight_l1()[i]; - luma_offset_l1[i] = pwt.luma_offset_l1()[i]; + if hdr.type_.is_b() { + delta_luma_weight_l1[i] = pwt.delta_luma_weight_l1[i]; + luma_offset_l1[i] = pwt.luma_offset_l1[i]; } for j in 0..2 { - delta_chroma_weight_l0[i][j] = pwt.delta_chroma_weight_l0()[i][j]; - let delta_chroma_offset = pwt.delta_chroma_offset_l0()[i][j]; + delta_chroma_weight_l0[i][j] = pwt.delta_chroma_weight_l0[i][j]; + let delta_chroma_offset = pwt.delta_chroma_offset_l0[i][j]; - let chroma_weight_l0 = (1 << pwt.chroma_log2_weight_denom()) - + i32::from(pwt.delta_chroma_weight_l0()[i][j]); + let chroma_weight_l0 = (1 << pwt.chroma_log2_weight_denom) + + i32::from(pwt.delta_chroma_weight_l0[i][j]); let offset = sps.wp_offset_half_range_c as i32 + delta_chroma_offset as i32 - ((sps.wp_offset_half_range_c as i32 * chroma_weight_l0) - >> pwt.chroma_log2_weight_denom()); + >> pwt.chroma_log2_weight_denom); chroma_offset_l0[i][j] = clip3( -(sps.wp_offset_half_range_c as i32), @@ -745,16 +745,16 @@ impl StatelessH265DecoderBackend for Vaapi offset, ) as _; - if hdr.type_().is_b() { - delta_chroma_weight_l1[i][j] = pwt.delta_chroma_weight_l1()[i][j]; - let delta_chroma_offset = pwt.delta_chroma_offset_l1()[i][j]; + if hdr.type_.is_b() { + delta_chroma_weight_l1[i][j] = pwt.delta_chroma_weight_l1[i][j]; + let delta_chroma_offset = pwt.delta_chroma_offset_l1[i][j]; - let chroma_weight_l1 = (1 << pwt.chroma_log2_weight_denom()) - + i32::from(pwt.delta_chroma_weight_l1()[i][j]); + let chroma_weight_l1 = (1 << pwt.chroma_log2_weight_denom) + + i32::from(pwt.delta_chroma_weight_l1[i][j]); let offset = sps.wp_offset_half_range_c as i32 + delta_chroma_offset as i32 - ((sps.wp_offset_half_range_c as i32 * chroma_weight_l1) - >> pwt.chroma_log2_weight_denom()); + >> pwt.chroma_log2_weight_denom); chroma_offset_l1[i][j] = clip3( -(sps.wp_offset_half_range_c as i32), @@ -766,23 +766,23 @@ impl StatelessH265DecoderBackend for Vaapi } let slice_param = SliceParameterBufferHEVC::new( - slice.nalu().size() as u32, + slice.nalu.size as u32, 0, libva::constants::VA_SLICE_DATA_FLAG_ALL, - (hdr.header_bit_size() / 8) as _, - hdr.segment_address(), + (hdr.header_bit_size / 8) as _, + hdr.segment_address, [ref_pic_list0, ref_pic_list1], &long_slice_flags, collocated_ref_idx, - hdr.num_ref_idx_l0_active_minus1(), - hdr.num_ref_idx_l1_active_minus1(), - hdr.qp_delta(), - hdr.cb_qp_offset(), - hdr.cr_qp_offset(), - hdr.beta_offset_div2(), - hdr.tc_offset_div2(), - pwt.luma_log2_weight_denom(), - pwt.delta_chroma_log2_weight_denom(), + hdr.num_ref_idx_l0_active_minus1, + hdr.num_ref_idx_l1_active_minus1, + hdr.qp_delta, + hdr.cb_qp_offset, + hdr.cr_qp_offset, + hdr.beta_offset_div2, + hdr.tc_offset_div2, + pwt.luma_log2_weight_denom, + pwt.delta_chroma_log2_weight_denom, delta_luma_weight_l0, luma_offset_l0, delta_chroma_weight_l0, @@ -791,10 +791,10 @@ impl StatelessH265DecoderBackend for Vaapi luma_offset_l1, delta_chroma_weight_l1, chroma_offset_l1, - hdr.five_minus_max_num_merge_cand(), - hdr.num_entry_point_offsets() as _, + hdr.five_minus_max_num_merge_cand, + hdr.num_entry_point_offsets as _, 0, - hdr.n_emulation_prevention_bytes() as _, + hdr.n_emulation_prevention_bytes as _, ); let va_profile = sps.va_profile()?; @@ -802,8 +802,8 @@ impl StatelessH265DecoderBackend for Vaapi let slice_param_ext = if is_range_extension_profile(va_profile) || is_scc_ext_profile(va_profile) { let slice_ext_flags = HevcSliceExtFlags::new( - hdr.cu_chroma_qp_offset_enabled_flag() as u32, - hdr.use_integer_mv_flag() as u32, + hdr.cu_chroma_qp_offset_enabled_flag as u32, + hdr.use_integer_mv_flag as u32, ); let slice_param_ext = SliceParameterBufferHEVCRext::new( @@ -812,9 +812,9 @@ impl StatelessH265DecoderBackend for Vaapi luma_offset_l1.map(i16::from), chroma_offset_l1.map(|outer| outer.map(i16::from)), &slice_ext_flags, - hdr.slice_act_y_qp_offset(), - hdr.slice_act_cb_qp_offset(), - hdr.slice_act_cr_qp_offset(), + hdr.slice_act_y_qp_offset, + hdr.slice_act_cb_qp_offset, + hdr.slice_act_cr_qp_offset, ); Some(slice_param_ext) @@ -822,7 +822,7 @@ impl StatelessH265DecoderBackend for Vaapi None }; - let slice_data = Vec::from(slice.nalu().as_ref()); + let slice_data = Vec::from(slice.nalu.as_ref()); picture.last_slice = Some((slice_param, slice_param_ext, slice_data)); diff --git a/src/utils.rs b/src/utils.rs index 01ab408e..ce52e658 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -84,9 +84,9 @@ impl<'a> Iterator for NalIterator<'a, H264Nalu<'a>> { fn next(&mut self) -> Option { H264Nalu::next(&mut self.0) .map(|n| { - let start = n.sc_offset(); - let end = n.offset() + n.size(); - &n.data()[start..end] + let start = n.sc_offset; + let end = n.offset + n.size; + &n.data[start..end] }) .ok() } @@ -98,9 +98,9 @@ impl<'a> Iterator for NalIterator<'a, H265Nalu<'a>> { fn next(&mut self) -> Option { H265Nalu::next(&mut self.0) .map(|n| { - let start = n.sc_offset(); - let end = n.offset() + n.size(); - &n.data()[start..end] + let start = n.sc_offset; + let end = n.offset + n.size; + &n.data[start..end] }) .ok() } From 705d20e8191df467ac403732f9faa71c431fdcc1 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Thu, 30 Nov 2023 16:58:13 +0000 Subject: [PATCH 3/9] decoders: add support for multiple pools We need to support new pools to cater to SVC content where multiple spatial layers are being decoded, otherwise we would have to clear bigger frames before decoding smaller layers to avoid leaving trash in them and breaking the decode process. This patch sets the stage by allowing multiple pools to exists, but only a single pool is created in the VA code for now. Subsequent patches will build on this one to actually allocate multiple pools depending on the content being decoded. --- src/backend/dummy.rs | 5 +- src/backend/vaapi.rs | 80 +++++++++++++++++++++-------- src/decoder.rs | 8 +-- src/decoder/stateless.rs | 40 +++++++++++---- src/decoder/stateless/av1.rs | 18 +++++-- src/decoder/stateless/av1/vaapi.rs | 8 +-- src/decoder/stateless/h264.rs | 17 ++++-- src/decoder/stateless/h264/vaapi.rs | 9 ++-- src/decoder/stateless/h265.rs | 18 +++++-- src/decoder/stateless/h265/vaapi.rs | 8 +-- src/decoder/stateless/vp8.rs | 19 +++++-- src/decoder/stateless/vp8/vaapi.rs | 14 ++--- src/decoder/stateless/vp9.rs | 17 ++++-- src/decoder/stateless/vp9/vaapi.rs | 12 ++--- src/utils.rs | 26 ++++++---- 15 files changed, 213 insertions(+), 86 deletions(-) diff --git a/src/backend/dummy.rs b/src/backend/dummy.rs index 3896effe..63c1e6a7 100644 --- a/src/backend/dummy.rs +++ b/src/backend/dummy.rs @@ -8,6 +8,7 @@ use std::cell::RefCell; use std::rc::Rc; +use crate::decoder::stateless::PoolLayer; use crate::decoder::stateless::StatelessCodec; use crate::decoder::stateless::StatelessDecoderBackend; use crate::decoder::stateless::StatelessDecoderBackendPicture; @@ -141,7 +142,7 @@ impl StatelessDecoderBackend for Backend { Some(&self.stream_info) } - fn frame_pool(&mut self) -> &mut dyn FramePool<()> { - self + fn frame_pool(&mut self, _: PoolLayer) -> Vec<&mut dyn FramePool<()>> { + vec![self] } } diff --git a/src/backend/vaapi.rs b/src/backend/vaapi.rs index b31cf9fa..ccec627e 100644 --- a/src/backend/vaapi.rs +++ b/src/backend/vaapi.rs @@ -29,6 +29,7 @@ use libva::VAConfigAttribType; use libva::VaError; use crate::backend::vaapi::surface_pool::SurfacePool; +use crate::decoder::stateless::PoolLayer; use crate::decoder::stateless::StatelessBackendError; use crate::decoder::stateless::StatelessBackendResult; use crate::decoder::stateless::StatelessCodec; @@ -534,9 +535,9 @@ impl StreamMetadataState { hdr: S, format_map: Option<&FormatMap>, old_metadata_state: StreamMetadataState, - old_surface_pool: Rc>>, + old_surface_pools: Vec>>>, supports_context_reuse: bool, - ) -> anyhow::Result<(StreamMetadataState, Rc>>)> { + ) -> anyhow::Result<(StreamMetadataState, Vec>>>)> { let va_profile = hdr.va_profile()?; let rt_format = hdr.rt_format()?; @@ -577,7 +578,7 @@ impl StreamMetadataState { height: visible_rect.1 .1 - visible_rect.0 .1, }; - let (config, context, surface_pool) = match old_metadata_state { + let (config, context, surface_pools) = match old_metadata_state { // Nothing has changed for VAAPI, reuse current context. // // This can happen as the decoder cannot possibly know whether a @@ -588,7 +589,7 @@ impl StreamMetadataState { && old_state.rt_format == rt_format && old_state.profile == va_profile => { - (old_state.config, old_state.context, old_surface_pool) + (old_state.config, old_state.context, old_surface_pools) } // The resolution has changed, but we support context reuse. Reuse // current context. @@ -597,7 +598,7 @@ impl StreamMetadataState { && old_state.rt_format == rt_format && old_state.profile == va_profile => { - (old_state.config, old_state.context, old_surface_pool) + (old_state.config, old_state.context, old_surface_pools) } // Create new context. _ => { @@ -618,18 +619,20 @@ impl StreamMetadataState { true, )?; - let surface_pool = Rc::new(RefCell::new(SurfacePool::new( + let surface_pools = vec![Rc::new(RefCell::new(SurfacePool::new( Rc::clone(display), rt_format, Some(libva::UsageHint::USAGE_HINT_DECODER), coded_resolution, - ))); + )))]; - (config, context, surface_pool) + (config, context, surface_pools) } }; - if !surface_pool + /* for now, we are sure to have at least one pool, so unwrapping will not + * panic */ + if !&surface_pools[0] .borrow() .coded_resolution() .can_contain(coded_resolution) @@ -641,7 +644,7 @@ impl StreamMetadataState { // video-conferencing applications, which are subject to bandwidth // fluctuations, this can be very advantageous as it avoid // reallocating all the time. - surface_pool + surface_pools[0] .borrow_mut() .set_coded_resolution(coded_resolution); } @@ -671,7 +674,7 @@ impl StreamMetadataState { rt_format, profile: va_profile, }), - surface_pool, + surface_pools, )) } } @@ -914,8 +917,10 @@ where { /// VA display in use for this stream. display: Rc, - /// A pool of surfaces. We reuse surfaces as they are expensive to allocate. - pub(crate) surface_pool: Rc>>, + /// Pools of surfaces. We reuse surfaces as they are expensive to allocate. + /// We allow for multiple pools so as to support one spatial layer per pool + /// when needed. + pub(crate) surface_pools: Vec>>>, /// The metadata state. Updated whenever the decoder reads new data from the stream. pub(crate) metadata_state: StreamMetadataState, /// Whether the codec supports context reuse on DRC. This is only supported @@ -929,16 +934,16 @@ where { pub(crate) fn new(display: Rc, supports_context_reuse: bool) -> Self { // Create a pool with reasonable defaults, as we don't know the format of the stream yet. - let surface_pool = Rc::new(RefCell::new(SurfacePool::new( + let surface_pools = vec![Rc::new(RefCell::new(SurfacePool::new( Rc::clone(&display), libva::constants::VA_RT_FORMAT_YUV420, Some(libva::UsageHint::USAGE_HINT_DECODER), Resolution::from((16, 16)), - ))); + )))]; Self { display, - surface_pool, + surface_pools, metadata_state: StreamMetadataState::Unparsed, supports_context_reuse, } @@ -954,12 +959,13 @@ where let old_metadata_state = std::mem::replace(&mut self.metadata_state, StreamMetadataState::Unparsed); - (self.metadata_state, self.surface_pool) = StreamMetadataState::open( + let old_surface_pools = self.surface_pools.drain(..).collect(); + (self.metadata_state, self.surface_pools) = StreamMetadataState::open( &self.display, stream_params, None, old_metadata_state, - Rc::clone(&self.surface_pool), + old_surface_pools, self.supports_context_reuse, )?; @@ -1000,6 +1006,14 @@ where Ok(formats.into_iter().map(|f| f.decoded_format).collect()) } + + pub(crate) fn highest_pool(&mut self) -> &Rc>> { + /* we guarantee that there is at least one pool, at minimum */ + self.surface_pools + .iter() + .max_by_key(|p| p.borrow().coded_resolution().height) + .unwrap() + } } /// Shortcut for pictures used for the VAAPI backend. @@ -1044,12 +1058,13 @@ where // // This does not apply to other (future) backends, like V4L2, which // need to reallocate on format change. - (self.metadata_state, self.surface_pool) = StreamMetadataState::open( + let old_surface_pools = self.surface_pools.drain(..).collect(); + (self.metadata_state, self.surface_pools) = StreamMetadataState::open( &self.display, format_info, Some(map_format), old_metadata_state, - Rc::clone(&self.surface_pool), + old_surface_pools, self.supports_context_reuse, )?; @@ -1059,8 +1074,29 @@ where } } - fn frame_pool(&mut self) -> &mut dyn FramePool { - &mut self.surface_pool + fn frame_pool(&mut self, layer: PoolLayer) -> Vec<&mut dyn FramePool> { + if let PoolLayer::Highest = layer { + return vec![self + .surface_pools + .iter_mut() + .max_by_key(|other| other.coded_resolution().height) + .unwrap()]; + } + + self.surface_pools + .iter_mut() + .filter(|pool| { + match layer { + PoolLayer::Highest => unreachable!(), + PoolLayer::Layer(resolution) => pool.coded_resolution() == resolution, + PoolLayer::All => { + /* let all through */ + true + } + } + }) + .map(|x| x as &mut dyn FramePool) + .collect() } fn stream_info(&self) -> Option<&StreamInfo> { diff --git a/src/decoder.rs b/src/decoder.rs index 4c44eab1..75893147 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -13,6 +13,7 @@ pub mod stateless; use std::collections::VecDeque; +use crate::decoder::stateless::PoolLayer; use crate::DecodedFormat; use crate::Resolution; @@ -62,7 +63,7 @@ pub struct StreamInfo { pub coded_resolution: Resolution, /// Display resolution of the stream, i.e. the part of the decoded frames we want to display. pub display_resolution: Resolution, - /// Minimum number of output frames required for decoding to proceed. + /// Minimum number of output frames per layer required for decoding to proceed. /// /// Codecs keep some frames as references and cannot decode immediately into them again after /// they are returned. Allocating at least this number of frames guarantees that the decoder @@ -81,8 +82,9 @@ pub struct StreamInfo { pub trait DecoderFormatNegotiator<'a, M> { /// Returns the current decoding parameters, as extracted from the stream. fn stream_info(&self) -> &StreamInfo; - /// Returns the frame pool in use for the decoder, set up for the new format. - fn frame_pool(&mut self) -> &mut dyn FramePool; + /// Returns the frame pool in use for the decoder for `layer` set up for the + /// new format. + fn frame_pool(&mut self, layer: PoolLayer) -> Vec<&mut dyn FramePool>; fn try_format(&mut self, format: DecodedFormat) -> anyhow::Result<()>; } diff --git a/src/decoder/stateless.rs b/src/decoder/stateless.rs index 342ea57b..8be4a01e 100644 --- a/src/decoder/stateless.rs +++ b/src/decoder/stateless.rs @@ -112,8 +112,11 @@ pub trait StatelessDecoderBackend: /// Returns the current decoding parameters, as parsed from the stream. fn stream_info(&self) -> Option<&StreamInfo>; - /// Returns the frame pool currently in use by the backend. - fn frame_pool(&mut self) -> &mut dyn FramePool<::Descriptor>; + /// Returns the frame pool currently in use by the backend for `layer`. + fn frame_pool( + &mut self, + layer: PoolLayer, + ) -> Vec<&mut dyn FramePool<::Descriptor>>; /// Try altering the decoded format. fn try_format( @@ -171,8 +174,8 @@ where self.decoder.try_format(format) } - fn frame_pool(&mut self) -> &mut dyn FramePool { - self.decoder.frame_pool() + fn frame_pool(&mut self, layer: PoolLayer) -> Vec<&mut dyn FramePool> { + self.decoder.frame_pool(layer) } fn stream_info(&self) -> &StreamInfo { @@ -190,6 +193,17 @@ where } } +/// Controls the pool returned by [`StatelessVideoDecoder::frame_pool`]. +#[derive(Debug, Clone, Copy)] +pub enum PoolLayer { + /// The pool for the highest spatial layer. + Highest, + /// The pool for the given resolution. + Layer(Resolution), + /// All pools. + All, +} + /// Stateless video decoder interface. /// /// A stateless decoder differs from a stateful one in that its input and output queues are not @@ -228,9 +242,14 @@ pub trait StatelessVideoDecoder { /// [`next_event`]: StatelessVideoDecoder::next_event fn flush(&mut self) -> Result<(), DecodeError>; - /// Returns the frame pool in use with the decoder. Useful to add new frames as decode. - /// targets. - fn frame_pool(&mut self) -> &mut dyn FramePool; + /// Returns the frame pool for `resolution` in use with the decoder. If + /// `resolution` is None, the pool of the highest resolution is returned. + /// + /// Multiple pools may be in use for SVC streams, since each spatial layer + /// will receive its frames from a separate pool. + /// + /// Useful to add new frames as decode targets. + fn frame_pool(&mut self, layer: PoolLayer) -> Vec<&mut dyn FramePool>; fn stream_info(&self) -> Option<&StreamInfo>; @@ -311,8 +330,11 @@ where C: StatelessCodec, B: StatelessDecoderBackend, { - fn frame_pool(&mut self) -> &mut dyn FramePool<::Descriptor> { - self.backend.frame_pool() + fn frame_pool( + &mut self, + layer: PoolLayer, + ) -> Vec<&mut dyn FramePool<::Descriptor>> { + self.backend.frame_pool(layer) } fn stream_info(&self) -> Option<&StreamInfo> { diff --git a/src/decoder/stateless/av1.rs b/src/decoder/stateless/av1.rs index f8296962..072c1b2a 100644 --- a/src/decoder/stateless/av1.rs +++ b/src/decoder/stateless/av1.rs @@ -25,6 +25,8 @@ use crate::decoder::stateless::StatelessDecoderBackend; use crate::decoder::stateless::StatelessDecoderFormatNegotiator; use crate::decoder::stateless::StatelessVideoDecoder; use crate::decoder::DecodedHandle; +use crate::decoder::FramePool; +use crate::decoder::PoolLayer; use crate::decoder::stateless::DecodeError; use crate::decoder::stateless::StatelessCodec; @@ -308,7 +310,16 @@ where let mut consumed = 0; let nframes = self.count_frames(bitstream); - let num_free_frames = self.backend.frame_pool().num_free_frames(); + /* we do not know the resolution at this point, as we haven't parsed the + * frames yet. Be conservative and check whether we have enough frames + * across all layers */ + let num_free_frames = self + .backend + .frame_pool(PoolLayer::All) + .iter() + .map(|x| x.num_free_frames()) + .min() + .ok_or(anyhow!("No pool found"))?; if matches!(self.decoding_state, DecodingState::Decoding) && num_free_frames < nframes { return Err(DecodeError::NotEnoughOutputBuffers( @@ -473,8 +484,9 @@ where fn frame_pool( &mut self, - ) -> &mut dyn crate::decoder::FramePool<::Descriptor> { - self.backend.frame_pool() + layer: PoolLayer, + ) -> Vec<&mut dyn FramePool<::Descriptor>> { + self.backend.frame_pool(layer) } fn stream_info(&self) -> Option<&crate::decoder::StreamInfo> { diff --git a/src/decoder/stateless/av1/vaapi.rs b/src/decoder/stateless/av1/vaapi.rs index 3dda0840..a022001d 100644 --- a/src/decoder/stateless/av1/vaapi.rs +++ b/src/decoder/stateless/av1/vaapi.rs @@ -582,13 +582,13 @@ impl StatelessAV1DecoderBackend for VaapiB timestamp: u64, reference_frames: &[Option; NUM_REF_FRAMES], ) -> crate::decoder::stateless::StatelessBackendResult { - let metadata = self.metadata_state.get_parsed()?; - let surface = self - .surface_pool + let highest_pool = self.highest_pool(); + let surface = highest_pool .borrow_mut() - .get_surface(&self.surface_pool) + .get_surface(highest_pool) .ok_or(StatelessBackendError::OutOfResources)?; + let metadata = self.metadata_state.get_parsed()?; let mut picture = VaPicture::new(timestamp, Rc::clone(&metadata.context), surface); let surface_id = picture.surface().id(); diff --git a/src/decoder/stateless/h264.rs b/src/decoder/stateless/h264.rs index 71c39fc6..264eff92 100644 --- a/src/decoder/stateless/h264.rs +++ b/src/decoder/stateless/h264.rs @@ -32,6 +32,7 @@ use crate::codec::h264::picture::PictureData; use crate::codec::h264::picture::Reference; use crate::decoder::stateless::DecodeError; use crate::decoder::stateless::DecodingState; +use crate::decoder::stateless::PoolLayer; use crate::decoder::stateless::StatelessBackendResult; use crate::decoder::stateless::StatelessCodec; use crate::decoder::stateless::StatelessDecoder; @@ -1496,7 +1497,14 @@ where return Err(DecodeError::CheckEvents); } - if self.backend.frame_pool().num_free_frames() == 0 { + if self + .backend + .frame_pool(PoolLayer::Highest) + .pop() + .ok_or(anyhow!("No pool found"))? + .num_free_frames() + == 0 + { return Err(DecodeError::NotEnoughOutputBuffers(1)); } @@ -1951,8 +1959,11 @@ where }) } - fn frame_pool(&mut self) -> &mut dyn FramePool<::Descriptor> { - self.frame_pool() + fn frame_pool( + &mut self, + layer: PoolLayer, + ) -> Vec<&mut dyn FramePool<::Descriptor>> { + self.frame_pool(layer) } fn stream_info(&self) -> Option<&StreamInfo> { diff --git a/src/decoder/stateless/h264/vaapi.rs b/src/decoder/stateless/h264/vaapi.rs index 8f11aa91..044b0946 100644 --- a/src/decoder/stateless/h264/vaapi.rs +++ b/src/decoder/stateless/h264/vaapi.rs @@ -549,13 +549,14 @@ impl StatelessH264DecoderBackend for Vaapi _: &PictureData, timestamp: u64, ) -> StatelessBackendResult { - let metadata = self.metadata_state.get_parsed()?; - let surface = self - .surface_pool + let highest_pool = self.highest_pool(); + let surface = highest_pool .borrow_mut() - .get_surface(&self.surface_pool) + .get_surface(highest_pool) .ok_or(StatelessBackendError::OutOfResources)?; + let metadata = self.metadata_state.get_parsed()?; + Ok(VaPicture::new( timestamp, Rc::clone(&metadata.context), diff --git a/src/decoder/stateless/h265.rs b/src/decoder/stateless/h265.rs index ff667863..d00e6b3f 100644 --- a/src/decoder/stateless/h265.rs +++ b/src/decoder/stateless/h265.rs @@ -28,6 +28,7 @@ use crate::codec::h265::picture::PictureData; use crate::codec::h265::picture::Reference; use crate::decoder::stateless::DecodeError; use crate::decoder::stateless::DecodingState; +use crate::decoder::stateless::PoolLayer; use crate::decoder::stateless::StatelessBackendResult; use crate::decoder::stateless::StatelessCodec; use crate::decoder::stateless::StatelessDecoder; @@ -922,7 +923,15 @@ where timestamp: u64, slice: &Slice, ) -> Result>, DecodeError> { - if self.backend.frame_pool().num_free_frames() == 0 { + let layer = PoolLayer::Layer(self.coded_resolution); + if self + .backend + .frame_pool(layer) + .pop() + .ok_or(anyhow!("Pool not found"))? + .num_free_frames() + == 0 + { return Err(DecodeError::NotEnoughOutputBuffers(1)); } @@ -1313,8 +1322,11 @@ where }) } - fn frame_pool(&mut self) -> &mut dyn FramePool<::Descriptor> { - self.backend.frame_pool() + fn frame_pool( + &mut self, + layer: PoolLayer, + ) -> Vec<&mut dyn FramePool<::Descriptor>> { + self.backend.frame_pool(layer) } fn stream_info(&self) -> Option<&StreamInfo> { diff --git a/src/decoder/stateless/h265/vaapi.rs b/src/decoder/stateless/h265/vaapi.rs index 40650baf..dadb4835 100644 --- a/src/decoder/stateless/h265/vaapi.rs +++ b/src/decoder/stateless/h265/vaapi.rs @@ -597,12 +597,12 @@ impl StatelessH265DecoderBackend for Vaapi _: &PictureData, timestamp: u64, ) -> StatelessBackendResult { - let metadata = self.metadata_state.get_parsed()?; - let surface = self - .surface_pool + let highest_pool = self.highest_pool(); + let surface = highest_pool .borrow_mut() - .get_surface(&self.surface_pool) + .get_surface(highest_pool) .ok_or(StatelessBackendError::OutOfResources)?; + let metadata = self.metadata_state.get_parsed()?; Ok(VaapiH265Picture { picture: VaPicture::new(timestamp, Rc::clone(&metadata.context), surface), diff --git a/src/decoder/stateless/vp8.rs b/src/decoder/stateless/vp8.rs index 6d145c39..b5f5b633 100644 --- a/src/decoder/stateless/vp8.rs +++ b/src/decoder/stateless/vp8.rs @@ -7,6 +7,8 @@ mod dummy; #[cfg(feature = "vaapi")] mod vaapi; +use anyhow::anyhow; + use crate::codec::vp8::parser::Frame; use crate::codec::vp8::parser::Header; use crate::codec::vp8::parser::MbLfAdjustments; @@ -14,6 +16,7 @@ use crate::codec::vp8::parser::Parser; use crate::codec::vp8::parser::Segmentation; use crate::decoder::stateless::DecodeError; use crate::decoder::stateless::DecodingState; +use crate::decoder::stateless::PoolLayer; use crate::decoder::stateless::StatelessBackendResult; use crate::decoder::stateless::StatelessCodec; use crate::decoder::stateless::StatelessDecoder; @@ -169,7 +172,14 @@ where { /// Handle a single frame. fn handle_frame(&mut self, frame: Frame, timestamp: u64) -> Result<(), DecodeError> { - if self.backend.frame_pool().num_free_frames() == 0 { + if self + .backend + .frame_pool(PoolLayer::Highest) + .pop() + .ok_or(DecodeError::DecoderError(anyhow!("No pool found")))? + .num_free_frames() + == 0 + { return Err(DecodeError::NotEnoughOutputBuffers(1)); } @@ -275,8 +285,11 @@ where }) } - fn frame_pool(&mut self) -> &mut dyn FramePool<::Descriptor> { - self.backend.frame_pool() + fn frame_pool( + &mut self, + layer: PoolLayer, + ) -> Vec<&mut dyn FramePool<::Descriptor>> { + self.backend.frame_pool(layer) } fn stream_info(&self) -> Option<&StreamInfo> { diff --git a/src/decoder/stateless/vp8/vaapi.rs b/src/decoder/stateless/vp8/vaapi.rs index c6a1089b..6b567406 100644 --- a/src/decoder/stateless/vp8/vaapi.rs +++ b/src/decoder/stateless/vp8/vaapi.rs @@ -241,9 +241,15 @@ impl StatelessVp8DecoderBackend for VaapiB libva::constants::VA_INVALID_SURFACE }; + let highest_pool = self.highest_pool(); + let surface = highest_pool + .borrow_mut() + .get_surface(highest_pool) + .ok_or(StatelessBackendError::OutOfResources)?; + + let coded_resolution = self.highest_pool().borrow().coded_resolution(); let metadata = self.metadata_state.get_parsed()?; let context = &metadata.context; - let coded_resolution = self.surface_pool.borrow().coded_resolution(); let iq_buffer = context .create_buffer(build_iq_matrix(picture, segmentation)?) @@ -273,12 +279,6 @@ impl StatelessVp8DecoderBackend for VaapiB .create_buffer(libva::BufferType::SliceData(Vec::from(bitstream))) .context("while creating slice data buffer")?; - let surface = self - .surface_pool - .borrow_mut() - .get_surface(&self.surface_pool) - .ok_or(StatelessBackendError::OutOfResources)?; - let mut va_picture = VaPicture::new(timestamp, Rc::clone(context), surface); // Add buffers with the parsed data. diff --git a/src/decoder/stateless/vp9.rs b/src/decoder/stateless/vp9.rs index 5bcd1547..02a4f1c4 100644 --- a/src/decoder/stateless/vp9.rs +++ b/src/decoder/stateless/vp9.rs @@ -7,6 +7,7 @@ mod dummy; #[cfg(feature = "vaapi")] mod vaapi; +use anyhow::anyhow; use log::debug; use crate::codec::vp9::parser::BitDepth; @@ -19,6 +20,7 @@ use crate::codec::vp9::parser::MAX_SEGMENTS; use crate::codec::vp9::parser::NUM_REF_FRAMES; use crate::decoder::stateless::DecodeError; use crate::decoder::stateless::DecodingState; +use crate::decoder::stateless::PoolLayer; use crate::decoder::stateless::StatelessBackendResult; use crate::decoder::stateless::StatelessCodec; use crate::decoder::stateless::StatelessDecoder; @@ -212,7 +214,13 @@ where fn decode(&mut self, timestamp: u64, bitstream: &[u8]) -> Result { let frames = self.codec.parser.parse_chunk(bitstream)?; - let num_free_frames = self.backend.frame_pool().num_free_frames(); + let num_free_frames = self + .backend + .frame_pool(PoolLayer::Highest) + .pop() + .ok_or(DecodeError::DecoderError(anyhow!("No pool found")))? + .num_free_frames(); + if matches!(self.decoding_state, DecodingState::Decoding) && num_free_frames < frames.len() { return Err(DecodeError::NotEnoughOutputBuffers( @@ -292,8 +300,11 @@ where }) } - fn frame_pool(&mut self) -> &mut dyn FramePool<::Descriptor> { - self.backend.frame_pool() + fn frame_pool( + &mut self, + layer: PoolLayer, + ) -> Vec<&mut dyn FramePool<::Descriptor>> { + self.backend.frame_pool(layer) } fn stream_info(&self) -> Option<&StreamInfo> { diff --git a/src/decoder/stateless/vp9/vaapi.rs b/src/decoder/stateless/vp9/vaapi.rs index e3a7f697..fe2df524 100644 --- a/src/decoder/stateless/vp9/vaapi.rs +++ b/src/decoder/stateless/vp9/vaapi.rs @@ -263,6 +263,12 @@ impl StatelessVp9DecoderBackend for VaapiB .try_into() .unwrap(); + let highest_pool = self.highest_pool(); + let surface = highest_pool + .borrow_mut() + .get_surface(highest_pool) + .ok_or(StatelessBackendError::OutOfResources)?; + let metadata = self.metadata_state.get_parsed()?; let context = &metadata.context; @@ -278,12 +284,6 @@ impl StatelessVp9DecoderBackend for VaapiB .create_buffer(libva::BufferType::SliceData(Vec::from(bitstream))) .context("while creating slice data buffer")?; - let surface = self - .surface_pool - .borrow_mut() - .get_surface(&self.surface_pool) - .ok_or(StatelessBackendError::OutOfResources)?; - let mut va_picture = VaPicture::new(timestamp, Rc::clone(context), surface); // Add buffers with the parsed data. diff --git a/src/utils.rs b/src/utils.rs index ce52e658..4a4d5691 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -17,6 +17,7 @@ use bytes::Buf; use crate::codec::h264::parser::Nalu as H264Nalu; use crate::codec::h265::parser::Nalu as H265Nalu; use crate::decoder::stateless::DecodeError; +use crate::decoder::stateless::PoolLayer; use crate::decoder::stateless::StatelessVideoDecoder; use crate::decoder::BlockingMode; use crate::decoder::DecodedHandle; @@ -130,16 +131,21 @@ where } DecoderEvent::FormatChanged(mut format_setter) => { format_setter.try_format(output_format).unwrap(); - // Allocate the missing number of buffers in our pool for decoding to succeed. - let min_num_frames = format_setter.stream_info().min_num_frames; - let pool_num_frames = format_setter.frame_pool().num_managed_frames(); - if pool_num_frames < min_num_frames { - let frames = allocate_new_frames( - format_setter.stream_info(), - min_num_frames - pool_num_frames, - )?; - let pool = format_setter.frame_pool(); - pool.add_frames(frames).unwrap(); + let stream_info = format_setter.stream_info().clone(); + let min_num_frames = stream_info.min_num_frames; + /* we need to account for multiple layers if applicable for + * the stream */ + let pools = format_setter.frame_pool(PoolLayer::All); + for pool in pools { + // Allocate the missing number of buffers in our pool for decoding to succeed. + let pool_num_frames = pool.num_managed_frames(); + if pool_num_frames < min_num_frames { + let frames = allocate_new_frames( + &stream_info, + min_num_frames - pool_num_frames, + )?; + pool.add_frames(frames).unwrap(); + } } } } From cefccd1e232ffcfcb34c40a1d13267efffdb7f83 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Tue, 5 Dec 2023 12:51:35 +0000 Subject: [PATCH 4/9] decoders: create more than one pool when needed The previous commit added the capability of drawing frames from multiple pools. This commits follows up by actually creating more than one pool when needed. --- src/backend/vaapi.rs | 65 +++++++++++++++++++---------- src/decoder/stateless/av1.rs | 16 +++++-- src/decoder/stateless/av1/dummy.rs | 1 + src/decoder/stateless/av1/vaapi.rs | 18 +++++++- src/decoder/stateless/h264/vaapi.rs | 3 +- src/decoder/stateless/h265/vaapi.rs | 3 +- src/decoder/stateless/vp8/vaapi.rs | 3 +- src/decoder/stateless/vp9/vaapi.rs | 3 +- 8 files changed, 80 insertions(+), 32 deletions(-) diff --git a/src/backend/vaapi.rs b/src/backend/vaapi.rs index ccec627e..bc32763e 100644 --- a/src/backend/vaapi.rs +++ b/src/backend/vaapi.rs @@ -509,6 +509,16 @@ pub(crate) struct ParsedStreamMetadata { profile: i32, } +/// Controls how the decoder should create its surface pool. +#[derive(Clone, Debug)] +pub(crate) enum PoolCreationMode { + /// Create a single pool and assume a single spatial layer. Used for non-SVC + /// content. + Highest, + /// Create a pool for each spatial layer. Used for SVC content. + Layers(Vec), +} + /// State of the input stream, which can be either unparsed (we don't know the stream properties /// yet) or parsed (we know the stream properties and are ready to decode). pub(crate) enum StreamMetadataState { @@ -537,6 +547,7 @@ impl StreamMetadataState { old_metadata_state: StreamMetadataState, old_surface_pools: Vec>>>, supports_context_reuse: bool, + pool_creation_mode: PoolCreationMode, ) -> anyhow::Result<(StreamMetadataState, Vec>>>)> { let va_profile = hdr.va_profile()?; let rt_format = hdr.rt_format()?; @@ -578,6 +589,11 @@ impl StreamMetadataState { height: visible_rect.1 .1 - visible_rect.0 .1, }; + let layers = match pool_creation_mode { + PoolCreationMode::Highest => vec![coded_resolution], + PoolCreationMode::Layers(layers) => layers, + }; + let (config, context, surface_pools) = match old_metadata_state { // Nothing has changed for VAAPI, reuse current context. // @@ -619,34 +635,30 @@ impl StreamMetadataState { true, )?; - let surface_pools = vec![Rc::new(RefCell::new(SurfacePool::new( - Rc::clone(display), - rt_format, - Some(libva::UsageHint::USAGE_HINT_DECODER), - coded_resolution, - )))]; + let surface_pools = layers + .iter() + .map(|layer| { + Rc::new(RefCell::new(SurfacePool::new( + Rc::clone(display), + rt_format, + Some(libva::UsageHint::USAGE_HINT_DECODER), + *layer, + ))) + }) + .collect(); (config, context, surface_pools) } }; - /* for now, we are sure to have at least one pool, so unwrapping will not - * panic */ - if !&surface_pools[0] - .borrow() - .coded_resolution() - .can_contain(coded_resolution) - { - // Purge the old surfaces to receive the new ones below. This - // ensures that the pool is always set to the largest resolution in - // the stream, so that no new allocations are needed when we come - // across a smaller resolution. In particular, for - // video-conferencing applications, which are subject to bandwidth - // fluctuations, this can be very advantageous as it avoid - // reallocating all the time. - surface_pools[0] - .borrow_mut() - .set_coded_resolution(coded_resolution); + /* sanity check */ + assert!(surface_pools.len() == layers.len()); + for (pool, layer) in surface_pools.iter().zip(layers.iter()) { + let mut pool = pool.borrow_mut(); + if !pool.coded_resolution().can_contain(*layer) { + /* this will purge the old surfaces by not reclaiming them */ + pool.set_coded_resolution(*layer); + } } Ok(( @@ -926,6 +938,8 @@ where /// Whether the codec supports context reuse on DRC. This is only supported /// by VP9 and AV1. supports_context_reuse: bool, + /// Controls the creation of surface pools. + pool_creation_mode: PoolCreationMode, } impl VaapiBackend @@ -946,12 +960,14 @@ where surface_pools, metadata_state: StreamMetadataState::Unparsed, supports_context_reuse, + pool_creation_mode: PoolCreationMode::Highest, } } pub(crate) fn new_sequence( &mut self, stream_params: &StreamData, + pool_creation_mode: PoolCreationMode, ) -> StatelessBackendResult<()> where for<'a> &'a StreamData: VaStreamInfo, @@ -967,8 +983,10 @@ where old_metadata_state, old_surface_pools, self.supports_context_reuse, + pool_creation_mode.clone(), )?; + self.pool_creation_mode = pool_creation_mode; Ok(()) } @@ -1066,6 +1084,7 @@ where old_metadata_state, old_surface_pools, self.supports_context_reuse, + self.pool_creation_mode.clone(), )?; Ok(()) diff --git a/src/decoder/stateless/av1.rs b/src/decoder/stateless/av1.rs index 072c1b2a..d729a717 100644 --- a/src/decoder/stateless/av1.rs +++ b/src/decoder/stateless/av1.rs @@ -39,8 +39,15 @@ mod vaapi; /// Stateless backend methods specific to AV1. pub trait StatelessAV1DecoderBackend: StatelessDecoderBackend { - /// Called when a new Sequence Header OBU is parsed. - fn new_sequence(&mut self, sequence: &Rc) -> StatelessBackendResult<()>; + /// Called when a new Sequence Header OBU is parsed. The + /// `highest_spatial_layer` argument refers to the maximum layer selected by + /// the client through `set_operating_point()` and the scalability + /// information present in the stream, if any. + fn new_sequence( + &mut self, + sequence: &Rc, + highest_spatial_layer: Option, + ) -> StatelessBackendResult<()>; /// Called when the decoder determines that a new picture was found. fn new_picture( @@ -421,10 +428,11 @@ where sequence.bit_depth ); /* there is nothing to drain, much like vp8 and vp9 */ - self.backend.new_sequence(&sequence)?; - self.decoding_state = DecodingState::AwaitingFormat(sequence); self.codec.highest_spatial_layer = self.codec.parser.highest_operating_point(); + self.backend + .new_sequence(&sequence, self.codec.highest_spatial_layer)?; + self.decoding_state = DecodingState::AwaitingFormat(sequence); } } ObuType::TemporalDelimiter => { diff --git a/src/decoder/stateless/av1/dummy.rs b/src/decoder/stateless/av1/dummy.rs index cc7a009f..70582fcb 100644 --- a/src/decoder/stateless/av1/dummy.rs +++ b/src/decoder/stateless/av1/dummy.rs @@ -19,6 +19,7 @@ impl StatelessAV1DecoderBackend for Backend { fn new_sequence( &mut self, _: &std::rc::Rc, + _: Option, ) -> crate::decoder::stateless::StatelessBackendResult<()> { Ok(()) } diff --git a/src/decoder/stateless/av1/vaapi.rs b/src/decoder/stateless/av1/vaapi.rs index a022001d..5218e110 100644 --- a/src/decoder/stateless/av1/vaapi.rs +++ b/src/decoder/stateless/av1/vaapi.rs @@ -11,6 +11,7 @@ use libva::Picture as VaPicture; use libva::SurfaceMemoryDescriptor; use crate::backend::vaapi::DecodedHandle as VADecodedHandle; +use crate::backend::vaapi::PoolCreationMode; use crate::backend::vaapi::VaStreamInfo; use crate::backend::vaapi::VaapiBackend; use crate::backend::vaapi::VaapiPicture; @@ -32,6 +33,7 @@ use crate::decoder::stateless::StatelessBackendError; use crate::decoder::stateless::StatelessDecoder; use crate::decoder::stateless::StatelessDecoderBackendPicture; use crate::decoder::BlockingMode; +use crate::Resolution; /// The number of surfaces to allocate for this codec. const NUM_SURFACES: usize = 16; @@ -571,8 +573,22 @@ impl StatelessAV1DecoderBackend for VaapiB fn new_sequence( &mut self, sequence: &Rc, + highest_spatial_layer: Option, ) -> crate::decoder::stateless::StatelessBackendResult<()> { - self.new_sequence(sequence) + let pool_creation_mode = match highest_spatial_layer { + Some(highest_layer) => { + /* The spec mandates a 2:1 or 1.5:1 ratio, let's go with 2:1 to + * accomodate the other case. See 6.7.5 in the spec */ + let layers = (0..=highest_layer).map(|layer| Resolution { + width: (sequence.max_frame_width_minus_1 + 1) / (layer + 1), + height: (sequence.max_frame_height_minus_1 + 1) / (layer + 1), + }); + + PoolCreationMode::Layers(layers.collect()) + } + None => PoolCreationMode::Highest, + }; + self.new_sequence(sequence, pool_creation_mode) } fn new_picture( diff --git a/src/decoder/stateless/h264/vaapi.rs b/src/decoder/stateless/h264/vaapi.rs index 044b0946..c072ac3e 100644 --- a/src/decoder/stateless/h264/vaapi.rs +++ b/src/decoder/stateless/h264/vaapi.rs @@ -17,6 +17,7 @@ use libva::SliceParameter; use libva::SurfaceMemoryDescriptor; use crate::backend::vaapi::DecodedHandle as VADecodedHandle; +use crate::backend::vaapi::PoolCreationMode; use crate::backend::vaapi::VaStreamInfo; use crate::backend::vaapi::VaapiBackend; use crate::backend::vaapi::VaapiPicture; @@ -472,7 +473,7 @@ impl StatelessDecoderBackendPicture impl StatelessH264DecoderBackend for VaapiBackend { fn new_sequence(&mut self, sps: &Rc) -> StatelessBackendResult<()> { - self.new_sequence(sps) + self.new_sequence(sps, PoolCreationMode::Highest) } fn start_picture( diff --git a/src/decoder/stateless/h265/vaapi.rs b/src/decoder/stateless/h265/vaapi.rs index dadb4835..f9544f2d 100644 --- a/src/decoder/stateless/h265/vaapi.rs +++ b/src/decoder/stateless/h265/vaapi.rs @@ -20,6 +20,7 @@ use libva::SliceParameterBufferHEVCRext; use libva::SurfaceMemoryDescriptor; use crate::backend::vaapi::DecodedHandle as VADecodedHandle; +use crate::backend::vaapi::PoolCreationMode; use crate::backend::vaapi::VaStreamInfo; use crate::backend::vaapi::VaapiBackend; use crate::backend::vaapi::VaapiPicture; @@ -589,7 +590,7 @@ impl StatelessDecoderBackendPicture impl StatelessH265DecoderBackend for VaapiBackend { fn new_sequence(&mut self, sps: &Sps) -> StatelessBackendResult<()> { - self.new_sequence(sps) + self.new_sequence(sps, PoolCreationMode::Highest) } fn new_picture( diff --git a/src/decoder/stateless/vp8/vaapi.rs b/src/decoder/stateless/vp8/vaapi.rs index 6b567406..f44c4888 100644 --- a/src/decoder/stateless/vp8/vaapi.rs +++ b/src/decoder/stateless/vp8/vaapi.rs @@ -14,6 +14,7 @@ use libva::Picture as VaPicture; use libva::ProbabilityDataBufferVP8; use libva::SurfaceMemoryDescriptor; +use crate::backend::vaapi::PoolCreationMode; use crate::backend::vaapi::VaStreamInfo; use crate::backend::vaapi::VaapiBackend; use crate::codec::vp8::parser::Header; @@ -209,7 +210,7 @@ impl StatelessDecoderBackendPicture f impl StatelessVp8DecoderBackend for VaapiBackend { fn new_sequence(&mut self, header: &Header) -> StatelessBackendResult<()> { - self.new_sequence(header) + self.new_sequence(header, PoolCreationMode::Highest) } fn submit_picture( diff --git a/src/decoder/stateless/vp9/vaapi.rs b/src/decoder/stateless/vp9/vaapi.rs index fe2df524..b7e00b98 100644 --- a/src/decoder/stateless/vp9/vaapi.rs +++ b/src/decoder/stateless/vp9/vaapi.rs @@ -11,6 +11,7 @@ use libva::Picture as VaPicture; use libva::SegmentParameterVP9; use libva::SurfaceMemoryDescriptor; +use crate::backend::vaapi::PoolCreationMode; use crate::backend::vaapi::VaStreamInfo; use crate::backend::vaapi::VaapiBackend; use crate::codec::vp9::parser::BitDepth; @@ -239,7 +240,7 @@ impl StatelessDecoderBackendPicture f impl StatelessVp9DecoderBackend for VaapiBackend { fn new_sequence(&mut self, header: &Header) -> StatelessBackendResult<()> { - self.new_sequence(header) + self.new_sequence(header, PoolCreationMode::Highest) } fn submit_picture( From c71c990ecdf7d9d63c3cc7fdb43c81d02707287f Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Tue, 5 Dec 2023 13:34:40 +0000 Subject: [PATCH 5/9] decoders: av1: draw from the right pool for svc streams We now have multiple pools available. Draw from the right pool when decoding SVC streams. --- src/backend/vaapi.rs | 6 ++++++ src/decoder/stateless/av1.rs | 2 ++ src/decoder/stateless/av1/dummy.rs | 1 + src/decoder/stateless/av1/vaapi.rs | 31 +++++++++++++++++++++++++----- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/backend/vaapi.rs b/src/backend/vaapi.rs index bc32763e..cf262be8 100644 --- a/src/backend/vaapi.rs +++ b/src/backend/vaapi.rs @@ -1032,6 +1032,12 @@ where .max_by_key(|p| p.borrow().coded_resolution().height) .unwrap() } + + pub(crate) fn pool(&mut self, layer: Resolution) -> Option<&Rc>>> { + self.surface_pools + .iter() + .find(|p| p.borrow().coded_resolution() == layer) + } } /// Shortcut for pictures used for the VAAPI backend. diff --git a/src/decoder/stateless/av1.rs b/src/decoder/stateless/av1.rs index d729a717..5359f961 100644 --- a/src/decoder/stateless/av1.rs +++ b/src/decoder/stateless/av1.rs @@ -56,6 +56,7 @@ pub trait StatelessAV1DecoderBackend: StatelessDecoderBackend { picture: &FrameHeaderObu, timestamp: u64, reference_frames: &[Option; NUM_REF_FRAMES], + highest_spatial_layer: Option, ) -> StatelessBackendResult; /// Called to dispatch a decode operation to the backend. @@ -203,6 +204,7 @@ where &frame_header, timestamp, &self.codec.reference_frames, + self.codec.highest_spatial_layer, )?; self.codec.current_pic = Some(CurrentPicState::RegularFrame { diff --git a/src/decoder/stateless/av1/dummy.rs b/src/decoder/stateless/av1/dummy.rs index 70582fcb..02414dcb 100644 --- a/src/decoder/stateless/av1/dummy.rs +++ b/src/decoder/stateless/av1/dummy.rs @@ -30,6 +30,7 @@ impl StatelessAV1DecoderBackend for Backend { _: &crate::codec::av1::parser::FrameHeaderObu, _: u64, _: &[Option; crate::codec::av1::parser::NUM_REF_FRAMES], + _: Option, ) -> crate::decoder::stateless::StatelessBackendResult { Ok(()) } diff --git a/src/decoder/stateless/av1/vaapi.rs b/src/decoder/stateless/av1/vaapi.rs index 5218e110..74fdfbe6 100644 --- a/src/decoder/stateless/av1/vaapi.rs +++ b/src/decoder/stateless/av1/vaapi.rs @@ -597,12 +597,33 @@ impl StatelessAV1DecoderBackend for VaapiB hdr: &FrameHeaderObu, timestamp: u64, reference_frames: &[Option; NUM_REF_FRAMES], + highest_spatial_layer: Option, ) -> crate::decoder::stateless::StatelessBackendResult { - let highest_pool = self.highest_pool(); - let surface = highest_pool - .borrow_mut() - .get_surface(highest_pool) - .ok_or(StatelessBackendError::OutOfResources)?; + let surface = match highest_spatial_layer { + Some(_) => { + let layer = Resolution { + width: hdr.upscaled_width, + height: hdr.frame_height, + }; + + let pool = self + .pool(layer) + .ok_or(StatelessBackendError::Other(anyhow!( + "No pool available for this layer" + )))?; + + pool.borrow_mut() + .get_surface(pool) + .ok_or(StatelessBackendError::OutOfResources)? + } + None => { + let highest_pool = self.highest_pool(); + highest_pool + .borrow_mut() + .get_surface(highest_pool) + .ok_or(StatelessBackendError::OutOfResources)? + } + }; let metadata = self.metadata_state.get_parsed()?; let mut picture = VaPicture::new(timestamp, Rc::clone(&metadata.context), surface); From e9e3070bd014a16d36497e87e800d0c270d2e1e9 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 11 Dec 2023 14:47:01 +0000 Subject: [PATCH 6/9] simple_playback_loop: account for multiple pools when allocating If we have multiple pools, we should split min_num_frames among them --- src/utils.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils.rs b/src/utils.rs index 4a4d5691..35598505 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -136,10 +136,11 @@ where /* we need to account for multiple layers if applicable for * the stream */ let pools = format_setter.frame_pool(PoolLayer::All); + let nb_pools = pools.len(); for pool in pools { // Allocate the missing number of buffers in our pool for decoding to succeed. let pool_num_frames = pool.num_managed_frames(); - if pool_num_frames < min_num_frames { + if pool_num_frames < (min_num_frames / nb_pools) { let frames = allocate_new_frames( &stream_info, min_num_frames - pool_num_frames, From cfcc103b0f47906504ffb1b964ff7dac621fd80b Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Wed, 13 Dec 2023 19:12:22 +0000 Subject: [PATCH 7/9] vaapi: av1: submit slice parameters as an array All tiles belonging to the same tile group must be submitted to the vaapi driver as an array. The Intel driver, in particular, expects one array of Slice Parameters per instance of Slice Data when submitting the data for an AV1 Tile Group. It will produce a corrupted frame if the slice parameters are submitted separately (i.e.: in their own VABuffers). This was discovered by Nicolas Dufresne. --- src/decoder/stateless/av1/vaapi.rs | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/decoder/stateless/av1/vaapi.rs b/src/decoder/stateless/av1/vaapi.rs index 74fdfbe6..1859cb7f 100644 --- a/src/decoder/stateless/av1/vaapi.rs +++ b/src/decoder/stateless/av1/vaapi.rs @@ -536,11 +536,12 @@ fn build_pic_param( )) } -fn build_slice_params_for_tg(tg: &TileGroupObu) -> anyhow::Result> { - let mut slice_params = vec![]; +fn build_slice_params_for_tg(tg: &TileGroupObu) -> anyhow::Result { + let mut slice_params = libva::SliceParameterBufferAV1::new(); for tile in &tg.tiles { - let slice_param = libva::SliceParameterBufferAV1::new( + /* all tiles must be submitted in the same slice parameter array */ + slice_params.add_slice_parameter( tile.tile_size, tile.tile_offset, 0, @@ -551,13 +552,11 @@ fn build_slice_params_for_tg(tg: &TileGroupObu) -> anyhow::Result libva::BufferType { @@ -652,13 +651,11 @@ impl StatelessAV1DecoderBackend for VaapiB let metadata = self.metadata_state.get_parsed()?; let context = &metadata.context; - for slice_param in slice_params { - let buffer = context - .create_buffer(slice_param) - .context("Failed to create slice parameter buffer")?; + let buffer = context + .create_buffer(slice_params) + .context("Failed to create slice parameter buffer")?; - picture.add_buffer(buffer) - } + picture.add_buffer(buffer); let buffer = context .create_buffer(slice_data) From e48eb00928313df3e9f9664bb192a1eaea89c941 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Thu, 28 Dec 2023 15:16:12 +0000 Subject: [PATCH 8/9] backend: vaapi: add a handle for post-processing Add a new handle for post-processing. This use-case requires a surface for non-filtered data (for the decode process), and one surface for the filtered data (for display). This was previously impossible, as we only had one handle. Thus add a new type of handle and unite them through an enum. A next commit will make use of this handle to implement film grain in the AV1 VA-API code. --- src/backend/vaapi.rs | 209 ++++++++++++++++++++++------ src/decoder/stateless/av1/vaapi.rs | 2 +- src/decoder/stateless/h264/vaapi.rs | 2 +- src/decoder/stateless/h265/vaapi.rs | 2 +- src/decoder/stateless/vp8/vaapi.rs | 6 +- src/decoder/stateless/vp9/vaapi.rs | 2 +- 6 files changed, 173 insertions(+), 50 deletions(-) diff --git a/src/backend/vaapi.rs b/src/backend/vaapi.rs index cf262be8..f2a9b11f 100644 --- a/src/backend/vaapi.rs +++ b/src/backend/vaapi.rs @@ -174,22 +174,60 @@ fn supported_formats_for_rt_format( Ok(supported_formats) } -/// A decoded frame handle. -pub(crate) type DecodedHandle = Rc>>; +pub(crate) type DecodedHandle = Rc>>; -impl DecodedHandleTrait for DecodedHandle { +/// The handle type used by the decoder backend that takes into account whether +/// post processing is needed. +pub enum VaDecodedHandle { + Generic(GenericBackendHandle), + PostProcessed(PostProcessedHandle), +} + +impl VaDecodedHandle { + fn handle(&self) -> &GenericBackendHandle { + match self { + VaDecodedHandle::Generic(h) => h, + VaDecodedHandle::PostProcessed(h) => &h.decode_handle, + } + } + + fn handle_mut(&mut self) -> &mut GenericBackendHandle { + match self { + VaDecodedHandle::Generic(h) => h, + VaDecodedHandle::PostProcessed(h) => &mut h.decode_handle, + } + } + + pub(crate) fn decoded_surface_id(&self) -> libva::VASurfaceID { + match &self.handle().state { + PictureState::Ready(picture) => picture.surface().id(), + PictureState::Pending(picture) => picture.surface().id(), + PictureState::Invalid => unreachable!(), + } + } + + /// Returns the picture of this handle. + pub(crate) fn picture(&self) -> Option<&Picture>> { + match self { + VaDecodedHandle::Generic(h) => h.picture(), + VaDecodedHandle::PostProcessed(h) => h.picture(), + } + } +} + +impl DecodedHandleTrait for Rc>> { type Descriptor = M; fn coded_resolution(&self) -> Resolution { - self.borrow().coded_resolution + self.borrow().handle().coded_resolution } fn display_resolution(&self) -> Resolution { - self.borrow().display_resolution + self.borrow().handle().display_resolution } fn timestamp(&self) -> u64 { - self.borrow().timestamp() + self.borrow().handle().timestamp() } fn dyn_picture<'a>(&'a self) -> Box { @@ -197,24 +235,88 @@ impl DecodedHandleTrait for DecodedHandle { } fn is_ready(&self) -> bool { - self.borrow().is_va_ready().unwrap_or(true) + let borrow = self.borrow(); + let handle = borrow.handle(); + + let decode_is_ready = match &handle.state { + PictureState::Ready(_) => Ok(true), + PictureState::Pending(picture) => picture + .surface() + .query_status() + .map(|s| s == libva::VASurfaceStatus::VASurfaceReady), + PictureState::Invalid => unreachable!(), + } + .unwrap_or(true); + + match &*self.borrow() { + VaDecodedHandle::Generic(_) => decode_is_ready, + VaDecodedHandle::PostProcessed(h) => { + use std::borrow::Borrow; + let display_surface: &libva::Surface = h.display_surface.borrow(); + + let display_is_ready = display_surface + .query_status() + .map(|s| s == libva::VASurfaceStatus::VASurfaceReady) + .unwrap_or(true); + + decode_is_ready && display_is_ready + } + } } fn sync(&self) -> anyhow::Result<()> { - self.borrow_mut().sync().context("while syncing picture")?; - - Ok(()) + let mut borrow = self.borrow_mut(); + let handle = borrow.handle_mut(); + handle.sync().context("while syncing picture")?; + + match &*borrow { + VaDecodedHandle::Generic(_) => Ok(()), + VaDecodedHandle::PostProcessed(h) => { + use std::borrow::Borrow; + let display_surface: &libva::Surface = h.display_surface.borrow(); + display_surface + .sync() + .context("while syncing the display surface") + } + } } fn resource(&self) -> std::cell::Ref { - std::cell::Ref::map(self.borrow(), |r| match &r.state { - PictureState::Ready(p) => p.surface().as_ref(), - PictureState::Pending(p) => p.surface().as_ref(), - PictureState::Invalid => unreachable!(), + std::cell::Ref::map(self.borrow(), |r| match r { + VaDecodedHandle::Generic(h) => match &h.state { + PictureState::Ready(p) => p.surface().as_ref(), + PictureState::Pending(p) => p.surface().as_ref(), + PictureState::Invalid => unreachable!(), + }, + VaDecodedHandle::PostProcessed(h) => { + /* return the display resource, as this is what most clients care about */ + h.display_surface.as_ref() + } }) } } +impl<'a, M: SurfaceMemoryDescriptor> DynHandle for std::cell::Ref<'a, VaDecodedHandle> { + fn dyn_mappable_handle<'b>(&'b self) -> anyhow::Result> { + match &**self { + VaDecodedHandle::Generic(h) => { + h.image().map(|i| Box::new(i) as Box) + } + VaDecodedHandle::PostProcessed(h) => { + use std::borrow::Borrow; + let surface: &libva::Surface = h.display_surface.borrow(); + let image = libva::Image::create_from( + surface, + *h.decode_handle.map_format, + h.decode_handle.coded_resolution.into(), + h.decode_handle.display_resolution.into(), + )?; + Ok(Box::new(image) as Box) + } + } + } +} + mod surface_pool { use std::borrow::Borrow; use std::cell::RefCell; @@ -691,6 +793,35 @@ impl StreamMetadataState { } } +/// A handle that can be post processed. One surface holds the non-filtered data +/// and is fed to the decode process, the other holds the filtered data and is +/// meant to be displayed. +pub struct PostProcessedHandle { + /// The non-filtered handle. All decoding happens here. + decode_handle: GenericBackendHandle, + /// The filtered surface. We merely display it. + display_surface: PooledSurface, +} + +impl PostProcessedHandle { + /// Creates a new pending handle on `surface_id`. + fn new( + picture: Picture>, + metadata: &ParsedStreamMetadata, + display_surface: PooledSurface, + ) -> anyhow::Result { + Ok(Self { + decode_handle: GenericBackendHandle::new(picture, metadata)?, + display_surface, + }) + } + + /// Returns the picture of this handle. + pub(crate) fn picture(&self) -> Option<&Picture>> { + self.decode_handle.picture() + } +} + /// VA-API backend handle. /// /// This includes the VA picture which can be pending rendering or complete, as well as useful @@ -777,32 +908,6 @@ impl GenericBackendHandle { PictureState::Invalid => unreachable!(), } } - - /// Returns the id of the VA surface backing this handle. - pub(crate) fn surface_id(&self) -> libva::VASurfaceID { - match &self.state { - PictureState::Ready(picture) => picture.surface().id(), - PictureState::Pending(picture) => picture.surface().id(), - PictureState::Invalid => unreachable!(), - } - } - - fn is_va_ready(&self) -> Result { - match &self.state { - PictureState::Ready(_) => Ok(true), - PictureState::Pending(picture) => picture - .surface() - .query_status() - .map(|s| s == libva::VASurfaceStatus::VASurfaceReady), - PictureState::Invalid => unreachable!(), - } - } -} - -impl<'a, M: SurfaceMemoryDescriptor> DynHandle for std::cell::Ref<'a, GenericBackendHandle> { - fn dyn_mappable_handle<'b>(&'b self) -> anyhow::Result> { - self.image().map(|i| Box::new(i) as Box) - } } /// Rendering state of a VA picture. @@ -1000,9 +1105,27 @@ where { let metadata = self.metadata_state.get_parsed()?; - Ok(Rc::new(RefCell::new(GenericBackendHandle::new( - picture, metadata, - )?))) + let handle = GenericBackendHandle::new(picture, metadata)?; + let handle = Rc::new(RefCell::new(VaDecodedHandle::Generic(handle))); + Ok(handle) + } + + /// Process an AV1 picture. AV1 supports film grain, and its use requires a + /// different type of Handle. + pub(crate) fn process_av1_picture( + &mut self, + picture: Picture>, + display_surface: PooledSurface, + ) -> StatelessBackendResult<>::Handle> + where + Self: StatelessDecoderBackendPicture, + for<'a> &'a Codec::FormatInfo: VaStreamInfo, + { + let metadata = self.metadata_state.get_parsed()?; + + let handle = PostProcessedHandle::new(picture, metadata, display_surface)?; + let handle = Rc::new(RefCell::new(VaDecodedHandle::PostProcessed(handle))); + Ok(handle) } /// Gets a set of supported formats for the particular stream being diff --git a/src/decoder/stateless/av1/vaapi.rs b/src/decoder/stateless/av1/vaapi.rs index 1859cb7f..6c7f412b 100644 --- a/src/decoder/stateless/av1/vaapi.rs +++ b/src/decoder/stateless/av1/vaapi.rs @@ -347,7 +347,7 @@ fn build_pic_param( .iter() .map(|h| { if let Some(h) = h { - h.borrow().surface_id() + h.borrow().decoded_surface_id() } else { libva::constants::VA_INVALID_SURFACE } diff --git a/src/decoder/stateless/h264/vaapi.rs b/src/decoder/stateless/h264/vaapi.rs index c072ac3e..e913b255 100644 --- a/src/decoder/stateless/h264/vaapi.rs +++ b/src/decoder/stateless/h264/vaapi.rs @@ -116,7 +116,7 @@ fn surface_id( ) -> libva::VASurfaceID { match handle { None => libva::constants::VA_INVALID_SURFACE, - Some(handle) => handle.borrow().surface_id(), + Some(handle) => handle.borrow().decoded_surface_id(), } } diff --git a/src/decoder/stateless/h265/vaapi.rs b/src/decoder/stateless/h265/vaapi.rs index f9544f2d..0141e82e 100644 --- a/src/decoder/stateless/h265/vaapi.rs +++ b/src/decoder/stateless/h265/vaapi.rs @@ -343,7 +343,7 @@ fn build_pic_param( let mut reference_frames = vec![]; for ref_pic in dpb.get_all_references() { - let surface_id = ref_pic.1.borrow().surface_id(); + let surface_id = ref_pic.1.borrow().decoded_surface_id(); let ref_pic = fill_va_hevc_pic(&ref_pic.0.borrow(), surface_id, rps); reference_frames.push(ref_pic); } diff --git a/src/decoder/stateless/vp8/vaapi.rs b/src/decoder/stateless/vp8/vaapi.rs index f44c4888..48c02f70 100644 --- a/src/decoder/stateless/vp8/vaapi.rs +++ b/src/decoder/stateless/vp8/vaapi.rs @@ -225,19 +225,19 @@ impl StatelessVp8DecoderBackend for VaapiB timestamp: u64, ) -> StatelessBackendResult { let last_ref = if let Some(last_ref) = last_ref { - last_ref.borrow().surface_id() + last_ref.borrow().decoded_surface_id() } else { libva::constants::VA_INVALID_SURFACE }; let golden_ref = if let Some(golden_ref) = golden_ref { - golden_ref.borrow().surface_id() + golden_ref.borrow().decoded_surface_id() } else { libva::constants::VA_INVALID_SURFACE }; let alt_ref = if let Some(alt_ref) = alt_ref { - alt_ref.borrow().surface_id() + alt_ref.borrow().decoded_surface_id() } else { libva::constants::VA_INVALID_SURFACE }; diff --git a/src/decoder/stateless/vp9/vaapi.rs b/src/decoder/stateless/vp9/vaapi.rs index b7e00b98..14f4212d 100644 --- a/src/decoder/stateless/vp9/vaapi.rs +++ b/src/decoder/stateless/vp9/vaapi.rs @@ -255,7 +255,7 @@ impl StatelessVp9DecoderBackend for VaapiB .iter() .map(|h| { if let Some(h) = h { - h.borrow().surface_id() + h.borrow().decoded_surface_id() } else { libva::constants::VA_INVALID_SURFACE } From 6265f8908e767990a3cfc8f1e53fa89b4c15a86f Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Fri, 29 Dec 2023 17:28:21 +0000 Subject: [PATCH 9/9] decoders: vaapi: av1: add film grain support Use the new VAAPI handle to add film grain support in the VAAPI AV1 decoder. One surface contains the grain and is meant to be displayed, while the other one does not. We need the decode surface to not have any grain, otherwise this would break the decoding process. The number of surfaces is doubled to accomodate for this, but only when film grain is active. --- src/decoder/stateless/av1/vaapi.rs | 99 +++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 16 deletions(-) diff --git a/src/decoder/stateless/av1/vaapi.rs b/src/decoder/stateless/av1/vaapi.rs index 6c7f412b..577ae82e 100644 --- a/src/decoder/stateless/av1/vaapi.rs +++ b/src/decoder/stateless/av1/vaapi.rs @@ -12,6 +12,7 @@ use libva::SurfaceMemoryDescriptor; use crate::backend::vaapi::DecodedHandle as VADecodedHandle; use crate::backend::vaapi::PoolCreationMode; +use crate::backend::vaapi::PooledSurface; use crate::backend::vaapi::VaStreamInfo; use crate::backend::vaapi::VaapiBackend; use crate::backend::vaapi::VaapiPicture; @@ -87,7 +88,13 @@ impl VaStreamInfo for &Rc { } fn min_num_surfaces(&self) -> usize { - NUM_SURFACES + if self.film_grain_params_present { + /* assume grain will be applied. We need twice the number of surfaces + * for that. */ + NUM_SURFACES * 2 + } else { + NUM_SURFACES + } } fn coded_size(&self) -> (u32, u32) { @@ -271,6 +278,7 @@ fn build_pic_param( hdr: &FrameHeaderObu, seq: &SequenceHeaderObu, current_frame: libva::VASurfaceID, + current_display_picture: libva::VASurfaceID, reference_frames: &[Option>; NUM_REF_FRAMES], ) -> anyhow::Result { let seq_info_fields = libva::AV1SeqFields::new( @@ -487,8 +495,8 @@ fn build_pic_param( .context("Invalid matrix_coefficients")?, &seq_info_fields, current_frame, - libva::constants::VA_INVALID_SURFACE, /* film grain is unsupported for now */ - vec![], /* anchor_frames_list */ + current_display_picture, + vec![], /* anchor_frames_list */ u16::try_from(hdr.upscaled_width - 1).context("Invalid frame width")?, u16::try_from(hdr.frame_height - 1).context("Invalid frame height")?, 0, /* output_frame_width_in_tiles_minus_1 */ @@ -564,8 +572,14 @@ fn build_slice_data_for_tg(tg: TileGroupObu) -> libva::BufferType { libva::BufferType::SliceData(Vec::from(obu.as_ref())) } +pub struct Picture { + va_picture: VaapiPicture, + /// Some if film grain is to be applied. + display_surface: Option>, +} + impl StatelessDecoderBackendPicture for VaapiBackend { - type Picture = VaapiPicture; + type Picture = Picture; } impl StatelessAV1DecoderBackend for VaapiBackend { @@ -598,7 +612,7 @@ impl StatelessAV1DecoderBackend for VaapiB reference_frames: &[Option; NUM_REF_FRAMES], highest_spatial_layer: Option, ) -> crate::decoder::stateless::StatelessBackendResult { - let surface = match highest_spatial_layer { + let (decode_surface, display_surface) = match highest_spatial_layer { Some(_) => { let layer = Resolution { width: hdr.upscaled_width, @@ -611,33 +625,77 @@ impl StatelessAV1DecoderBackend for VaapiB "No pool available for this layer" )))?; - pool.borrow_mut() + let decode_surface = pool + .borrow_mut() .get_surface(pool) - .ok_or(StatelessBackendError::OutOfResources)? + .ok_or(StatelessBackendError::OutOfResources)?; + + let display_surface = if hdr.film_grain_params.apply_grain { + Some( + pool.borrow_mut() + .get_surface(pool) + .ok_or(StatelessBackendError::OutOfResources)?, + ) + } else { + None + }; + + (decode_surface, display_surface) } None => { let highest_pool = self.highest_pool(); - highest_pool + + let decode_surface = highest_pool .borrow_mut() .get_surface(highest_pool) - .ok_or(StatelessBackendError::OutOfResources)? + .ok_or(StatelessBackendError::OutOfResources)?; + + let display_surface = if hdr.film_grain_params.apply_grain { + Some( + highest_pool + .borrow_mut() + .get_surface(highest_pool) + .ok_or(StatelessBackendError::OutOfResources)?, + ) + } else { + None + }; + + (decode_surface, display_surface) } }; let metadata = self.metadata_state.get_parsed()?; - let mut picture = VaPicture::new(timestamp, Rc::clone(&metadata.context), surface); + let mut picture = VaPicture::new(timestamp, Rc::clone(&metadata.context), decode_surface); let surface_id = picture.surface().id(); + let display_surface_id = match display_surface { + Some(ref pooled_surface) => { + use std::borrow::Borrow; + let display_surface: &libva::Surface = pooled_surface.borrow(); + display_surface.id() + } + None => libva::constants::VA_INVALID_SURFACE, + }; - let pic_param = build_pic_param(hdr, sequence, surface_id, reference_frames) - .context("Failed to build picture parameter")?; + let pic_param = build_pic_param( + hdr, + sequence, + surface_id, + display_surface_id, + reference_frames, + ) + .context("Failed to build picture parameter")?; let pic_param = metadata .context .create_buffer(pic_param) .context("Failed to create picture parameter buffer")?; picture.add_buffer(pic_param); - Ok(picture) + Ok(Picture { + va_picture: picture, + display_surface, + }) } fn decode_tile_group( @@ -655,13 +713,13 @@ impl StatelessAV1DecoderBackend for VaapiB .create_buffer(slice_params) .context("Failed to create slice parameter buffer")?; - picture.add_buffer(buffer); + picture.va_picture.add_buffer(buffer); let buffer = context .create_buffer(slice_data) .context("Failed to create slice data buffer")?; - picture.add_buffer(buffer); + picture.va_picture.add_buffer(buffer); Ok(()) } @@ -670,7 +728,16 @@ impl StatelessAV1DecoderBackend for VaapiB &mut self, picture: Self::Picture, ) -> crate::decoder::stateless::StatelessBackendResult { - self.process_picture::(picture) + let Picture { + va_picture, + display_surface, + } = picture; + + if let Some(display_surface) = display_surface { + self.process_av1_picture::(va_picture, display_surface) + } else { + self.process_picture::(va_picture) + } } }