diff --git a/src/decode.rs b/src/decode.rs index 03a4d7f52..3c06df151 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -69,6 +69,7 @@ use crate::src::internal::Rav1dFrameContext; use crate::src::internal::Rav1dFrameContext_frame_thread; use crate::src::internal::Rav1dFrameContext_lf; use crate::src::internal::Rav1dFrameData; +use crate::src::internal::Rav1dState; use crate::src::internal::Rav1dTaskContext; use crate::src::internal::Rav1dTileState; use crate::src::internal::Rav1dTileStateContext; @@ -170,7 +171,6 @@ use crate::src::warpmv::rav1d_find_affine_int; use crate::src::warpmv::rav1d_get_shear_params; use crate::src::warpmv::rav1d_set_affine_mv2d; use libc::ptrdiff_t; -use parking_lot::Mutex; use std::array; use std::cmp; use std::ffi::c_int; @@ -4992,18 +4992,18 @@ fn get_upscale_x0(in_w: c_int, out_w: c_int, step: c_int) -> c_int { x0 & 0x3fff } -pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { +pub fn rav1d_submit_frame(c: &Rav1dContext, state: &mut Rav1dState) -> Rav1dResult { // wait for c->out_delayed[next] and move into c->out if visible let (fc, out, _task_thread_lock) = if c.fc.len() > 1 { let mut task_thread_lock = c.task_thread.lock.lock(); - let next = c.frame_thread.next; - c.frame_thread.next = (c.frame_thread.next + 1) % c.fc.len() as u32; + let next = state.frame_thread.next; + state.frame_thread.next = (state.frame_thread.next + 1) % c.fc.len() as u32; let fc = &c.fc[next as usize]; while !fc.task_thread.finished.load(Ordering::SeqCst) { fc.task_thread.cond.wait(&mut task_thread_lock); } - let out_delayed = &mut c.frame_thread.out_delayed[next as usize]; + let out_delayed = &mut state.frame_thread.out_delayed[next as usize]; if out_delayed.p.data.is_some() || fc.task_thread.error.load(Ordering::SeqCst) != 0 { let first = c.task_thread.first.load(Ordering::SeqCst); if first as usize + 1 < c.fc.len() { @@ -5025,32 +5025,32 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { } let error = &mut *fc.task_thread.retval.try_lock().unwrap(); if error.is_some() { - c.cached_error = mem::take(&mut *error); - *c.cached_error_props.get_mut() = out_delayed.p.m.clone(); + state.cached_error = mem::take(&mut *error); + state.cached_error_props = out_delayed.p.m.clone(); let _ = mem::take(out_delayed); } else if out_delayed.p.data.is_some() { let progress = out_delayed.progress.as_ref().unwrap()[1].load(Ordering::Relaxed); if (out_delayed.visible || c.output_invisible_frames) && progress != FRAME_ERROR { - c.out = out_delayed.clone(); - c.event_flags |= out_delayed.flags.into(); + state.out = out_delayed.clone(); + state.event_flags |= out_delayed.flags.into(); } let _ = mem::take(out_delayed); } (fc, out_delayed, Some(task_thread_lock)) } else { - (&c.fc[0], &mut c.out, None) + (&c.fc[0], &mut state.out, None) }; let mut f = fc.data.try_write().unwrap(); - f.seq_hdr = c.seq_hdr.clone(); - f.frame_hdr = mem::take(&mut c.frame_hdr); + f.seq_hdr = state.seq_hdr.clone(); + f.frame_hdr = mem::take(&mut state.frame_hdr); let seq_hdr = f.seq_hdr.clone().unwrap(); fn on_error( fc: &Rav1dFrameContext, f: &mut Rav1dFrameData, out: &mut Rav1dThreadPicture, - cached_error_props: &Mutex, + cached_error_props: &mut Rav1dDataProps, m: &Rav1dDataProps, ) { fc.task_thread.error.store(1, Ordering::Relaxed); @@ -5070,7 +5070,7 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { let _ = mem::take(&mut f.mvs); let _ = mem::take(&mut f.seq_hdr); let _ = mem::take(&mut f.frame_hdr); - *cached_error_props.lock() = m.clone(); + *cached_error_props = m.clone(); f.tiles.clear(); fc.task_thread.finished.store(true, Ordering::SeqCst); @@ -5081,7 +5081,13 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { Some(dsp) => f.dsp = dsp, None => { writeln!(c.logger, "Compiled without support for {bpc}-bit decoding",); - on_error(fc, &mut f, out, &c.cached_error_props, &c.in_0.m); + on_error( + fc, + &mut f, + out, + &mut state.cached_error_props, + &state.in_0.m, + ); return Err(ENOPROTOOPT); } }; @@ -5095,34 +5101,53 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { if frame_hdr.frame_type.is_inter_or_switch() { if frame_hdr.primary_ref_frame != RAV1D_PRIMARY_REF_NONE { let pri_ref = frame_hdr.refidx[frame_hdr.primary_ref_frame as usize] as usize; - if c.refs[pri_ref].p.p.data.is_none() { - on_error(fc, &mut f, out, &c.cached_error_props, &c.in_0.m); + if state.refs[pri_ref].p.p.data.is_none() { + on_error( + fc, + &mut f, + out, + &mut state.cached_error_props, + &state.in_0.m, + ); return Err(EINVAL); } } for i in 0..7 { let refidx = frame_hdr.refidx[i] as usize; - if c.refs[refidx].p.p.data.is_none() - || (frame_hdr.size.width[0] * 2) < c.refs[refidx].p.p.p.w - || (frame_hdr.size.height * 2) < c.refs[refidx].p.p.p.h - || frame_hdr.size.width[0] > c.refs[refidx].p.p.p.w * 16 - || frame_hdr.size.height > c.refs[refidx].p.p.p.h * 16 - || seq_hdr.layout != c.refs[refidx].p.p.p.layout - || bpc != c.refs[refidx].p.p.p.bpc + if state.refs[refidx].p.p.data.is_none() + || (frame_hdr.size.width[0] * 2) < state.refs[refidx].p.p.p.w + || (frame_hdr.size.height * 2) < state.refs[refidx].p.p.p.h + || frame_hdr.size.width[0] > state.refs[refidx].p.p.p.w * 16 + || frame_hdr.size.height > state.refs[refidx].p.p.p.h * 16 + || seq_hdr.layout != state.refs[refidx].p.p.p.layout + || bpc != state.refs[refidx].p.p.p.bpc { for j in 0..i { let _ = mem::take(&mut f.refp[j]); } - on_error(fc, &mut f, out, &c.cached_error_props, &c.in_0.m); + on_error( + fc, + &mut f, + out, + &mut state.cached_error_props, + &state.in_0.m, + ); return Err(EINVAL); } - f.refp[i] = c.refs[refidx].p.clone(); - ref_coded_width[i] = c.refs[refidx].p.p.frame_hdr.as_ref().unwrap().size.width[0]; - if frame_hdr.size.width[0] != c.refs[refidx].p.p.p.w - || frame_hdr.size.height != c.refs[refidx].p.p.p.h + f.refp[i] = state.refs[refidx].p.clone(); + ref_coded_width[i] = state.refs[refidx] + .p + .p + .frame_hdr + .as_ref() + .unwrap() + .size + .width[0]; + if frame_hdr.size.width[0] != state.refs[refidx].p.p.p.w + || frame_hdr.size.height != state.refs[refidx].p.p.p.h { - f.svc[i][0].scale = scale_fac(c.refs[refidx].p.p.p.w, frame_hdr.size.width[0]); - f.svc[i][1].scale = scale_fac(c.refs[refidx].p.p.p.h, frame_hdr.size.height); + f.svc[i][0].scale = scale_fac(state.refs[refidx].p.p.p.w, frame_hdr.size.width[0]); + f.svc[i][1].scale = scale_fac(state.refs[refidx].p.p.p.h, frame_hdr.size.height); f.svc[i][0].step = f.svc[i][0].scale + 8 >> 4; f.svc[i][1].step = f.svc[i][1].scale + 8 >> 4; } else { @@ -5141,13 +5166,19 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { *fc.in_cdf.try_write().unwrap() = rav1d_cdf_thread_init_static(frame_hdr.quant.yac); } else { let pri_ref = frame_hdr.refidx[frame_hdr.primary_ref_frame as usize] as usize; - *fc.in_cdf.try_write().unwrap() = c.cdf[pri_ref].clone(); + *fc.in_cdf.try_write().unwrap() = state.cdf[pri_ref].clone(); } if frame_hdr.refresh_context != 0 { let res = rav1d_cdf_thread_alloc(c.fc.len() > 1); match res { Err(e) => { - on_error(fc, &mut f, out, &c.cached_error_props, &c.in_0.m); + on_error( + fc, + &mut f, + out, + &mut state.cached_error_props, + &state.in_0.m, + ); return Err(e); } Ok(res) => { @@ -5158,7 +5189,7 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { // FIXME qsort so tiles are in order (for frame threading) f.tiles.clear(); - mem::swap(&mut f.tiles, &mut c.tiles); + mem::swap(&mut f.tiles, &mut state.tiles); fc.task_thread .finished .store(f.tiles.is_empty(), Ordering::SeqCst); @@ -5167,22 +5198,28 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { // We must take itut_t35 out of the context before the call so borrowck can // see we mutably borrow `c.itut_t35` disjointly from the task thread lock. - let itut_t35 = mem::take(&mut c.itut_t35); + let itut_t35 = mem::take(&mut state.itut_t35); let res = rav1d_thread_picture_alloc( &c.fc, &c.logger, &c.allocator, - c.content_light.clone(), - c.mastering_display.clone(), + state.content_light.clone(), + state.mastering_display.clone(), c.output_invisible_frames, - c.max_spatial_id, - &c.frame_flags, + state.max_spatial_id, + &mut state.frame_flags, &mut f, bpc, itut_t35, ); if res.is_err() { - on_error(fc, &mut f, out, &c.cached_error_props, &c.in_0.m); + on_error( + fc, + &mut f, + out, + &mut state.cached_error_props, + &state.in_0.m, + ); return res; } @@ -5195,7 +5232,7 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { let res = rav1d_picture_alloc_copy(&c.logger, &mut f.cur, frame_hdr.size.width[0], &f.sr_cur.p); if res.is_err() { - on_error(fc, f, out, &c.cached_error_props, &c.in_0.m); + on_error(fc, f, out, &mut state.cached_error_props, &state.in_0.m); return res; } } else { @@ -5215,7 +5252,7 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { if c.fc.len() == 1 { if frame_hdr.show_frame != 0 || c.output_invisible_frames { *out = f.sr_cur.clone(); - c.event_flags |= f.sr_cur.flags.into(); + state.event_flags |= f.sr_cur.flags.into(); } } else { *out = f.sr_cur.clone(); @@ -5262,11 +5299,11 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { let ref_w = (ref_coded_width[i] + 7 >> 3) << 1; let ref_h = (f.refp[i].p.p.h + 7 >> 3) << 1; if ref_w == f.bw && ref_h == f.bh { - f.ref_mvs[i] = c.refs[refidx].refmvs.clone(); + f.ref_mvs[i] = state.refs[refidx].refmvs.clone(); } else { f.ref_mvs[i] = None; } - f.refrefpoc[i] = c.refs[refidx].refpoc; + f.refrefpoc[i] = state.refs[refidx].refpoc; } } else { f.ref_mvs.fill_with(Default::default); @@ -5289,7 +5326,9 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { let ref_w = (ref_coded_width[pri_ref] + 7 >> 3) << 1; let ref_h = (f.refp[pri_ref].p.p.h + 7 >> 3) << 1; if ref_w == f.bw && ref_h == f.bh { - f.prev_segmap = c.refs[frame_hdr.refidx[pri_ref] as usize].segmap.clone(); + f.prev_segmap = state.refs[frame_hdr.refidx[pri_ref] as usize] + .segmap + .clone(); } } @@ -5326,23 +5365,23 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { let refresh_frame_flags = frame_hdr.refresh_frame_flags as c_uint; for i in 0..8 { if refresh_frame_flags & (1 << i) != 0 { - if c.refs[i].p.p.frame_hdr.is_some() { - let _ = mem::take(&mut c.refs[i].p); + if state.refs[i].p.p.frame_hdr.is_some() { + let _ = mem::take(&mut state.refs[i].p); } - c.refs[i].p = f.sr_cur.clone(); + state.refs[i].p = f.sr_cur.clone(); if frame_hdr.refresh_context != 0 { - c.cdf[i] = f.out_cdf.clone(); + state.cdf[i] = f.out_cdf.clone(); } else { - c.cdf[i] = fc.in_cdf.try_read().unwrap().clone(); + state.cdf[i] = fc.in_cdf.try_read().unwrap().clone(); } - c.refs[i].segmap = f.cur_segmap.clone(); - let _ = mem::take(&mut c.refs[i].refmvs); + state.refs[i].segmap = f.cur_segmap.clone(); + let _ = mem::take(&mut state.refs[i].refmvs); if !frame_hdr.allow_intrabc { - c.refs[i].refmvs = f.mvs.clone(); + state.refs[i].refmvs = f.mvs.clone(); } - c.refs[i].refpoc = f.refpoc; + state.refs[i].refpoc = f.refpoc; } } drop(f); @@ -5350,19 +5389,25 @@ pub fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult { if c.fc.len() == 1 { let res = rav1d_decode_frame(c, &fc); if res.is_err() { - let _ = mem::take(&mut c.out); + let _ = mem::take(&mut state.out); for i in 0..8 { if refresh_frame_flags & (1 << i) != 0 { - if c.refs[i].p.p.frame_hdr.is_some() { - let _ = mem::take(&mut c.refs[i].p); + if state.refs[i].p.p.frame_hdr.is_some() { + let _ = mem::take(&mut state.refs[i].p); } - let _ = mem::take(&mut c.cdf[i]); - let _ = mem::take(&mut c.refs[i].segmap); - let _ = mem::take(&mut c.refs[i].refmvs); + let _ = mem::take(&mut state.cdf[i]); + let _ = mem::take(&mut state.refs[i].segmap); + let _ = mem::take(&mut state.refs[i].refmvs); } } let mut f = fc.data.try_write().unwrap(); - on_error(fc, &mut f, &mut c.out, &c.cached_error_props, &c.in_0.m); + on_error( + fc, + &mut f, + &mut state.out, + &mut state.cached_error_props, + &state.in_0.m, + ); return res; } } else { diff --git a/src/internal.rs b/src/internal.rs index 01673e3da..bfa1c0b45 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -368,16 +368,15 @@ impl Rav1dContextTaskThread { } } +/// State that was formerly part of [`Rav1dContext`] +/// that is flushed/reset in [`rav1d_flush`] and other `DAV1D_API`s. +/// It is not accessed by other threads +/// (not in the call tree of [`rav1d_worker_task`]). +/// +/// [`rav1d_flush`]: crate::src::lib::rav1d_flush +/// [`rav1d_worker_task`]: crate::src::thread_task::rav1d_worker_task #[derive(Default)] -#[repr(C)] -#[repr(align(64))] -pub struct Rav1dContext { - pub(crate) fc: Box<[Rav1dFrameContext]>, - - /// Worker thread join handles and communication, or main thread task - /// context if single-threaded - pub(crate) tc: Box<[Rav1dContextTaskThread]>, - +pub struct Rav1dState { /// Cache of OBUs that make up a single frame before we submit them /// to a frame worker to be decoded. pub(crate) tiles: Vec, @@ -392,34 +391,49 @@ pub struct Rav1dContext { pub(crate) in_0: Rav1dData, pub(crate) out: Rav1dThreadPicture, pub(crate) cache: Rav1dThreadPicture, - pub(crate) flush: AtomicBool, pub(crate) frame_thread: Rav1dContext_frame_thread, - // task threading (refer to tc[] for per_thread thingies) - pub(crate) task_thread: Arc, - // reference/entropy state pub(crate) refs: [Rav1dContext_refs; 8], pub(crate) cdf: [CdfThreadContext; 8], // Previously pooled + pub(crate) operating_point_idc: c_uint, + pub(crate) max_spatial_id: u8, + pub(crate) drain: bool, + pub(crate) frame_flags: PictureFlags, + pub(crate) event_flags: Rav1dEventFlags, + pub(crate) cached_error_props: Rav1dDataProps, + pub(crate) cached_error: Option, +} + +#[derive(Default)] +#[repr(C)] +#[repr(align(64))] +pub struct Rav1dContext { + pub(crate) state: Mutex, + + pub(crate) fc: Box<[Rav1dFrameContext]>, + + /// Worker thread join handles and communication, or main thread task + /// context if single-threaded + pub(crate) tc: Box<[Rav1dContextTaskThread]>, + + pub(crate) flush: AtomicBool, + + // task threading (refer to tc[] for per_thread thingies) + pub(crate) task_thread: Arc, + pub dsp: &'static Rav1dDSPContext, pub(crate) allocator: Rav1dPicAllocator, pub(crate) apply_grain: bool, pub(crate) operating_point: u8, - pub(crate) operating_point_idc: c_uint, pub(crate) all_layers: 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, pub(crate) inloop_filters: Rav1dInloopFilterType, pub(crate) decode_frame_type: Rav1dDecodeFrameType, - pub(crate) drain: bool, - pub(crate) frame_flags: Atomic, - pub(crate) event_flags: Rav1dEventFlags, - pub(crate) cached_error_props: Mutex, - pub(crate) cached_error: Option, pub(crate) logger: Option, diff --git a/src/lib.rs b/src/lib.rs index d69d48458..9932142fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,9 @@ use crate::src::internal::Rav1dBitDepthDSPContext; use crate::src::internal::Rav1dContext; use crate::src::internal::Rav1dContextTaskThread; use crate::src::internal::Rav1dContextTaskType; +use crate::src::internal::Rav1dContext_frame_thread; use crate::src::internal::Rav1dFrameContext; +use crate::src::internal::Rav1dState; use crate::src::internal::Rav1dTaskContext; use crate::src::internal::Rav1dTaskContext_task_thread; use crate::src::internal::TaskThreadData; @@ -171,7 +173,7 @@ pub unsafe extern "C" fn dav1d_get_frame_delay(s: *const Dav1dSettings) -> Dav1d } #[cold] -pub(crate) unsafe fn rav1d_open(c_out: &mut *mut Rav1dContext, s: &Rav1dSettings) -> Rav1dResult { +pub(crate) unsafe fn rav1d_open(c_out: &mut *const Rav1dContext, s: &Rav1dSettings) -> Rav1dResult { static initted: Once = Once::new(); initted.call_once(|| init_internal()); @@ -187,7 +189,6 @@ pub(crate) unsafe fn rav1d_open(c_out: &mut *mut Rav1dContext, s: &Rav1dSettings let c = Box::new(Default::default()); let c = Box::into_raw(c); *c_out = c; - let c: *mut Rav1dContext = *c_out; (*c).allocator = s.allocator.clone(); (*c).logger = s.logger.clone(); (*c).apply_grain = s.apply_grain; @@ -239,11 +240,17 @@ pub(crate) unsafe fn rav1d_open(c_out: &mut *mut Rav1dContext, s: &Rav1dSettings delayed_fg: Default::default(), }; (*c).task_thread = Arc::new(ttd); - (*c).frame_thread.out_delayed = if n_fc > 1 { - (0..n_fc).map(|_| Default::default()).collect() - } else { - Box::new([]) - }; + (*c).state = Mutex::new(Rav1dState { + frame_thread: Rav1dContext_frame_thread { + out_delayed: if n_fc > 1 { + (0..n_fc).map(|_| Default::default()).collect() + } else { + Box::new([]) + }, + ..Default::default() + }, + ..Default::default() + }); for fc in (*c).fc.iter_mut() { fc.task_thread.finished = AtomicBool::new(true); fc.task_thread.ttd = Arc::clone(&(*c).task_thread); @@ -285,13 +292,18 @@ pub(crate) unsafe fn rav1d_open(c_out: &mut *mut Rav1dContext, s: &Rav1dSettings #[no_mangle] #[cold] pub unsafe extern "C" fn dav1d_open( - c_out: *mut *mut Dav1dContext, + c_out: *mut *const Dav1dContext, s: *const Dav1dSettings, ) -> Dav1dResult { (|| { validate_input!((!c_out.is_null(), EINVAL))?; validate_input!((!s.is_null(), EINVAL))?; - rav1d_open(&mut *c_out, &s.read().try_into()?) + let c_out = &mut *c_out; + let s = s.read().try_into()?; + rav1d_open(c_out, &s).inspect_err(|_| { + *c_out = ptr::null_mut(); + })?; + Ok(()) })() .into() } @@ -328,13 +340,17 @@ impl Rav1dPicture { } } -unsafe fn output_image(c: &mut Rav1dContext, out: &mut Rav1dPicture) -> Rav1dResult { +unsafe fn output_image( + c: &Rav1dContext, + state: &mut Rav1dState, + out: &mut Rav1dPicture, +) -> Rav1dResult { let mut res = Ok(()); - let r#in: *mut Rav1dThreadPicture = if c.all_layers || c.max_spatial_id == 0 { - &mut c.out + let r#in: *mut Rav1dThreadPicture = if c.all_layers || state.max_spatial_id == 0 { + &mut state.out } else { - &mut c.cache + &mut state.cache }; if !c.apply_grain || !(*r#in).p.has_grain() { *out = mem::take(&mut (*r#in).p); @@ -343,49 +359,53 @@ 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 != 0 && c.out.p.data.is_some() { - *r#in = mem::take(&mut c.out); + if !c.all_layers && state.max_spatial_id != 0 && state.out.p.data.is_some() { + *r#in = mem::take(&mut state.out); } res } -fn output_picture_ready(c: &mut Rav1dContext, drain: bool) -> bool { - if c.cached_error.is_some() { +fn output_picture_ready(c: &Rav1dContext, state: &mut Rav1dState, drain: bool) -> bool { + if state.cached_error.is_some() { return true; } - 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 - || c.out.flags.contains(PictureFlags::NEW_TEMPORAL_UNIT) + if !c.all_layers && state.max_spatial_id != 0 { + if state.out.p.data.is_some() && state.cache.p.data.is_some() { + if state.max_spatial_id == state.cache.p.frame_hdr.as_ref().unwrap().spatial_id + || state.out.flags.contains(PictureFlags::NEW_TEMPORAL_UNIT) { return true; } - c.cache = mem::take(&mut c.out); + state.cache = mem::take(&mut state.out); return false; } else { - if c.cache.p.data.is_some() && drain { + if state.cache.p.data.is_some() && drain { return true; } else { - if c.out.p.data.is_some() { - c.cache = mem::take(&mut c.out); + if state.out.p.data.is_some() { + state.cache = mem::take(&mut state.out); return false; } } } } - c.out.p.data.is_some() + state.out.p.data.is_some() } -unsafe fn drain_picture(c: &mut Rav1dContext, out: &mut Rav1dPicture) -> Rav1dResult { +unsafe fn drain_picture( + c: &Rav1dContext, + state: &mut Rav1dState, + out: &mut Rav1dPicture, +) -> Rav1dResult { let mut drained = false; for _ in 0..c.fc.len() { - let next = c.frame_thread.next; + let next = state.frame_thread.next; let fc = &c.fc[next as usize]; let mut task_thread_lock = c.task_thread.lock.lock(); while !fc.task_thread.finished.load(Ordering::SeqCst) { fc.task_thread.cond.wait(&mut task_thread_lock); } - let out_delayed = &mut c.frame_thread.out_delayed[next as usize]; + let out_delayed = &mut state.frame_thread.out_delayed[next as usize]; if out_delayed.p.data.is_some() || fc.task_thread.error.load(Ordering::SeqCst) != 0 { let first = c.task_thread.first.load(Ordering::SeqCst); if first as usize + 1 < c.fc.len() { @@ -407,52 +427,52 @@ unsafe fn drain_picture(c: &mut Rav1dContext, out: &mut Rav1dPicture) -> Rav1dRe } else if drained { break; } - c.frame_thread.next = (c.frame_thread.next + 1) % c.fc.len() as u32; + state.frame_thread.next = (state.frame_thread.next + 1) % c.fc.len() as u32; drop(task_thread_lock); mem::take(&mut *fc.task_thread.retval.try_lock().unwrap()) .err_or(()) .inspect_err(|_| { - *c.cached_error_props.get_mut() = out_delayed.p.m.clone(); + state.cached_error_props = out_delayed.p.m.clone(); let _ = mem::take(out_delayed); })?; if out_delayed.p.data.is_some() { let progress = out_delayed.progress.as_ref().unwrap()[1].load(Ordering::Relaxed); if (out_delayed.visible || c.output_invisible_frames) && progress != FRAME_ERROR { - c.out = out_delayed.clone(); - c.event_flags |= out_delayed.flags.into(); + state.out = out_delayed.clone(); + state.event_flags |= out_delayed.flags.into(); } let _ = mem::take(out_delayed); - if output_picture_ready(c, false) { - return output_image(c, out); + if output_picture_ready(c, state, false) { + return output_image(c, state, out); } } } - if output_picture_ready(c, true) { - return output_image(c, out); + if output_picture_ready(c, state, true) { + return output_image(c, state, out); } Err(EAGAIN) } -fn gen_picture(c: &mut Rav1dContext) -> Rav1dResult { - if output_picture_ready(c, false) { +fn gen_picture(c: &Rav1dContext, state: &mut Rav1dState) -> Rav1dResult { + if output_picture_ready(c, state, false) { return Ok(()); } // Take so we don't have 2 `&mut`s. let Rav1dData { data: r#in, m: props, - } = mem::take(&mut c.in_0); + } = mem::take(&mut state.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); + let len = rav1d_parse_obus(c, state, &r#in, &props); if let Ok(len) = len { r#in.slice_in_place(len..); } // Note that [`output_picture_ready`] doesn't read [`Rav1dContext::in_0`]. - if output_picture_ready(c, false) { + if output_picture_ready(c, state, false) { // Restore into `c` when there's still data left. if !r#in.is_empty() { - c.in_0 = Rav1dData { + state.in_0 = Rav1dData { data: Some(r#in), m: props, } @@ -464,64 +484,64 @@ fn gen_picture(c: &mut Rav1dContext) -> Rav1dResult { Ok(()) } -pub(crate) fn rav1d_send_data(c: &mut Rav1dContext, in_0: &mut Rav1dData) -> Rav1dResult { +pub(crate) fn rav1d_send_data(c: &Rav1dContext, in_0: &mut Rav1dData) -> Rav1dResult { + let state = &mut *c.state.try_lock().unwrap(); if in_0.data.is_some() { let sz = in_0.data.as_ref().unwrap().len(); validate_input!((sz > 0 && sz <= usize::MAX / 2, EINVAL))?; - c.drain = false; + state.drain = false; } - if c.in_0.data.is_some() { + if state.in_0.data.is_some() { return Err(EAGAIN); } - c.in_0 = in_0.clone(); - let res = gen_picture(c); + state.in_0 = in_0.clone(); + let res = gen_picture(c, state); if res.is_ok() { let _ = mem::take(in_0); } - return res; + res } #[no_mangle] pub unsafe extern "C" fn dav1d_send_data( - c: *mut Rav1dContext, + c: *const Rav1dContext, in_0: *mut Dav1dData, ) -> Dav1dResult { (|| { validate_input!((!c.is_null(), EINVAL))?; validate_input!((!in_0.is_null(), EINVAL))?; + let c = &*c; let mut in_rust = in_0.read().into(); - let result = rav1d_send_data(&mut *c, &mut in_rust); + let result = rav1d_send_data(c, &mut in_rust); in_0.write(in_rust.into()); result })() .into() } -pub(crate) unsafe fn rav1d_get_picture( - c: &mut Rav1dContext, - out: &mut Rav1dPicture, -) -> Rav1dResult { - let drain = mem::replace(&mut c.drain, true); - gen_picture(c)?; - mem::take(&mut c.cached_error).err_or(())?; - if output_picture_ready(c, c.fc.len() == 1) { - return output_image(c, out); +pub(crate) unsafe fn rav1d_get_picture(c: &Rav1dContext, out: &mut Rav1dPicture) -> Rav1dResult { + let state = &mut *c.state.try_lock().unwrap(); + let drain = mem::replace(&mut state.drain, true); + gen_picture(c, state)?; + mem::take(&mut state.cached_error).err_or(())?; + if output_picture_ready(c, state, c.fc.len() == 1) { + return output_image(c, state, out); } if c.fc.len() > 1 && drain { - return drain_picture(c, out); + return drain_picture(c, state, out); } Err(EAGAIN) } #[no_mangle] pub unsafe extern "C" fn dav1d_get_picture( - c: *mut Dav1dContext, + c: *const Dav1dContext, out: *mut Dav1dPicture, ) -> Dav1dResult { (|| { validate_input!((!c.is_null(), EINVAL))?; validate_input!((!out.is_null(), EINVAL))?; - let c = &mut *c; + let c = &*c; let mut out_rust = Default::default(); // TODO(kkysen) Temporary until we return it directly. let result = rav1d_get_picture(c, &mut out_rust); out.write(out_rust.into()); @@ -531,7 +551,7 @@ pub unsafe extern "C" fn dav1d_get_picture( } pub(crate) fn rav1d_apply_grain( - c: &mut Rav1dContext, + c: &Rav1dContext, out: &mut Rav1dPicture, in_0: &Rav1dPicture, ) -> Rav1dResult { @@ -575,7 +595,7 @@ pub(crate) fn rav1d_apply_grain( #[no_mangle] pub unsafe extern "C" fn dav1d_apply_grain( - c: *mut Dav1dContext, + c: *const Dav1dContext, out: *mut Dav1dPicture, in_0: *const Dav1dPicture, ) -> Dav1dResult { @@ -583,7 +603,7 @@ pub unsafe extern "C" fn dav1d_apply_grain( validate_input!((!c.is_null(), EINVAL))?; validate_input!((!out.is_null(), EINVAL))?; validate_input!((!in_0.is_null(), EINVAL))?; - let c = &mut *c; + let c = &*c; let in_0 = in_0.read(); // Don't `.update_rav1d()` [`Rav1dSequenceHeader`] because it's meant to be read-only. // Don't `.update_rav1d()` [`Rav1dFrameHeader`] because it's meant to be read-only. @@ -597,20 +617,18 @@ pub unsafe extern "C" fn dav1d_apply_grain( .into() } -pub(crate) fn rav1d_flush(c: &mut Rav1dContext) { - let _ = mem::take(&mut c.in_0); - let _ = mem::take(&mut c.out); - let _ = mem::take(&mut c.cache); - c.drain = false; - c.cached_error = None; - let _ = mem::take(&mut c.refs); - let _ = mem::take(&mut c.cdf); - let _ = mem::take(&mut c.frame_hdr); - let _ = mem::take(&mut c.seq_hdr); - let _ = mem::take(&mut c.content_light); - let _ = mem::take(&mut c.mastering_display); - let _ = mem::take(&mut c.itut_t35); - let _ = mem::take(&mut c.cached_error_props); +pub(crate) fn rav1d_flush(c: &Rav1dContext) { + let state = &mut *c.state.try_lock().unwrap(); + + let old_state = mem::take(state); + state.tiles = old_state.tiles; + state.n_tiles = old_state.n_tiles; + state.frame_thread = old_state.frame_thread; + state.operating_point_idc = old_state.operating_point_idc; + state.max_spatial_id = old_state.max_spatial_id; + state.frame_flags = old_state.frame_flags; + state.event_flags = old_state.event_flags; + if c.fc.len() == 1 && c.tc.len() == 1 { return; } @@ -622,7 +640,7 @@ pub(crate) fn rav1d_flush(c: &mut Rav1dContext) { tc.thread_data.cond.wait(&mut task_thread_lock); } } - for fc in c.fc.iter_mut() { + for fc in c.fc.iter() { fc.task_thread.tasks.clear(); } c.task_thread.first.store(0, Ordering::SeqCst); @@ -633,32 +651,32 @@ pub(crate) fn rav1d_flush(c: &mut Rav1dContext) { c.task_thread.cond_signaled.store(0, Ordering::SeqCst); } if c.fc.len() > 1 { - for fc in wrapping_iter(c.fc.iter(), c.frame_thread.next as usize) { + for fc in wrapping_iter(c.fc.iter(), state.frame_thread.next as usize) { let _ = rav1d_decode_frame_exit(c, fc, Err(EGeneric)); *fc.task_thread.retval.try_lock().unwrap() = None; - let out_delayed = &mut c.frame_thread.out_delayed[fc.index]; + let out_delayed = &mut state.frame_thread.out_delayed[fc.index]; if out_delayed.p.frame_hdr.is_some() { let _ = mem::take(out_delayed); } } - c.frame_thread.next = 0; + state.frame_thread.next = 0; } c.flush.store(false, Ordering::SeqCst); } #[no_mangle] -pub unsafe extern "C" fn dav1d_flush(c: *mut Dav1dContext) { - rav1d_flush(&mut *c) +pub unsafe extern "C" fn dav1d_flush(c: *const Dav1dContext) { + rav1d_flush(&*c) } #[cold] -pub(crate) unsafe fn rav1d_close(c_out: &mut *mut Rav1dContext) { +pub(crate) unsafe fn rav1d_close(c_out: &mut *const Rav1dContext) { close_internal(c_out, true); } #[no_mangle] #[cold] -pub unsafe extern "C" fn dav1d_close(c_out: *mut *mut Dav1dContext) { +pub unsafe extern "C" fn dav1d_close(c_out: *mut *const Dav1dContext) { if validate_input!(!c_out.is_null()).is_err() { return; } @@ -666,15 +684,15 @@ pub unsafe extern "C" fn dav1d_close(c_out: *mut *mut Dav1dContext) { } #[cold] -unsafe fn close_internal(c_out: &mut *mut Rav1dContext, flush: bool) { - let c: *mut Rav1dContext = *c_out; +unsafe fn close_internal(c_out: &mut *const Rav1dContext, flush: bool) { + let c: *const Rav1dContext = *c_out; if c.is_null() { return; } *c_out = ptr::null_mut(); - let mut c = Box::from_raw(c); + let c = Arc::from_raw(c); if flush { - rav1d_flush(&mut c); + rav1d_flush(&c); } } @@ -701,13 +719,15 @@ impl Drop for Rav1dContext { #[no_mangle] pub unsafe extern "C" fn dav1d_get_event_flags( - c: *mut Dav1dContext, + c: *const Dav1dContext, flags: *mut Dav1dEventFlags, ) -> Dav1dResult { (|| { validate_input!((!c.is_null(), EINVAL))?; validate_input!((!flags.is_null(), EINVAL))?; - flags.write(mem::take(&mut (*c).event_flags).into()); + let c = &*c; + let state = &mut *c.state.try_lock().unwrap(); + flags.write(mem::take(&mut state.event_flags).into()); Ok(()) })() .into() @@ -715,13 +735,15 @@ pub unsafe extern "C" fn dav1d_get_event_flags( #[no_mangle] pub unsafe extern "C" fn dav1d_get_decode_error_data_props( - c: *mut Dav1dContext, + c: *const Dav1dContext, out: *mut Dav1dDataProps, ) -> Dav1dResult { (|| { validate_input!((!c.is_null(), EINVAL))?; validate_input!((!out.is_null(), EINVAL))?; - out.write(mem::take(&mut *((*c).cached_error_props).get_mut()).into()); + let c = &*c; + let state = &mut *c.state.try_lock().unwrap(); + out.write(mem::take(&mut state.cached_error_props).into()); Ok(()) })() .into() diff --git a/src/obu.rs b/src/obu.rs index 81f6e1053..45ba87ed8 100644 --- a/src/obu.rs +++ b/src/obu.rs @@ -61,6 +61,7 @@ use crate::src::error::Rav1dError::ERANGE; use crate::src::error::Rav1dResult; use crate::src::getbits::GetBits; use crate::src::internal::Rav1dContext; +use crate::src::internal::Rav1dState; use crate::src::internal::Rav1dTileGroup; use crate::src::internal::Rav1dTileGroupHeader; use crate::src::levels::ObuMetaType; @@ -602,7 +603,7 @@ pub(crate) fn rav1d_parse_sequence_header( } fn parse_frame_size( - c: &Rav1dContext, + state: &Rav1dState, seqhdr: &Rav1dSequenceHeader, refidx: Option<&[i8; RAV1D_REFS_PER_FRAME]>, frame_size_override: bool, @@ -611,7 +612,7 @@ fn parse_frame_size( if let Some(refidx) = refidx { for i in 0..7 { if gb.get_bit() { - let r#ref = &c.refs[refidx[i as usize] as usize].p; + let r#ref = &state.refs[refidx[i as usize] as usize].p; let ref_size = &r#ref.p.frame_hdr.as_ref().ok_or(EINVAL)?.size; let width1 = ref_size.width[1]; let height = ref_size.height; @@ -703,7 +704,7 @@ static default_mode_ref_deltas: Rav1dLoopfilterModeRefDeltas = Rav1dLoopfilterMo }; fn parse_refidx( - c: &Rav1dContext, + state: &Rav1dState, seqhdr: &Rav1dSequenceHeader, frame_ref_short_signaling: u8, frame_offset: u8, @@ -722,7 +723,7 @@ fn parse_refidx( shifted_frame_offset[i as usize] = current_frame_offset + get_poc_diff( seqhdr.order_hint_n_bits, - c.refs[i as usize] + state.refs[i as usize] .p .p .frame_hdr @@ -824,7 +825,7 @@ fn parse_refidx( let delta_ref_frame_id = gb.get_bits(seqhdr.delta_frame_id_n_bits.into()) as u32 + 1; let ref_frame_id = frame_id + (1 << seqhdr.frame_id_n_bits) - delta_ref_frame_id & (1 << seqhdr.frame_id_n_bits) - 1; - c.refs[refidx[i as usize] as usize] + state.refs[refidx[i as usize] as usize] .p .p .frame_hdr @@ -1124,7 +1125,7 @@ fn parse_seg_data(gb: &mut GetBits) -> Rav1dSegmentationDataSet { } fn parse_segmentation( - c: &Rav1dContext, + state: &Rav1dState, primary_ref_frame: u8, refidx: &[i8; RAV1D_REFS_PER_FRAME], quant: &Rav1dFrameHeader_quant, @@ -1157,7 +1158,7 @@ fn parse_segmentation( // segmentation data from the reference frame. assert!(primary_ref_frame != RAV1D_PRIMARY_REF_NONE); let pri_ref = refidx[primary_ref_frame as usize]; - c.refs[pri_ref as usize] + state.refs[pri_ref as usize] .p .p .frame_hdr @@ -1244,7 +1245,7 @@ fn parse_delta( } fn parse_loopfilter( - c: &Rav1dContext, + state: &Rav1dState, seqhdr: &Rav1dSequenceHeader, all_lossless: bool, allow_intrabc: bool, @@ -1284,7 +1285,7 @@ fn parse_loopfilter( mode_ref_deltas = default_mode_ref_deltas.clone(); } else { let r#ref = refidx[primary_ref_frame as usize]; - mode_ref_deltas = c.refs[r#ref as usize] + mode_ref_deltas = state.refs[r#ref as usize] .p .p .frame_hdr @@ -1427,7 +1428,7 @@ fn parse_restoration( } fn parse_skip_mode( - c: &Rav1dContext, + state: &Rav1dState, seqhdr: &Rav1dSequenceHeader, switchable_comp_refs: u8, frame_type: Rav1dFrameType, @@ -1445,7 +1446,7 @@ fn parse_skip_mode( let mut off_before_idx = 0; let mut off_after_idx = 0; for i in 0..7 { - let refpoc = c.refs[refidx[i as usize] as usize] + let refpoc = state.refs[refidx[i as usize] as usize] .p .p .frame_hdr @@ -1484,7 +1485,7 @@ fn parse_skip_mode( let mut off_before2 = 0xffffffff; let mut off_before2_idx = 0; for i in 0..7 { - let refpoc = c.refs[refidx[i as usize] as usize] + let refpoc = state.refs[refidx[i as usize] as usize] .p .p .frame_hdr @@ -1529,7 +1530,7 @@ fn parse_skip_mode( } fn parse_gmv( - c: &Rav1dContext, + state: &Rav1dState, frame_type: Rav1dFrameType, primary_ref_frame: u8, refidx: &[i8; RAV1D_REFS_PER_FRAME], @@ -1559,7 +1560,7 @@ fn parse_gmv( &default_gmv } else { let pri_ref = refidx[primary_ref_frame as usize]; - &c.refs[pri_ref as usize] + &state.refs[pri_ref as usize] .p .p .frame_hdr @@ -1709,7 +1710,7 @@ fn parse_film_grain_data( } fn parse_film_grain( - c: &Rav1dContext, + state: &Rav1dState, seqhdr: &Rav1dSequenceHeader, show_frame: u8, showable_frame: u8, @@ -1739,7 +1740,7 @@ fn parse_film_grain( } Rav1dFilmGrainData { seed, - ..c.refs[refidx as usize] + ..state.refs[refidx as usize] .p .p .frame_hdr @@ -1768,6 +1769,7 @@ fn parse_film_grain( fn parse_frame_hdr( c: &Rav1dContext, + state: &Rav1dState, seqhdr: &Rav1dSequenceHeader, temporal_id: u8, spatial_id: u8, @@ -1791,7 +1793,7 @@ fn parse_frame_hdr( let frame_id; if seqhdr.frame_id_numbers_present != 0 { frame_id = gb.get_bits(seqhdr.frame_id_n_bits.into()) as u32; - c.refs[existing_frame_idx as usize] + state.refs[existing_frame_idx as usize] .p .p .frame_hdr @@ -1937,7 +1939,7 @@ fn parse_frame_hdr( { return Err(EINVAL); } - size = parse_frame_size(c, seqhdr, None, frame_size_override, gb)?; + size = parse_frame_size(state, seqhdr, None, frame_size_override, gb)?; allow_intrabc = allow_screen_content_tools && !size.super_res.enabled && gb.get_bit(); use_ref_frame_mvs = 0; @@ -1961,7 +1963,7 @@ fn parse_frame_hdr( } frame_ref_short_signaling = (seqhdr.order_hint != 0 && gb.get_bit()) as u8; refidx = parse_refidx( - c, + state, seqhdr, frame_ref_short_signaling, frame_offset, @@ -1970,7 +1972,7 @@ fn parse_frame_hdr( )?; let use_ref = error_resilient_mode == 0 && frame_size_override; size = parse_frame_size( - c, + state, seqhdr, Some(&refidx).filter(|_| use_ref), frame_size_override, @@ -1998,11 +2000,11 @@ fn parse_frame_hdr( let tiling = parse_tiling(seqhdr, &size, &debug, gb)?; let quant = parse_quant(seqhdr, &debug, gb); - let segmentation = parse_segmentation(c, primary_ref_frame, &refidx, &quant, &debug, gb)?; + let segmentation = parse_segmentation(state, primary_ref_frame, &refidx, &quant, &debug, gb)?; let all_lossless = segmentation.lossless.iter().all(|&it| it); let delta = parse_delta(&quant, allow_intrabc, &debug, gb); let loopfilter = parse_loopfilter( - c, + state, seqhdr, all_lossless, allow_intrabc, @@ -2036,7 +2038,7 @@ fn parse_frame_hdr( }; debug.post(gb, "refmode"); let skip_mode = parse_skip_mode( - c, + state, seqhdr, switchable_comp_refs, frame_type, @@ -2053,9 +2055,17 @@ fn parse_frame_hdr( let reduced_txtp_set = gb.get_bit() as u8; debug.post(gb, "reducedtxtpset"); - let gmv = parse_gmv(c, frame_type, primary_ref_frame, &refidx, hp, &debug, gb)?; + let gmv = parse_gmv( + state, + frame_type, + primary_ref_frame, + &refidx, + hp, + &debug, + gb, + )?; let film_grain = parse_film_grain( - c, + state, seqhdr, show_frame, showable_frame, @@ -2134,23 +2144,24 @@ fn parse_tile_hdr(tiling: &Rav1dFrameHeader_tiling, gb: &mut GetBits) -> Rav1dTi } fn parse_obus( - c: &mut Rav1dContext, + c: &Rav1dContext, + state: &mut Rav1dState, r#in: &CArc<[u8]>, props: &Rav1dDataProps, gb: &mut GetBits, ) -> Rav1dResult<()> { - fn skip(c: &mut Rav1dContext) { + fn skip(state: &mut Rav1dState) { // update refs with only the headers in case we skip the frame for i in 0..8 { - if c.frame_hdr.as_ref().unwrap().refresh_frame_flags & (1 << i) != 0 { - let _ = mem::take(&mut c.refs[i as usize].p); - c.refs[i as usize].p.p.frame_hdr = c.frame_hdr.clone(); - c.refs[i as usize].p.p.seq_hdr = c.seq_hdr.clone(); + if state.frame_hdr.as_ref().unwrap().refresh_frame_flags & (1 << i) != 0 { + let _ = mem::take(&mut state.refs[i as usize].p); + state.refs[i as usize].p.p.frame_hdr = state.frame_hdr.clone(); + state.refs[i as usize].p.p.seq_hdr = state.seq_hdr.clone(); } } - let _ = mem::take(&mut c.frame_hdr); - c.n_tiles = 0; + let _ = mem::take(&mut state.frame_hdr); + state.n_tiles = 0; } // obu header @@ -2190,22 +2201,22 @@ fn parse_obus( // skip obu not belonging to the selected temporal/spatial layer if !matches!(r#type, Some(Rav1dObuType::SeqHdr | Rav1dObuType::Td)) && has_extension - && c.operating_point_idc != 0 + && state.operating_point_idc != 0 { - let in_temporal_layer = (c.operating_point_idc >> temporal_id & 1) as c_int; - let in_spatial_layer = (c.operating_point_idc >> spatial_id + 8 & 1) as c_int; + let in_temporal_layer = (state.operating_point_idc >> temporal_id & 1) as c_int; + let in_spatial_layer = (state.operating_point_idc >> spatial_id + 8 & 1) as c_int; if in_temporal_layer == 0 || in_spatial_layer == 0 { return Ok(()); } } fn parse_tile_grp( - c: &mut Rav1dContext, + state: &mut Rav1dState, r#in: &CArc<[u8]>, props: &Rav1dDataProps, gb: &mut GetBits, ) -> Rav1dResult { - let hdr = parse_tile_hdr(&c.frame_hdr.as_ref().ok_or(EINVAL)?.tiling, gb); + let hdr = parse_tile_hdr(&state.frame_hdr.as_ref().ok_or(EINVAL)?.tiling, gb); // Align to the next byte boundary and check for overrun. gb.bytealign(); if gb.has_error() != 0 { @@ -2216,16 +2227,16 @@ fn parse_obus( data.slice_in_place(gb.byte_pos()..); data.slice_in_place(..gb.remaining_len()); // Ensure tile groups are in order and sane; see 6.10.1. - if hdr.start > hdr.end || hdr.start != c.n_tiles { - c.tiles.clear(); - c.n_tiles = 0; + if hdr.start > hdr.end || hdr.start != state.n_tiles { + state.tiles.clear(); + state.n_tiles = 0; return Err(EINVAL); } - if let Err(_) = c.tiles.try_reserve_exact(1) { + if let Err(_) = state.tiles.try_reserve_exact(1) { return Err(EINVAL); } - c.n_tiles += 1 + hdr.end - hdr.start; - c.tiles.push(Rav1dTileGroup { + state.n_tiles += 1 + hdr.end - hdr.start; + state.tiles.push(Rav1dTileGroup { data: Rav1dData { data: Some(data), // TODO(kkysen) Are props needed here? @@ -2252,9 +2263,9 @@ fn parse_obus( } 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 { + state.operating_point_idc = seq_hdr.operating_points[op_idx as usize].idc as c_uint; + let spatial_mask = state.operating_point_idc >> 8; + state.max_spatial_id = if spatial_mask != 0 { ulog2(spatial_mask) as u8 } else { 0 @@ -2264,57 +2275,55 @@ fn parse_obus( // this is a new video sequence and can't use any previous state. // Free that state. - match &c.seq_hdr { + match &state.seq_hdr { None => { - c.frame_hdr = None; - c.frame_flags - .fetch_or(PictureFlags::NEW_SEQUENCE, Ordering::Relaxed); + state.frame_hdr = None; + state.frame_flags |= PictureFlags::NEW_SEQUENCE; } Some(c_seq_hdr) if !seq_hdr.eq_without_operating_parameter_info(&c_seq_hdr) => { // See 7.5, `operating_parameter_info` is allowed to change in // sequence headers of a single sequence. - c.frame_hdr = None; - let _ = mem::take(&mut c.content_light); - let _ = mem::take(&mut c.mastering_display); + state.frame_hdr = None; + let _ = mem::take(&mut state.content_light); + let _ = mem::take(&mut state.mastering_display); for i in 0..8 { - if c.refs[i as usize].p.p.frame_hdr.is_some() { - let _ = mem::take(&mut c.refs[i as usize].p); + if state.refs[i as usize].p.p.frame_hdr.is_some() { + let _ = mem::take(&mut state.refs[i as usize].p); } - let _ = mem::take(&mut c.refs[i as usize].segmap); - let _ = mem::take(&mut c.refs[i as usize].refmvs); - let _ = mem::take(&mut c.cdf[i]); + let _ = mem::take(&mut state.refs[i as usize].segmap); + let _ = mem::take(&mut state.refs[i as usize].refmvs); + let _ = mem::take(&mut state.cdf[i]); } - c.frame_flags - .fetch_or(PictureFlags::NEW_SEQUENCE, Ordering::Relaxed); + state.frame_flags |= PictureFlags::NEW_SEQUENCE; } Some(c_seq_hdr) if seq_hdr.operating_parameter_info != c_seq_hdr.operating_parameter_info => { // If operating_parameter_info changed, signal it - c.frame_flags - .fetch_or(PictureFlags::NEW_OP_PARAMS_INFO, Ordering::Relaxed); + state.frame_flags |= PictureFlags::NEW_OP_PARAMS_INFO; } _ => {} } - c.seq_hdr = Some(Arc::new(DRav1d::from_rav1d(seq_hdr))); // TODO(kkysen) fallible allocation + state.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) if state.frame_hdr.is_some() => {} Some(Rav1dObuType::RedundantFrameHdr | Rav1dObuType::Frame | Rav1dObuType::FrameHdr) => { - c.frame_hdr = None; + state.frame_hdr = None; // TODO(kkysen) C originally re-used this allocation, // but it was also pooling, which we've dropped for now. let frame_hdr = parse_frame_hdr( c, - c.seq_hdr.as_ref().ok_or(EINVAL)?, + state, + state.seq_hdr.as_ref().ok_or(EINVAL)?, temporal_id, spatial_id, gb, ) .inspect_err(|_| writeln!(c.logger, "Error parsing frame header"))?; - c.tiles.clear(); - c.n_tiles = 0; + state.tiles.clear(); + state.n_tiles = 0; if r#type != Some(Rav1dObuType::Frame) { // This is actually a frame header OBU, // so read the trailing bit and check for overrun. @@ -2340,18 +2349,18 @@ fn parse_obus( } } - c.frame_hdr = Some(Arc::new(DRav1d::from_rav1d(frame_hdr))); // TODO(kkysen) fallible allocation + state.frame_hdr = Some(Arc::new(DRav1d::from_rav1d(frame_hdr))); // TODO(kkysen) fallible allocation if r#type == Some(Rav1dObuType::Frame) { // This is the frame header at the start of a frame OBU. // There's no trailing bit at the end to skip, // but we do need to align to the next byte. gb.bytealign(); - parse_tile_grp(c, r#in, props, gb)?; + parse_tile_grp(state, r#in, props, gb)?; } } Some(Rav1dObuType::TileGrp) => { - parse_tile_grp(c, r#in, props, gb)?; + parse_tile_grp(state, r#in, props, gb)?; } Some(Rav1dObuType::Metadata) => { let debug = Debug::new(false, "OBU", &gb); @@ -2380,7 +2389,7 @@ fn parse_obus( check_trailing_bits(gb, c.strict_std_compliance)?; - c.content_light = Some(Arc::new(Rav1dContentLightLevel { + state.content_light = Some(Arc::new(Rav1dContentLightLevel { max_content_light_level, max_frame_average_light_level, })); // TODO(kkysen) fallible allocation @@ -2403,7 +2412,7 @@ fn parse_obus( debug.log(&gb, format_args!("min-luminance: {min_luminance}")); check_trailing_bits(gb, c.strict_std_compliance)?; - c.mastering_display = Some(Arc::new(Rav1dMasteringDisplay { + state.mastering_display = Some(Arc::new(Rav1dMasteringDisplay { primaries, white_point, max_luminance, @@ -2437,7 +2446,7 @@ fn parse_obus( country_code_extension_byte, payload, }; - c.itut_t35.try_lock().unwrap().push(itut_t35); // TODO fallible allocation + state.itut_t35.try_lock().unwrap().push(itut_t35); // TODO fallible allocation } } Some(ObuMetaType::Scalability | ObuMetaType::Timecode) => {} // Ignore metadata OBUs we don't care about. @@ -2447,10 +2456,7 @@ fn parse_obus( } } } - Some(Rav1dObuType::Td) => { - c.frame_flags - .fetch_or(PictureFlags::NEW_TEMPORAL_UNIT, Ordering::Relaxed); - } + Some(Rav1dObuType::Td) => state.frame_flags |= PictureFlags::NEW_TEMPORAL_UNIT, Some(Rav1dObuType::Padding) => {} // Ignore OBUs we don't care about. None => { // Print a warning, but don't fail for unknown types. @@ -2459,10 +2465,10 @@ fn parse_obus( } } - if let (Some(_), Some(frame_hdr)) = (c.seq_hdr.as_ref(), c.frame_hdr.as_ref()) { + if let (Some(_), Some(frame_hdr)) = (state.seq_hdr.as_ref(), state.frame_hdr.as_ref()) { let frame_hdr = &***frame_hdr; if frame_hdr.show_existing_frame != 0 { - match c.refs[frame_hdr.existing_frame_idx as usize] + match state.refs[frame_hdr.existing_frame_idx as usize] .p .p .frame_hdr @@ -2472,17 +2478,17 @@ fn parse_obus( { Rav1dFrameType::Inter | Rav1dFrameType::Switch => { if c.decode_frame_type > Rav1dDecodeFrameType::Reference { - return Ok(skip(c)); + return Ok(skip(state)); } } Rav1dFrameType::Intra => { if c.decode_frame_type > Rav1dDecodeFrameType::Intra { - return Ok(skip(c)); + return Ok(skip(state)); } } _ => {} } - if c.refs[frame_hdr.existing_frame_idx as usize] + if state.refs[frame_hdr.existing_frame_idx as usize] .p .p .data @@ -2490,32 +2496,36 @@ fn parse_obus( { return Err(EINVAL); } - if c.strict_std_compliance && !c.refs[frame_hdr.existing_frame_idx as usize].p.showable + if c.strict_std_compliance + && !state.refs[frame_hdr.existing_frame_idx as usize].p.showable { return Err(EINVAL); } if c.fc.len() == 1 { - c.out = c.refs[frame_hdr.existing_frame_idx as usize].p.clone(); + state.out = state.refs[frame_hdr.existing_frame_idx as usize].p.clone(); rav1d_picture_copy_props( - &mut (*c).out.p, - c.content_light.clone(), - c.mastering_display.clone(), + &mut state.out.p, + state.content_light.clone(), + state.mastering_display.clone(), // Must be moved from the context to the frame. - Rav1dITUTT35::to_immut(mem::take(&mut c.itut_t35)), + Rav1dITUTT35::to_immut(mem::take(&mut state.itut_t35)), props.clone(), ); - c.event_flags |= c.refs[frame_hdr.existing_frame_idx as usize].p.flags.into(); + state.event_flags |= state.refs[frame_hdr.existing_frame_idx as usize] + .p + .flags + .into(); } else { let mut task_thread_lock = c.task_thread.lock.lock(); // Need to append this to the frame output queue. - let next = c.frame_thread.next; - c.frame_thread.next = (c.frame_thread.next + 1) % c.fc.len() as u32; + let next = state.frame_thread.next; + state.frame_thread.next = (state.frame_thread.next + 1) % c.fc.len() as u32; let fc = &c.fc[next as usize]; while !fc.task_thread.finished.load(Ordering::SeqCst) { fc.task_thread.cond.wait(&mut task_thread_lock); } - let out_delayed = &mut c.frame_thread.out_delayed[next as usize]; + let out_delayed = &mut state.frame_thread.out_delayed[next as usize]; if out_delayed.p.data.is_some() || fc.task_thread.error.load(Ordering::SeqCst) != 0 { let first = c.task_thread.first.load(Ordering::SeqCst); @@ -2538,31 +2548,31 @@ fn parse_obus( } let error = &mut *fc.task_thread.retval.try_lock().unwrap(); if error.is_some() { - c.cached_error = mem::take(error); - *c.cached_error_props.get_mut() = out_delayed.p.m.clone(); + state.cached_error = mem::take(error); + state.cached_error_props = out_delayed.p.m.clone(); let _ = mem::take(out_delayed); } else if out_delayed.p.data.is_some() { let progress = out_delayed.progress.as_ref().unwrap()[1].load(Ordering::Relaxed); if (out_delayed.visible || c.output_invisible_frames) && progress != FRAME_ERROR { - c.out = out_delayed.clone(); - c.event_flags |= out_delayed.flags.into(); + state.out = out_delayed.clone(); + state.event_flags |= out_delayed.flags.into(); } let _ = mem::take(out_delayed); } - *out_delayed = c.refs[frame_hdr.existing_frame_idx as usize].p.clone(); + *out_delayed = state.refs[frame_hdr.existing_frame_idx as usize].p.clone(); out_delayed.visible = true; rav1d_picture_copy_props( &mut out_delayed.p, - c.content_light.clone(), - c.mastering_display.clone(), + state.content_light.clone(), + state.mastering_display.clone(), // Must be moved from the context to the frame. - Rav1dITUTT35::to_immut(mem::take(&mut c.itut_t35)), + Rav1dITUTT35::to_immut(mem::take(&mut state.itut_t35)), props.clone(), ); } - if c.refs[frame_hdr.existing_frame_idx as usize] + if state.refs[frame_hdr.existing_frame_idx as usize] .p .p .frame_hdr @@ -2572,32 +2582,32 @@ fn parse_obus( == Rav1dFrameType::Key { let r = frame_hdr.existing_frame_idx; - c.refs[r as usize].p.showable = false; + state.refs[r as usize].p.showable = false; for i in 0..8 { if i == r { continue; } - if c.refs[i as usize].p.p.frame_hdr.is_some() { - let _ = mem::take(&mut c.refs[i as usize].p); + if state.refs[i as usize].p.p.frame_hdr.is_some() { + let _ = mem::take(&mut state.refs[i as usize].p); } - c.refs[i as usize].p = c.refs[r as usize].p.clone(); + state.refs[i as usize].p = state.refs[r as usize].p.clone(); - c.cdf[i as usize] = c.cdf[r as usize].clone(); + state.cdf[i as usize] = state.cdf[r as usize].clone(); - c.refs[i as usize].segmap = c.refs[r as usize].segmap.clone(); - let _ = mem::take(&mut c.refs[i as usize].refmvs); + state.refs[i as usize].segmap = state.refs[r as usize].segmap.clone(); + let _ = mem::take(&mut state.refs[i as usize].refmvs); } } - c.frame_hdr = None; - } else if c.n_tiles == frame_hdr.tiling.cols as c_int * frame_hdr.tiling.rows as c_int { + state.frame_hdr = None; + } else if state.n_tiles == frame_hdr.tiling.cols as c_int * frame_hdr.tiling.rows as c_int { match frame_hdr.frame_type { Rav1dFrameType::Inter | Rav1dFrameType::Switch => { if c.decode_frame_type > Rav1dDecodeFrameType::Reference || c.decode_frame_type == Rav1dDecodeFrameType::Reference && frame_hdr.refresh_frame_flags == 0 { - return Ok(skip(c)); + return Ok(skip(state)); } } Rav1dFrameType::Intra => { @@ -2605,18 +2615,18 @@ fn parse_obus( || c.decode_frame_type == Rav1dDecodeFrameType::Reference && frame_hdr.refresh_frame_flags == 0 { - return Ok(skip(c)); + return Ok(skip(state)); } } _ => {} } - if c.tiles.is_empty() { + if state.tiles.is_empty() { return Err(EINVAL); } - rav1d_submit_frame(c)?; - assert!(c.tiles.is_empty()); - c.frame_hdr = None; - c.n_tiles = 0; + rav1d_submit_frame(c, state)?; + assert!(state.tiles.is_empty()); + state.frame_hdr = None; + state.n_tiles = 0; } } @@ -2624,15 +2634,16 @@ fn parse_obus( } pub(crate) fn rav1d_parse_obus( - c: &mut Rav1dContext, + c: &Rav1dContext, + state: &mut Rav1dState, r#in: &CArc<[u8]>, props: &Rav1dDataProps, ) -> Rav1dResult { let gb = &mut GetBits::new(r#in); - parse_obus(c, r#in, props, gb) + parse_obus(c, state, r#in, props, gb) .inspect_err(|_| { - *c.cached_error_props.get_mut() = props.clone(); + state.cached_error_props = props.clone(); writeln!( c.logger, "{}", diff --git a/src/picture.rs b/src/picture.rs index 66650fc96..39b1e8043 100644 --- a/src/picture.rs +++ b/src/picture.rs @@ -25,9 +25,6 @@ use crate::src::internal::Rav1dFrameData; use crate::src::log::Rav1dLog as _; use crate::src::log::Rav1dLogger; use crate::src::mem::MemPool; -use atomig::Atom; -use atomig::AtomLogic; -use atomig::Atomic; use bitflags::bitflags; use libc::ptrdiff_t; use parking_lot::Mutex; @@ -37,11 +34,10 @@ use std::mem; use std::ptr; use std::ptr::NonNull; use std::sync::atomic::AtomicU32; -use std::sync::atomic::Ordering; use std::sync::Arc; use to_method::To as _; -#[derive(Clone, Copy, PartialEq, Eq, Hash, Default, Atom, AtomLogic)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)] pub struct PictureFlags(u8); bitflags! { @@ -246,7 +242,7 @@ pub(crate) fn rav1d_thread_picture_alloc( mastering_display: Option>, output_invisible_frames: bool, max_spatial_id: u8, - frame_flags: &Atomic, + frame_flags: &mut PictureFlags, f: &mut Rav1dFrameData, bpc: u8, itut_t35: Arc>>, @@ -282,7 +278,8 @@ pub(crate) fn rav1d_thread_picture_alloc( } else { PictureFlags::NEW_SEQUENCE | PictureFlags::NEW_OP_PARAMS_INFO }; - p.flags = frame_flags.fetch_and(flags_mask, Ordering::Relaxed); + p.flags = *frame_flags; + *frame_flags &= flags_mask; p.visible = frame_hdr.show_frame != 0; p.showable = frame_hdr.showable_frame != 0; p.progress = if have_frame_mt { diff --git a/src/thread_task.rs b/src/thread_task.rs index e2b78520e..793a6f70a 100644 --- a/src/thread_task.rs +++ b/src/thread_task.rs @@ -185,7 +185,7 @@ impl Rav1dTasks { b: Rav1dTaskIndex, cond_signal: c_int, ) { - let ttd: &TaskThreadData = &*c.task_thread; + let ttd = &*c.task_thread; if c.flush.load(Ordering::SeqCst) { return; } @@ -280,12 +280,12 @@ impl Rav1dTasks { Rav1dTaskIndex(NonZeroU32::new(tasks.len() as u32)) } - pub fn clear(&mut self) { - self.tasks.get_mut().clear(); - self.pending_tasks.get_mut().clear(); - self.pending_tasks_merge = AtomicBool::new(false); - self.head = Default::default(); - self.cur_prev = Default::default(); + pub fn clear(&self) { + self.tasks.try_write().unwrap().clear(); + self.pending_tasks.try_lock().unwrap().clear(); + self.pending_tasks_merge.store(false, Ordering::SeqCst); + self.head.store(Default::default(), Ordering::Relaxed); + self.cur_prev.store(Default::default(), Ordering::Relaxed); } pub fn remove(&self, t: Rav1dTaskIndex, prev_t: Rav1dTaskIndex) -> Option { @@ -488,12 +488,8 @@ pub(crate) fn rav1d_task_frame_init(c: &Rav1dContext, fc: &Rav1dFrameContext) { fc.task_thread.insert_task(c, init_task, 1); } -pub(crate) fn rav1d_task_delayed_fg( - c: &mut Rav1dContext, - out: &mut Rav1dPicture, - in_0: &Rav1dPicture, -) { - let ttd: &TaskThreadData = &c.task_thread; +pub(crate) fn rav1d_task_delayed_fg(c: &Rav1dContext, out: &mut Rav1dPicture, in_0: &Rav1dPicture) { + let ttd = &*c.task_thread; { let mut delayed_fg = ttd.delayed_fg.try_write().unwrap(); delayed_fg.in_0 = in_0.clone(); diff --git a/tests/seek_stress.rs b/tests/seek_stress.rs index 3f5ade523..01d4feef8 100644 --- a/tests/seek_stress.rs +++ b/tests/seek_stress.rs @@ -105,7 +105,11 @@ unsafe fn xor128_rand() -> c_int { } #[inline] -unsafe fn decode_frame(p: *mut Dav1dPicture, c: *mut Dav1dContext, data: *mut Dav1dData) -> c_int { +unsafe fn decode_frame( + p: *mut Dav1dPicture, + c: *const Dav1dContext, + data: *mut Dav1dData, +) -> c_int { let mut res: c_int; libc::memset(p as *mut c_void, 0, ::core::mem::size_of::()); res = dav1d_send_data(c, data).0; @@ -137,7 +141,7 @@ unsafe fn decode_frame(p: *mut Dav1dPicture, c: *mut Dav1dContext, data: *mut Da unsafe fn decode_rand( in_0: *mut DemuxerContext, - c: *mut Dav1dContext, + c: *const Dav1dContext, data: *mut Dav1dData, fps: c_double, ) -> c_int { @@ -160,7 +164,7 @@ unsafe fn decode_rand( unsafe fn decode_all( in_0: *mut DemuxerContext, - c: *mut Dav1dContext, + c: *const Dav1dContext, data: *mut Dav1dData, ) -> c_int { let mut res: c_int; @@ -179,7 +183,7 @@ unsafe fn decode_all( unsafe fn seek( in_0: *mut DemuxerContext, - c: *mut Dav1dContext, + c: *const Dav1dContext, pts: u64, data: *mut Dav1dData, ) -> c_int { @@ -318,7 +322,7 @@ unsafe fn main_0(argc: c_int, argv: *const *mut c_char) -> c_int { reserved: [0; 16], }; let mut in_0: *mut DemuxerContext = 0 as *mut DemuxerContext; - let mut c: *mut Dav1dContext = 0 as *mut Dav1dContext; + let mut c: *const Dav1dContext = 0 as *const Dav1dContext; let mut data: Dav1dData = Dav1dData { data: None, sz: 0, diff --git a/tools/dav1d.rs b/tools/dav1d.rs index c4455e6f6..fd8296e38 100644 --- a/tools/dav1d.rs +++ b/tools/dav1d.rs @@ -315,7 +315,7 @@ unsafe fn main_0(argc: c_int, argv: *const *mut c_char) -> c_int { let mut in_0: *mut DemuxerContext = 0 as *mut DemuxerContext; let mut out: *mut MuxerContext = 0 as *mut MuxerContext; let mut p = Default::default(); - let mut c: *mut Dav1dContext = 0 as *mut Dav1dContext; + let mut c: *const Dav1dContext = 0 as *const Dav1dContext; let mut data: Dav1dData = Dav1dData { data: None, sz: 0,