From 488d3f1e7d62c83dd51dfb99bb0277da1bf2d212 Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 2 Feb 2024 18:45:50 -0300 Subject: [PATCH 1/2] picture: propagate the new sequence event flag in the next picture if the current one is from a lower layer This further ensures the caller sees the DAV1D_EVENT_FLAG_NEW_SEQUENCE flag in the first output frame after a new sequence header is parsed even if the first coded frame is not meant to be output. --- src/picture.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/picture.c b/src/picture.c index 5309c9f19..9c7c781e3 100644 --- a/src/picture.c +++ b/src/picture.c @@ -214,9 +214,10 @@ int dav1d_thread_picture_alloc(Dav1dContext *const c, Dav1dFrameContext *const f c->itut_t35 = NULL; c->n_itut_t35 = 0; - // Don't clear these flags from c->frame_flags if the frame is not visible. + // Don't clear these flags from c->frame_flags if the frame is not going to be output. // This way they will be added to the next visible frame too. - const int flags_mask = (f->frame_hdr->show_frame || c->output_invisible_frames) + const int flags_mask = ((f->frame_hdr->show_frame || c->output_invisible_frames) && + c->max_spatial_id == f->frame_hdr->spatial_id) ? 0 : (PICTURE_FLAG_NEW_SEQUENCE | PICTURE_FLAG_NEW_OP_PARAMS_INFO); p->flags = c->frame_flags; c->frame_flags &= flags_mask; From dfa9f9f1ab47113a2d1601cadfe4a56c0c6a8723 Mon Sep 17 00:00:00 2001 From: Frank Bossen Date: Fri, 24 May 2024 13:24:37 -0400 Subject: [PATCH 2/2] Port C code changes to Rust and fix type for `max_spatial_id` Change type of `max_spatial_id` from `bool` to `u8` to ensure that tests comparing two values of `max_spatial_id` are correct. --- src/decode.rs | 1 + src/internal.rs | 2 +- src/lib.rs | 8 ++++---- src/obu.rs | 4 ++-- src/picture.rs | 7 ++++++- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/decode.rs b/src/decode.rs index 40ef219aa..63cfbf668 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -5203,6 +5203,7 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { c.content_light.clone(), c.mastering_display.clone(), c.output_invisible_frames, + c.max_spatial_id, &c.frame_flags, &mut f, bpc, diff --git a/src/internal.rs b/src/internal.rs index ce926869c..60c878fb3 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -407,7 +407,7 @@ pub struct Rav1dContext { pub(crate) operating_point: u8, pub(crate) operating_point_idc: c_uint, pub(crate) all_layers: bool, - pub(crate) max_spatial_id: bool, + pub(crate) max_spatial_id: u8, pub(crate) frame_size_limit: c_uint, pub(crate) strict_std_compliance: bool, pub(crate) output_invisible_frames: bool, diff --git a/src/lib.rs b/src/lib.rs index 7d68db825..be474c740 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -337,7 +337,7 @@ impl Rav1dPicture { unsafe fn output_image(c: &mut Rav1dContext, out: &mut Rav1dPicture) -> Rav1dResult { let mut res = Ok(()); - let r#in: *mut Rav1dThreadPicture = if c.all_layers || !c.max_spatial_id { + let r#in: *mut Rav1dThreadPicture = if c.all_layers || c.max_spatial_id == 0 { &mut c.out } else { &mut c.cache @@ -349,7 +349,7 @@ unsafe fn output_image(c: &mut Rav1dContext, out: &mut Rav1dPicture) -> Rav1dRes } let _ = mem::take(&mut *r#in); - if !c.all_layers && c.max_spatial_id && c.out.p.data.is_some() { + if !c.all_layers && c.max_spatial_id != 0 && c.out.p.data.is_some() { *r#in = mem::take(&mut c.out); } res @@ -359,9 +359,9 @@ fn output_picture_ready(c: &mut Rav1dContext, drain: bool) -> bool { if c.cached_error.is_some() { return true; } - if !c.all_layers && c.max_spatial_id { + if !c.all_layers && c.max_spatial_id != 0 { if c.out.p.data.is_some() && c.cache.p.data.is_some() { - if c.max_spatial_id == (c.cache.p.frame_hdr.as_ref().unwrap().spatial_id != 0) + if c.max_spatial_id == c.cache.p.frame_hdr.as_ref().unwrap().spatial_id || c.out.flags.contains(PictureFlags::NEW_TEMPORAL_UNIT) { return true; diff --git a/src/obu.rs b/src/obu.rs index 33f7ebc1c..1e4e7dc60 100644 --- a/src/obu.rs +++ b/src/obu.rs @@ -2256,9 +2256,9 @@ unsafe fn parse_obus( 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 + ulog2(spatial_mask) as u8 } else { - false + 0 }; // If we have read a sequence header which is different from the old one, diff --git a/src/picture.rs b/src/picture.rs index d2637376c..66650fc96 100644 --- a/src/picture.rs +++ b/src/picture.rs @@ -245,6 +245,7 @@ pub(crate) fn rav1d_thread_picture_alloc( content_light: Option>, mastering_display: Option>, output_invisible_frames: bool, + max_spatial_id: u8, frame_flags: &Atomic, f: &mut Rav1dFrameData, bpc: u8, @@ -272,7 +273,11 @@ pub(crate) fn rav1d_thread_picture_alloc( f.tiles[0].data.m.clone(), ); - let flags_mask = if frame_hdr.show_frame != 0 || output_invisible_frames { + // Don't clear these flags from `c.frame_flags` if the frame is not going to be output. + // This way they will be added to the next visible frame too. + let flags_mask = if (frame_hdr.show_frame != 0 || output_invisible_frames) + && max_spatial_id == frame_hdr.spatial_id + { PictureFlags::empty() } else { PictureFlags::NEW_SEQUENCE | PictureFlags::NEW_OP_PARAMS_INFO