From 7ca067be2835390f1e80b8a84e2aca5963445f1f Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Mon, 30 Apr 2012 23:20:24 +0000 Subject: [PATCH] omxvideodec: Implement no-empty-eos-buffer hack, as in omxvideoenc. Conflicts: omx/gstomxvideodec.c --- omx/gstomx.h | 1 + omx/gstomxvideodec.c | 201 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 118 insertions(+), 84 deletions(-) diff --git a/omx/gstomx.h b/omx/gstomx.h index 41f6f0e..ed7283b 100644 --- a/omx/gstomx.h +++ b/omx/gstomx.h @@ -21,6 +21,7 @@ #ifndef __GST_OMX_H__ #define __GST_OMX_H__ +#include #include #include #include diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c index 4f729a1..9efe90a 100644 --- a/omx/gstomxvideodec.c +++ b/omx/gstomxvideodec.c @@ -498,6 +498,7 @@ done: static void gst_omx_video_dec_loop (GstOMXVideoDec * self) { + GstOMXVideoDecClass *klass; GstOMXPort *port = self->out_port; GstOMXBuffer *buf = NULL; GstVideoFrameState *frame; @@ -506,6 +507,8 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) GstClockTimeDiff deadline; gboolean is_eos; + klass = GST_OMX_VIDEO_DEC_GET_CLASS (self); + acq_return = gst_omx_port_acquire_buffer (port, &buf); if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) { goto component_error; @@ -566,106 +569,114 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) return; } - g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL); + g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK); - GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags, - buf->omx_buf->nTimeStamp); - - /* This prevents a deadlock between the srcpad stream - * lock and the videocodec stream lock, if ::reset() - * is called at the wrong time - */ - if (gst_omx_port_is_flushing (self->out_port)) { - GST_DEBUG_OBJECT (self, "Flushing"); - gst_omx_port_release_buffer (self->out_port, buf); - goto flushing; - } + if (buf) { + GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags, + buf->omx_buf->nTimeStamp); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); - frame = _find_nearest_frame (self, buf); - - is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS); - - if (frame - && (deadline = gst_base_video_decoder_get_max_decode_time - (GST_BASE_VIDEO_DECODER (self), frame)) < 0) { - GST_WARNING_OBJECT (self, - "Frame is too late, dropping (deadline %" GST_TIME_FORMAT ")", - GST_TIME_ARGS (-deadline)); - flow_ret = - gst_base_video_decoder_drop_frame (GST_BASE_VIDEO_DECODER (self), - frame); - } else if (!frame && buf->omx_buf->nFilledLen > 0) { - GstBuffer *outbuf; - - /* This sometimes happens at EOS or if the input is not properly framed, - * let's handle it gracefully by allocating a new buffer for the current - * caps and filling it + /* This prevents a deadlock between the srcpad stream + * lock and the videocodec stream lock, if ::reset() + * is called at the wrong time */ - - GST_ERROR_OBJECT (self, "No corresponding frame found"); - - outbuf = - gst_base_video_decoder_alloc_src_buffer (GST_BASE_VIDEO_DECODER (self)); - - if (!gst_omx_video_dec_fill_buffer (self, buf, outbuf)) { - gst_buffer_unref (outbuf); + if (gst_omx_port_is_flushing (self->out_port)) { + GST_DEBUG_OBJECT (self, "Flushing"); gst_omx_port_release_buffer (self->out_port, buf); - goto invalid_buffer; + goto flushing; } - flow_ret = gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (self), outbuf); - } else if (buf->omx_buf->nFilledLen > 0) { - if (GST_BASE_VIDEO_CODEC (self)->state.bytes_per_picture == 0) { - /* FIXME: If the sinkpad caps change we have currently no way - * to allocate new src buffers because basevideodecoder assumes - * that the caps on both pads are equivalent all the time - */ + GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + frame = _find_nearest_frame (self, buf); + + is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS); + + if (frame + && (deadline = gst_base_video_decoder_get_max_decode_time + (GST_BASE_VIDEO_DECODER (self), frame)) < 0) { GST_WARNING_OBJECT (self, - "Caps change pending and still have buffers for old caps -- dropping"); - } else - if (gst_base_video_decoder_alloc_src_frame (GST_BASE_VIDEO_DECODER - (self), frame) == GST_FLOW_OK) { - /* FIXME: This currently happens because of a race condition too. - * We first need to reconfigure the output port and then the input - * port if both need reconfiguration. + "Frame is too late, dropping (deadline %" GST_TIME_FORMAT ")", + GST_TIME_ARGS (-deadline)); + flow_ret = + gst_base_video_decoder_drop_frame (GST_BASE_VIDEO_DECODER (self), + frame); + } else if (!frame && buf->omx_buf->nFilledLen > 0) { + GstBuffer *outbuf; + + /* This sometimes happens at EOS or if the input is not properly framed, + * let's handle it gracefully by allocating a new buffer for the current + * caps and filling it */ - if (!gst_omx_video_dec_fill_buffer (self, buf, frame->src_buffer)) { - gst_buffer_replace (&frame->src_buffer, NULL); - flow_ret = - gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER (self), - frame); + + GST_ERROR_OBJECT (self, "No corresponding frame found"); + + outbuf = + gst_base_video_decoder_alloc_src_buffer (GST_BASE_VIDEO_DECODER + (self)); + + if (!gst_omx_video_dec_fill_buffer (self, buf, outbuf)) { + gst_buffer_unref (outbuf); gst_omx_port_release_buffer (self->out_port, buf); goto invalid_buffer; } + + flow_ret = gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (self), outbuf); + } else if (buf->omx_buf->nFilledLen > 0) { + if (GST_BASE_VIDEO_CODEC (self)->state.bytes_per_picture == 0) { + /* FIXME: If the sinkpad caps change we have currently no way + * to allocate new src buffers because basevideodecoder assumes + * that the caps on both pads are equivalent all the time + */ + GST_WARNING_OBJECT (self, + "Caps change pending and still have buffers for old caps -- dropping"); + } else + if (gst_base_video_decoder_alloc_src_frame (GST_BASE_VIDEO_DECODER + (self), frame) == GST_FLOW_OK) { + /* FIXME: This currently happens because of a race condition too. + * We first need to reconfigure the output port and then the input + * port if both need reconfiguration. + */ + if (!gst_omx_video_dec_fill_buffer (self, buf, frame->src_buffer)) { + gst_buffer_replace (&frame->src_buffer, NULL); + flow_ret = + gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER + (self), frame); + gst_omx_port_release_buffer (self->out_port, buf); + goto invalid_buffer; + } + } + flow_ret = + gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER (self), + frame); + } else if (frame != NULL) { + flow_ret = + gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER (self), + frame); } - flow_ret = - gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER (self), - frame); - } else if (frame != NULL) { - flow_ret = - gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER (self), - frame); - } - if (is_eos || flow_ret == GST_FLOW_EOS) { - g_mutex_lock (self->drain_lock); - if (self->draining) { - GST_DEBUG_OBJECT (self, "Drained"); - self->draining = FALSE; - g_cond_broadcast (self->drain_cond); - } else if (flow_ret == GST_FLOW_OK) { - GST_DEBUG_OBJECT (self, "Component signalled EOS"); - flow_ret = GST_FLOW_EOS; + if (is_eos || flow_ret == GST_FLOW_EOS) { + g_mutex_lock (self->drain_lock); + if (self->draining) { + GST_DEBUG_OBJECT (self, "Drained"); + self->draining = FALSE; + g_cond_broadcast (self->drain_cond); + } else if (flow_ret == GST_FLOW_OK) { + GST_DEBUG_OBJECT (self, "Component signalled EOS"); + flow_ret = GST_FLOW_EOS; + } + g_mutex_unlock (self->drain_lock); + } else { + GST_DEBUG_OBJECT (self, "Finished frame: %s", + gst_flow_get_name (flow_ret)); } - g_mutex_unlock (self->drain_lock); - } else { - GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret)); - } - gst_omx_port_release_buffer (port, buf); + gst_omx_port_release_buffer (port, buf); - self->downstream_flow_ret = flow_ret; + self->downstream_flow_ret = flow_ret; + } else { + g_assert ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)); + GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + flow_ret = GST_FLOW_EOS; + } if (flow_ret != GST_FLOW_OK) goto flow_error; @@ -1311,10 +1322,12 @@ static GstFlowReturn gst_omx_video_dec_finish (GstBaseVideoDecoder * decoder) { GstOMXVideoDec *self; + GstOMXVideoDecClass *klass; GstOMXBuffer *buf; GstOMXAcquireBufferReturn acq_ret; self = GST_OMX_VIDEO_DEC (decoder); + klass = GST_OMX_VIDEO_DEC_GET_CLASS (self); GST_DEBUG_OBJECT (self, "Sending EOS to the component"); @@ -1325,6 +1338,18 @@ gst_omx_video_dec_finish (GstBaseVideoDecoder * decoder) } self->eos = TRUE; + if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) { + GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers"); + + /* Insert a NULL into the queue to signal EOS */ + g_mutex_lock (self->out_port->port_lock); + g_queue_push_tail (self->out_port->pending_buffers, NULL); + g_cond_broadcast (self->out_port->port_cond); + g_mutex_unlock (self->out_port->port_lock); + + return GST_BASE_VIDEO_DECODER_FLOW_DROPPED; + } + /* Make sure to release the base class stream lock, otherwise * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ @@ -1355,11 +1380,14 @@ gst_omx_video_dec_finish (GstBaseVideoDecoder * decoder) static GstFlowReturn gst_omx_video_dec_drain (GstOMXVideoDec * self) { + GstOMXVideoDecClass *klass; GstOMXBuffer *buf; GstOMXAcquireBufferReturn acq_ret; GST_DEBUG_OBJECT (self, "Draining component"); + klass = GST_OMX_VIDEO_DEC_GET_CLASS (self); + if (!self->started) { GST_DEBUG_OBJECT (self, "Component not started yet"); return GST_FLOW_OK; @@ -1372,6 +1400,11 @@ gst_omx_video_dec_drain (GstOMXVideoDec * self) return GST_FLOW_OK; } + if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) { + GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers"); + return GST_FLOW_OK; + } + /* Make sure to release the base class stream lock, otherwise * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ -- 2.7.4