diff --git a/src/getbits.rs b/src/getbits.rs index 87a121d2f..0357b11e7 100644 --- a/src/getbits.rs +++ b/src/getbits.rs @@ -180,4 +180,9 @@ impl<'a> GetBits<'a> { pub const fn pos(&self) -> usize { self.index * u8::BITS as usize - self.bits_left as usize } + + #[inline] + pub const fn has_pending_bits(&self) -> bool { + self.state != 0 || self.bits_left != 0 + } } diff --git a/src/lib.rs b/src/lib.rs index 3f9081da2..43ab042d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,8 @@ use crate::include::dav1d::dav1d::Dav1dSettings; use crate::include::dav1d::dav1d::Rav1dDecodeFrameType; use crate::include::dav1d::dav1d::Rav1dInloopFilterType; use crate::include::dav1d::dav1d::Rav1dSettings; -use crate::include::dav1d::headers::DRav1d; use crate::include::dav1d::headers::Dav1dSequenceHeader; use crate::include::dav1d::headers::Rav1dFilmGrainData; -use crate::include::dav1d::headers::Rav1dSequenceHeader; use crate::include::dav1d::picture::Dav1dPicture; use crate::include::dav1d::picture::Rav1dPicture; use crate::src::cdf::rav1d_cdf_thread_unref; @@ -25,7 +23,6 @@ use crate::src::error::Dav1dResult; use crate::src::error::Rav1dError::EGeneric; use crate::src::error::Rav1dError::EAGAIN; use crate::src::error::Rav1dError::EINVAL; -use crate::src::error::Rav1dError::ENOENT; use crate::src::error::Rav1dError::ENOMEM; use crate::src::error::Rav1dResult; use crate::src::fg_apply; @@ -37,13 +34,13 @@ use crate::src::internal::Rav1dTaskContext; use crate::src::internal::Rav1dTaskContext_task_thread; use crate::src::internal::TaskThreadData; use crate::src::log::Rav1dLog as _; -use crate::src::mem::freep; use crate::src::mem::rav1d_alloc_aligned; use crate::src::mem::rav1d_free_aligned; use crate::src::mem::rav1d_freep_aligned; use crate::src::mem::rav1d_mem_pool_end; use crate::src::mem::rav1d_mem_pool_init; use crate::src::obu::rav1d_parse_obus; +use crate::src::obu::rav1d_parse_sequence_header; use crate::src::picture::dav1d_default_picture_alloc; use crate::src::picture::dav1d_default_picture_release; use crate::src::picture::rav1d_picture_alloc_copy; @@ -398,57 +395,6 @@ pub unsafe extern "C" fn dav1d_open( .into() } -unsafe extern "C" fn dummy_free(data: *const u8, user_data: *mut c_void) { - if !(!data.is_null() && user_data.is_null()) { - unreachable!(); - } -} - -pub(crate) unsafe fn rav1d_parse_sequence_header( - ptr: *const u8, - sz: usize, -) -> Rav1dResult> { - let s = Rav1dSettings { - n_threads: 1, - logger: None, - ..Default::default() - }; - let mut c: *mut Rav1dContext = 0 as *mut Rav1dContext; - rav1d_open(&mut c, &s)?; - || -> Rav1dResult> { - let Rav1dData { - mut data, - m: mut props, - } = match NonNull::new(ptr.cast_mut()) { - None => Default::default(), - Some(ptr) => Rav1dData::wrap( - slice::from_raw_parts(ptr.as_ptr(), sz).into(), - Some(dummy_free), - ptr::null_mut(), - )?, - }; - if let Some(data) = &mut data { - while !data.is_empty() { - let len = rav1d_parse_obus(&mut *c, data, &mut props, true)?; - data.slice_in_place(len..); - } - } - - if (*c).seq_hdr.is_none() { - return Err(ENOENT); - } - - (*c).seq_hdr - .take() - .and_then(Arc::into_inner) - .map(Ok) - .unwrap() - }() - .inspect_err(|_| { - rav1d_close(&mut c); - }) -} - #[no_mangle] pub unsafe extern "C" fn dav1d_parse_sequence_header( out: *mut Dav1dSequenceHeader, @@ -457,7 +403,9 @@ pub unsafe extern "C" fn dav1d_parse_sequence_header( ) -> Dav1dResult { (|| { validate_input!((!out.is_null(), EINVAL))?; - let seq_hdr = rav1d_parse_sequence_header(ptr, sz)?; + validate_input!((!ptr.is_null(), EINVAL))?; + validate_input!((sz > 0, EINVAL))?; + let seq_hdr = rav1d_parse_sequence_header(slice::from_raw_parts(ptr, sz))?; out.write(seq_hdr.dav1d); Ok(()) })() @@ -607,7 +555,7 @@ unsafe fn gen_picture(c: &mut Rav1dContext) -> Rav1dResult { } = mem::take(&mut c.in_0); let Some(mut r#in) = r#in else { return Ok(()) }; while !r#in.is_empty() { - let len = rav1d_parse_obus(c, &r#in, &props, false); + let len = rav1d_parse_obus(c, &r#in, &props); if let Ok(len) = len { r#in.slice_in_place(len..); } diff --git a/src/obu.rs b/src/obu.rs index a914d43a8..46ed9ab7e 100644 --- a/src/obu.rs +++ b/src/obu.rs @@ -4,6 +4,7 @@ use crate::include::dav1d::common::Rav1dDataProps; use crate::include::dav1d::data::Rav1dData; use crate::include::dav1d::dav1d::Rav1dDecodeFrameType; use crate::include::dav1d::headers::DRav1d; +use crate::include::dav1d::headers::Dav1dSequenceHeader; use crate::include::dav1d::headers::Rav1dAdaptiveBoolean; use crate::include::dav1d::headers::Rav1dChromaSamplePosition; use crate::include::dav1d::headers::Rav1dColorPrimaries; @@ -59,6 +60,7 @@ use crate::src::cdf::rav1d_cdf_thread_unref; use crate::src::decode::rav1d_submit_frame; use crate::src::env::get_poc_diff; use crate::src::error::Rav1dError::EINVAL; +use crate::src::error::Rav1dError::ENOENT; use crate::src::error::Rav1dError::ERANGE; use crate::src::error::Rav1dResult; use crate::src::getbits::GetBits; @@ -130,7 +132,10 @@ impl Debug { } } -fn parse_seq_hdr(c: &mut Rav1dContext, gb: &mut GetBits) -> Rav1dResult { +fn parse_seq_hdr( + gb: &mut GetBits, + strict_std_compliance: bool, +) -> Rav1dResult { let debug = Debug::new(false, "SEQHDR", gb); let profile = Rav1dProfile::from_repr(gb.get_bits(3) as usize).ok_or(EINVAL)?; @@ -182,7 +187,7 @@ fn parse_seq_hdr(c: &mut Rav1dContext, gb: &mut GetBits) -> Rav1dResult Rav1dResult Rav1dResult> 8; - c.max_spatial_id = if spatial_mask != 0 { - ulog2(spatial_mask) != 0 - } else { - false - }; - let width_n_bits = gb.get_bits(4) as c_int + 1; let height_n_bits = gb.get_bits(4) as c_int + 1; let max_width = gb.get_bits(width_n_bits) as c_int + 1; @@ -468,7 +460,7 @@ fn parse_seq_hdr(c: &mut Rav1dContext, gb: &mut GetBits) -> Rav1dResult Rav1dResult Rav1dResult> { + let mut res = Err(ENOENT); + + while !data.is_empty() { + let mut gb = GetBits::new(data); + + gb.get_bit(); // obu_forbidden_bit + let r#type = Rav1dObuType::from_repr(gb.get_bits(4) as usize); + let has_extension = gb.get_bit(); + let has_length_field = gb.get_bit(); + gb.get_bits(1 + has_extension as i32 * 8); // reserved + + // obu length field + let obu_end = if has_length_field { + let len = gb.get_uleb128() as usize; + if len > data.len() { + return Err(EINVAL); + } + gb.pos() / u8::BITS as usize + len + } else { + data.len() + }; + + if r#type == Some(Rav1dObuType::SeqHdr) { + res = Ok(parse_seq_hdr(&mut gb, false)?); + if gb.pos() > obu_end * u8::BITS as usize { + return Err(EINVAL); + } + gb.bytealign(); + } + + if gb.has_error() != 0 { + return Err(EINVAL); + } + assert_eq!(gb.has_pending_bits(), false); + + data = &data[obu_end..] + } + + res.map(DRav1d::from_rav1d) +} + unsafe fn parse_frame_size( c: &Rav1dContext, seqhdr: &Rav1dSequenceHeader, @@ -2102,7 +2138,6 @@ unsafe fn parse_obus( c: &mut Rav1dContext, r#in: &CArc<[u8]>, props: &Rav1dDataProps, - global: bool, ) -> Rav1dResult { unsafe fn skip(c: &mut Rav1dContext, len: usize, init_byte_pos: usize) -> usize { // update refs with only the headers in case we skip the frame @@ -2225,12 +2260,26 @@ unsafe fn parse_obus( match r#type { Some(Rav1dObuType::SeqHdr) => { - let seq_hdr = parse_seq_hdr(c, &mut gb).inspect_err(|_| { + let seq_hdr = parse_seq_hdr(&mut gb, c.strict_std_compliance).inspect_err(|_| { writeln!(c.logger, "Error parsing sequence header"); })?; if check_for_overrun(c, &mut gb, init_bit_pos, len) != 0 { return Err(EINVAL); } + + let op_idx = if c.operating_point < seq_hdr.num_operating_points { + c.operating_point + } else { + 0 + }; + c.operating_point_idc = seq_hdr.operating_points[op_idx as usize].idc as c_uint; + let spatial_mask = c.operating_point_idc >> 8; + c.max_spatial_id = if spatial_mask != 0 { + ulog2(spatial_mask) != 0 + } else { + false + }; + // If we have read a sequence header which is different from the old one, // this is a new video sequence and can't use any previous state. // Free that state. @@ -2270,8 +2319,6 @@ unsafe fn parse_obus( c.seq_hdr = Some(Arc::new(DRav1d::from_rav1d(seq_hdr))); // TODO(kkysen) fallible allocation } Some(Rav1dObuType::RedundantFrameHdr) if c.frame_hdr.is_some() => {} - Some(Rav1dObuType::RedundantFrameHdr | Rav1dObuType::Frame | Rav1dObuType::FrameHdr) - if global => {} Some(Rav1dObuType::RedundantFrameHdr | Rav1dObuType::Frame | Rav1dObuType::FrameHdr) => { c.frame_hdr = None; // TODO(kkysen) C originally re-used this allocation, @@ -2323,15 +2370,11 @@ unsafe fn parse_obus( // There's no trailing bit at the end to skip, // but we do need to align to the next byte. gb.bytealign(); - if !global { - parse_tile_grp(c, r#in, props, &mut gb, init_bit_pos, init_byte_pos, len)?; - } + parse_tile_grp(c, r#in, props, &mut gb, init_bit_pos, init_byte_pos, len)?; } } Some(Rav1dObuType::TileGrp) => { - if !global { - parse_tile_grp(c, r#in, props, &mut gb, init_bit_pos, init_byte_pos, len)?; - } + parse_tile_grp(c, r#in, props, &mut gb, init_bit_pos, init_byte_pos, len)?; } Some(Rav1dObuType::Metadata) => { let debug = Debug::new(false, "OBU", &gb); @@ -2631,9 +2674,8 @@ pub(crate) unsafe fn rav1d_parse_obus( c: &mut Rav1dContext, r#in: &CArc<[u8]>, props: &Rav1dDataProps, - global: bool, ) -> Rav1dResult { - parse_obus(c, r#in, props, global).inspect_err(|_| { + parse_obus(c, r#in, props).inspect_err(|_| { *c.cached_error_props.get_mut().unwrap() = props.clone(); writeln!(c.logger, "Error parsing OBU data"); })