aboutsummaryrefslogtreecommitdiff
path: root/sys/v4l2/gstv4l2videodec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/v4l2/gstv4l2videodec.c')
-rw-r--r--sys/v4l2/gstv4l2videodec.c124
1 files changed, 80 insertions, 44 deletions
diff --git a/sys/v4l2/gstv4l2videodec.c b/sys/v4l2/gstv4l2videodec.c
index 1b4a051c..f3e03c78 100644
--- a/sys/v4l2/gstv4l2videodec.c
+++ b/sys/v4l2/gstv4l2videodec.c
@@ -259,23 +259,23 @@ gst_v4l2_video_dec_flush (GstVideoDecoder * decoder)
{
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
- GST_DEBUG_OBJECT (self, "Flushing");
+ GST_DEBUG_OBJECT (self, "Flushed");
- /* Wait for capture thread to stop */
- GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
- gst_v4l2_object_unlock (self->v4l2capture);
- gst_pad_stop_task (decoder->srcpad);
- GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+ /* Ensure the processing thread has stopped for the reverse playback
+ * discount case */
+ if (g_atomic_int_get (&self->processing)) {
+ GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
- self->output_flow = GST_FLOW_OK;
+ gst_v4l2_object_unlock (self->v4l2output);
+ gst_v4l2_object_unlock (self->v4l2capture);
+ gst_pad_stop_task (decoder->srcpad);
+ GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
+ }
- if (self->v4l2output->pool)
- gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
- (self->v4l2output->pool));
+ self->output_flow = GST_FLOW_OK;
- if (self->v4l2capture->pool)
- gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
- (self->v4l2capture->pool));
+ gst_v4l2_object_unlock_stop (self->v4l2output);
+ gst_v4l2_object_unlock_stop (self->v4l2capture);
return TRUE;
}
@@ -293,7 +293,7 @@ gst_v4l2_video_dec_finish (GstVideoDecoder * decoder)
GstFlowReturn ret = GST_FLOW_OK;
GstBuffer *buffer;
- if (!self->processing)
+ if (!g_atomic_int_get (&self->processing))
goto done;
GST_DEBUG_OBJECT (self, "Finishing decoding");
@@ -308,14 +308,12 @@ gst_v4l2_video_dec_finish (GstVideoDecoder * decoder)
v4l2output->pool), &buffer);
gst_buffer_unref (buffer);
}
- GST_VIDEO_DECODER_STREAM_LOCK (decoder);
- /* Ensure the processing thread has stopped */
- if (g_atomic_int_get (&self->processing)) {
- gst_v4l2_object_unlock (self->v4l2capture);
- gst_pad_stop_task (decoder->srcpad);
- g_assert (g_atomic_int_get (&self->processing) == FALSE);
- }
+ /* and ensure the processing thread has stopped in case another error
+ * occured. */
+ gst_v4l2_object_unlock (self->v4l2capture);
+ gst_pad_stop_task (decoder->srcpad);
+ GST_VIDEO_DECODER_STREAM_LOCK (decoder);
if (ret == GST_FLOW_FLUSHING)
ret = self->output_flow;
@@ -420,6 +418,20 @@ beach:
gst_pad_pause_task (decoder->srcpad);
}
+static void
+gst_v4l2_video_dec_loop_stopped (GstV4l2VideoDec * self)
+{
+ /* When flushing, decoding thread may never run */
+ if (g_atomic_int_get (&self->processing)) {
+ GST_DEBUG_OBJECT (self, "Early stop of decoding thread");
+ self->output_flow = GST_FLOW_FLUSHING;
+ g_atomic_int_set (&self->processing, FALSE);
+ }
+
+ GST_DEBUG_OBJECT (self, "Decoding task destroyed: %s",
+ gst_flow_get_name (self->output_flow));
+}
+
static GstFlowReturn
gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
GstVideoCodecFrame * frame)
@@ -475,11 +487,9 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
}
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
- gst_v4l2_object_unlock_stop (self->v4l2output);
ret =
gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
v4l2output->pool), &codec_data);
- gst_v4l2_object_unlock (self->v4l2output);
GST_VIDEO_DECODER_STREAM_LOCK (decoder);
gst_buffer_unref (codec_data);
@@ -508,8 +518,9 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
}
if (g_atomic_int_get (&self->processing) == FALSE) {
- /* It possible that the processing thread stopped due to an error */
- if (self->output_flow != GST_FLOW_OK) {
+ /* It's possible that the processing thread stopped due to an error */
+ if (self->output_flow != GST_FLOW_OK &&
+ self->output_flow != GST_FLOW_FLUSHING) {
GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving");
ret = self->output_flow;
goto drop;
@@ -517,19 +528,13 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
GST_DEBUG_OBJECT (self, "Starting decoding thread");
- /* Enable processing input */
- if (!gst_v4l2_buffer_pool_start_streaming (GST_V4L2_BUFFER_POOL
- (self->v4l2capture->pool)))
- goto start_streaming_failed;
-
- gst_v4l2_object_unlock_stop (self->v4l2output);
- gst_v4l2_object_unlock_stop (self->v4l2capture);
-
/* Start the processing task, when it quits, the task will disable input
* processing to unlock input if draining, or prevent potential block */
g_atomic_int_set (&self->processing, TRUE);
- gst_pad_start_task (decoder->srcpad,
- (GstTaskFunction) gst_v4l2_video_dec_loop, self, NULL);
+ if (!gst_pad_start_task (decoder->srcpad,
+ (GstTaskFunction) gst_v4l2_video_dec_loop, self,
+ (GDestroyNotify) gst_v4l2_video_dec_loop_stopped))
+ goto start_task_failed;
}
if (frame->input_buffer) {
@@ -542,6 +547,9 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
if (ret == GST_FLOW_FLUSHING) {
if (g_atomic_int_get (&self->processing) == FALSE)
ret = self->output_flow;
+ goto drop;
+ } else if (ret != GST_FLOW_OK) {
+ goto process_failed;
}
/* No need to keep input arround */
@@ -558,25 +566,36 @@ not_negotiated:
ret = GST_FLOW_NOT_NEGOTIATED;
goto drop;
}
-start_streaming_failed:
- {
- GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
- (_("Failed to re-enabled decoder.")),
- ("Could not re-enqueue and start streaming on decide."));
- return GST_FLOW_ERROR;
- }
activate_failed:
{
GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
(_("Failed to allocate required memory.")),
("Buffer pool activation failed"));
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ goto drop;
}
flushing:
{
ret = GST_FLOW_FLUSHING;
goto drop;
}
+
+start_task_failed:
+ {
+ GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+ (_("Failed to start decoding thread.")), (NULL));
+ g_atomic_int_set (&self->processing, FALSE);
+ ret = GST_FLOW_ERROR;
+ goto drop;
+ }
+process_failed:
+ {
+ GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+ (_("Failed to process frame.")),
+ ("Maybe be due to not enough memory or failing driver"));
+ ret = GST_FLOW_ERROR;
+ goto drop;
+ }
drop:
{
gst_video_decoder_drop_frame (decoder, frame);
@@ -686,16 +705,31 @@ static gboolean
gst_v4l2_video_dec_sink_event (GstVideoDecoder * decoder, GstEvent * event)
{
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
+ gboolean ret;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_START:
+ GST_DEBUG_OBJECT (self, "flush start");
gst_v4l2_object_unlock (self->v4l2output);
gst_v4l2_object_unlock (self->v4l2capture);
+ break;
default:
break;
}
- return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
+ ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_START:
+ /* The processing thread should stop now, wait for it */
+ gst_pad_stop_task (decoder->srcpad);
+ GST_DEBUG_OBJECT (self, "flush start done");
+ break;
+ default:
+ break;
+ }
+
+ return ret;
}
static GstStateChangeReturn
@@ -703,11 +737,13 @@ gst_v4l2_video_dec_change_state (GstElement * element,
GstStateChange transition)
{
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (element);
+ GstVideoDecoder *decoder = GST_VIDEO_DECODER (element);
if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
g_atomic_int_set (&self->active, FALSE);
gst_v4l2_object_unlock (self->v4l2output);
gst_v4l2_object_unlock (self->v4l2capture);
+ gst_pad_stop_task (decoder->srcpad);
}
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);