omxvideodec: fixes race condition during seeks
authorJosep Torra <n770galaxy@gmail.com>
Fri, 7 Mar 2014 19:08:05 +0000 (20:08 +0100)
committerJulien Isorce <julien.isorce@collabora.co.uk>
Tue, 25 Mar 2014 16:07:25 +0000 (16:07 +0000)
Acording 6.1.3 Seek Event Sequence in the OpenMAX IL 1.1.2 spec
document in order to flush the component it needs to be in
paused state.

https://bugzilla.gnome.org/show_bug.cgi?id=726038

omx/gstomxvideodec.c

index 8a46d40..682ac8f 100644 (file)
@@ -1950,6 +1950,30 @@ gst_omx_video_dec_flush (GstVideoDecoder * decoder)
   if (gst_omx_component_get_state (self->dec, 0) == OMX_StateLoaded)
     return TRUE;
 
+  /* 0) Wait until the srcpad loop is stopped,
+   * unlock GST_VIDEO_DECODER_STREAM_LOCK to prevent deadlocks
+   * caused by using this lock from inside the loop function */
+  GST_VIDEO_DECODER_STREAM_UNLOCK (self);
+  gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
+  GST_DEBUG_OBJECT (self, "Flushing -- task stopped");
+  GST_VIDEO_DECODER_STREAM_LOCK (self);
+
+  /* 1) Pause the components */
+  if (gst_omx_component_get_state (self->dec, 0) == OMX_StateExecuting) {
+    gst_omx_component_set_state (self->dec, OMX_StatePause);
+    gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
+  }
+#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL)
+  if (self->eglimage) {
+    if (gst_omx_component_get_state (self->egl_render, 0) == OMX_StateExecuting) {
+      gst_omx_component_set_state (self->egl_render, OMX_StatePause);
+      gst_omx_component_get_state (self->egl_render, GST_CLOCK_TIME_NONE);
+    }
+  }
+#endif
+
+  /* 2) Flush the ports */
+  GST_DEBUG_OBJECT (self, "flushing ports");
   gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
   gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
 
@@ -1960,14 +1984,17 @@ gst_omx_video_dec_flush (GstVideoDecoder * decoder)
   }
 #endif
 
-  /* Wait until the srcpad loop is finished,
-   * unlock GST_VIDEO_DECODER_STREAM_LOCK to prevent deadlocks
-   * caused by using this lock from inside the loop function */
-  GST_VIDEO_DECODER_STREAM_UNLOCK (self);
-  GST_PAD_STREAM_LOCK (GST_VIDEO_DECODER_SRC_PAD (self));
-  GST_PAD_STREAM_UNLOCK (GST_VIDEO_DECODER_SRC_PAD (self));
-  GST_VIDEO_DECODER_STREAM_LOCK (self);
+  /* 3) Resume components */
+  gst_omx_component_set_state (self->dec, OMX_StateExecuting);
+  gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
+#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL)
+  if (self->eglimage) {
+    gst_omx_component_set_state (self->egl_render, OMX_StateExecuting);
+    gst_omx_component_get_state (self->egl_render, GST_CLOCK_TIME_NONE);
+  }
+#endif
 
+  /* 4) Unset flushing to allow ports to accept data again */
   gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, FALSE);
   gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
 
@@ -1976,6 +2003,7 @@ gst_omx_video_dec_flush (GstVideoDecoder * decoder)
     gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
     gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
     err = gst_omx_port_populate (self->egl_out_port);
+    gst_omx_port_mark_reconfigured (self->egl_out_port);
   } else {
     err = gst_omx_port_populate (self->dec_out_port);
   }
@@ -1988,14 +2016,12 @@ gst_omx_video_dec_flush (GstVideoDecoder * decoder)
         gst_omx_error_to_string (err), err);
   }
 
-  /* Start the srcpad loop again */
+  /* Reset our state */
   self->last_upstream_ts = 0;
   self->eos = FALSE;
   self->downstream_flow_ret = GST_FLOW_OK;
-  gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self),
-      (GstTaskFunction) gst_omx_video_dec_loop, decoder, NULL);
-
-  GST_DEBUG_OBJECT (self, "Flush decoder");
+  self->started = FALSE;
+  GST_DEBUG_OBJECT (self, "Flush finished");
 
   return TRUE;
 }
@@ -2025,9 +2051,14 @@ gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder,
     return GST_FLOW_EOS;
   }
 
-  if (!self->started && !GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
-    gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
-    return GST_FLOW_OK;
+  if (!self->started) {
+    if (!GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
+      gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
+      return GST_FLOW_OK;
+    }
+    GST_DEBUG_OBJECT (self, "Starting task");
+    gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self),
+        (GstTaskFunction) gst_omx_video_dec_loop, decoder, NULL);
   }
 
   timestamp = frame->pts;