dav1d: Only drain at most one decoded frame per input frame unless the decoder requires more before accepting new data

This works around a race condition in dav1d where the decoder deadlocks
if multiple threads are used, and also is generally beneficial as it
allows for proper frame threading.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1055>
This commit is contained in:
Sebastian Dröge 2023-01-22 00:25:23 +02:00
parent 4582ae91ab
commit d110977580

View file

@ -380,13 +380,13 @@ impl Dav1dDec {
} }
fn drop_decoded_pictures(&self, state_guard: &mut MutexGuard<Option<State>>) { fn drop_decoded_pictures(&self, state_guard: &mut MutexGuard<Option<State>>) {
while let Ok(Some(pic)) = self.pending_pictures(state_guard) { while let Ok(Some(pic)) = self.pending_picture(state_guard) {
gst::debug!(CAT, imp: self, "Dropping picture {}", pic.offset()); gst::debug!(CAT, imp: self, "Dropping picture {}", pic.offset());
drop(pic); drop(pic);
} }
} }
fn pending_pictures( fn pending_picture(
&self, &self,
state_guard: &mut MutexGuard<Option<State>>, state_guard: &mut MutexGuard<Option<State>>,
) -> Result<Option<dav1d::Picture>, gst::FlowError> { ) -> Result<Option<dav1d::Picture>, gst::FlowError> {
@ -425,9 +425,13 @@ impl Dav1dDec {
fn forward_pending_pictures<'s>( fn forward_pending_pictures<'s>(
&'s self, &'s self,
mut state_guard: MutexGuard<'s, Option<State>>, mut state_guard: MutexGuard<'s, Option<State>>,
drain: bool,
) -> Result<MutexGuard<Option<State>>, gst::FlowError> { ) -> Result<MutexGuard<Option<State>>, gst::FlowError> {
while let Some(pic) = self.pending_pictures(&mut state_guard)? { while let Some(pic) = self.pending_picture(&mut state_guard)? {
state_guard = self.handle_picture(state_guard, &pic)?; state_guard = self.handle_picture(state_guard, &pic)?;
if !drain {
break;
}
} }
Ok(state_guard) Ok(state_guard)
@ -709,19 +713,18 @@ impl VideoDecoderImpl for Dav1dDec {
{ {
let mut state_guard = self.state.lock().unwrap(); let mut state_guard = self.state.lock().unwrap();
state_guard = self.forward_pending_pictures(state_guard)?;
if self.send_data(&mut state_guard, input_buffer, frame)? if self.send_data(&mut state_guard, input_buffer, frame)?
== std::ops::ControlFlow::Continue(()) == std::ops::ControlFlow::Continue(())
{ {
loop { loop {
state_guard = self.forward_pending_pictures(state_guard)?; state_guard = self.forward_pending_pictures(state_guard, false)?;
if self.send_pending_data(&mut state_guard)? == std::ops::ControlFlow::Break(()) if self.send_pending_data(&mut state_guard)? == std::ops::ControlFlow::Break(())
{ {
break; break;
} }
} }
} }
let _state_guard = self.forward_pending_pictures(state_guard)?; let _state_guard = self.forward_pending_pictures(state_guard, false)?;
} }
Ok(gst::FlowSuccess::Ok) Ok(gst::FlowSuccess::Ok)
@ -750,7 +753,7 @@ impl VideoDecoderImpl for Dav1dDec {
if state_guard.is_some() { if state_guard.is_some() {
let state = state_guard.as_mut().unwrap(); let state = state_guard.as_mut().unwrap();
self.flush_decoder(state); self.flush_decoder(state);
let _state_guard = self.forward_pending_pictures(state_guard)?; let _state_guard = self.forward_pending_pictures(state_guard, true)?;
} }
} }
@ -765,7 +768,7 @@ impl VideoDecoderImpl for Dav1dDec {
if state_guard.is_some() { if state_guard.is_some() {
let state = state_guard.as_mut().unwrap(); let state = state_guard.as_mut().unwrap();
self.flush_decoder(state); self.flush_decoder(state);
let _state_guard = self.forward_pending_pictures(state_guard)?; let _state_guard = self.forward_pending_pictures(state_guard, true)?;
} }
} }