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..f2a9b11f 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; @@ -173,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 { @@ -196,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; @@ -508,6 +611,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 { @@ -534,9 +647,10 @@ 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>>)> { + pool_creation_mode: PoolCreationMode, + ) -> anyhow::Result<(StreamMetadataState, Vec>>>)> { let va_profile = hdr.va_profile()?; let rt_format = hdr.rt_format()?; @@ -577,7 +691,12 @@ impl StreamMetadataState { height: visible_rect.1 .1 - visible_rect.0 .1, }; - let (config, context, surface_pool) = match old_metadata_state { + 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. // // This can happen as the decoder cannot possibly know whether a @@ -588,7 +707,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 +716,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,32 +737,30 @@ impl StreamMetadataState { true, )?; - let surface_pool = Rc::new(RefCell::new(SurfacePool::new( - Rc::clone(display), - rt_format, - Some(libva::UsageHint::USAGE_HINT_DECODER), - coded_resolution, - ))); - - (config, context, surface_pool) + 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) } }; - if !surface_pool - .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_pool - .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(( @@ -671,11 +788,40 @@ impl StreamMetadataState { rt_format, profile: va_profile, }), - surface_pool, + surface_pools, )) } } +/// 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 @@ -762,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. @@ -914,13 +1034,17 @@ 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 /// by VP9 and AV1. supports_context_reuse: bool, + /// Controls the creation of surface pools. + pool_creation_mode: PoolCreationMode, } impl VaapiBackend @@ -929,24 +1053,26 @@ 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, + 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, @@ -954,15 +1080,18 @@ 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, + pool_creation_mode.clone(), )?; + self.pool_creation_mode = pool_creation_mode; Ok(()) } @@ -976,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 @@ -1000,6 +1147,20 @@ 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() + } + + 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. @@ -1044,13 +1205,15 @@ 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, + self.pool_creation_mode.clone(), )?; Ok(()) @@ -1059,8 +1222,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/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.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..5359f961 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; @@ -37,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( @@ -47,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. @@ -194,6 +204,7 @@ where &frame_header, timestamp, &self.codec.reference_frames, + self.codec.highest_spatial_layer, )?; self.codec.current_pic = Some(CurrentPicState::RegularFrame { @@ -308,7 +319,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( @@ -410,10 +430,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 => { @@ -473,8 +494,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/dummy.rs b/src/decoder/stateless/av1/dummy.rs index cc7a009f..02414dcb 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(()) } @@ -29,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 3dda0840..577ae82e 100644 --- a/src/decoder/stateless/av1/vaapi.rs +++ b/src/decoder/stateless/av1/vaapi.rs @@ -11,6 +11,8 @@ use libva::Picture as VaPicture; 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; @@ -32,6 +34,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; @@ -85,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) { @@ -269,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( @@ -345,7 +355,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 } @@ -485,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 */ @@ -534,11 +544,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, @@ -549,13 +560,11 @@ fn build_slice_params_for_tg(tg: &TileGroupObu) -> anyhow::Result libva::BufferType { @@ -563,16 +572,36 @@ 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 { 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( @@ -581,27 +610,92 @@ impl StatelessAV1DecoderBackend for VaapiB hdr: &FrameHeaderObu, timestamp: u64, reference_frames: &[Option; NUM_REF_FRAMES], + highest_spatial_layer: Option, ) -> crate::decoder::stateless::StatelessBackendResult { - let metadata = self.metadata_state.get_parsed()?; - let surface = self - .surface_pool - .borrow_mut() - .get_surface(&self.surface_pool) - .ok_or(StatelessBackendError::OutOfResources)?; + let (decode_surface, display_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" + )))?; + + let decode_surface = pool + .borrow_mut() + .get_surface(pool) + .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(); + + let decode_surface = highest_pool + .borrow_mut() + .get_surface(highest_pool) + .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 mut picture = VaPicture::new(timestamp, Rc::clone(&metadata.context), surface); + let metadata = self.metadata_state.get_parsed()?; + 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( @@ -615,19 +709,17 @@ 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.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(()) } @@ -636,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) + } } } diff --git a/src/decoder/stateless/h264.rs b/src/decoder/stateless/h264.rs index e70da199..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; @@ -566,7 +567,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 +583,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 +1133,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 +1177,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 +1189,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 +1430,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 +1451,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 +1464,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 +1475,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( @@ -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)); } @@ -1527,7 +1535,7 @@ where pps.sps.as_ref(), pps.as_ref(), &self.codec.dpb, - slice.header(), + &slice.header, )?; Ok(CurrentPicState { @@ -1568,8 +1576,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 +1594,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 +1643,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 +1713,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 +1793,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 +1806,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 +1833,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 +1857,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 +1889,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 +1903,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)?; } } @@ -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 e020dc4c..e913b255 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; @@ -115,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(), } } @@ -199,11 +200,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 +277,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 +309,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 +380,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 +391,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 +410,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 +444,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, @@ -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( @@ -520,8 +521,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 +533,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); @@ -549,13 +550,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 b90d931f..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; @@ -379,27 +380,31 @@ 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(()) } // 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(); @@ -421,10 +426,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 { @@ -436,10 +441,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 { @@ -453,26 +458,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; } } @@ -644,14 +649,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 @@ -667,11 +672,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 @@ -722,9 +727,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() @@ -734,20 +739,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 @@ -792,9 +797,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() @@ -918,14 +923,22 @@ 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)); } 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; @@ -1013,7 +1026,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 @@ -1029,7 +1042,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, @@ -1124,11 +1137,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)?; } @@ -1148,7 +1161,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)) } } @@ -1171,14 +1184,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() { @@ -1236,7 +1248,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(). @@ -1250,21 +1262,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)?; @@ -1310,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 0969273d..0141e82e 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; @@ -342,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); } @@ -486,14 +487,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 +504,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 +532,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, ))) @@ -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( @@ -597,12 +598,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), @@ -681,7 +682,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 +690,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 +721,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 +746,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 +767,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 +792,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 +803,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 +813,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 +823,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/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..48c02f70 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( @@ -224,26 +225,32 @@ 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 }; + 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 +280,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..14f4212d 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( @@ -254,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 } @@ -263,6 +264,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 +285,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 01ab408e..35598505 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; @@ -84,9 +85,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 +99,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() } @@ -130,16 +131,22 @@ 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); + 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 / nb_pools) { + let frames = allocate_new_frames( + &stream_info, + min_num_frames - pool_num_frames, + )?; + pool.add_frames(frames).unwrap(); + } } } }