mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 14:26:43 +00:00
omxvideodec: Implement no-empty-eos-buffer hack, as in omxvideoenc.
Conflicts: omx/gstomxvideodec.c
This commit is contained in:
parent
4aa3fa8a0d
commit
7ca067be28
2 changed files with 119 additions and 85 deletions
|
@ -21,6 +21,7 @@
|
||||||
#ifndef __GST_OMX_H__
|
#ifndef __GST_OMX_H__
|
||||||
#define __GST_OMX_H__
|
#define __GST_OMX_H__
|
||||||
|
|
||||||
|
#include <gmodule.h>
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <OMX_Core.h>
|
#include <OMX_Core.h>
|
||||||
|
|
|
@ -498,6 +498,7 @@ done:
|
||||||
static void
|
static void
|
||||||
gst_omx_video_dec_loop (GstOMXVideoDec * self)
|
gst_omx_video_dec_loop (GstOMXVideoDec * self)
|
||||||
{
|
{
|
||||||
|
GstOMXVideoDecClass *klass;
|
||||||
GstOMXPort *port = self->out_port;
|
GstOMXPort *port = self->out_port;
|
||||||
GstOMXBuffer *buf = NULL;
|
GstOMXBuffer *buf = NULL;
|
||||||
GstVideoFrameState *frame;
|
GstVideoFrameState *frame;
|
||||||
|
@ -506,6 +507,8 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
|
||||||
GstClockTimeDiff deadline;
|
GstClockTimeDiff deadline;
|
||||||
gboolean is_eos;
|
gboolean is_eos;
|
||||||
|
|
||||||
|
klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
|
||||||
|
|
||||||
acq_return = gst_omx_port_acquire_buffer (port, &buf);
|
acq_return = gst_omx_port_acquire_buffer (port, &buf);
|
||||||
if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
|
if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
|
||||||
goto component_error;
|
goto component_error;
|
||||||
|
@ -566,107 +569,115 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
|
||||||
return;
|
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,
|
if (buf) {
|
||||||
buf->omx_buf->nTimeStamp);
|
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
|
/* This prevents a deadlock between the srcpad stream
|
||||||
* lock and the videocodec stream lock, if ::reset()
|
* lock and the videocodec stream lock, if ::reset()
|
||||||
* is called at the wrong time
|
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
|
if (gst_omx_port_is_flushing (self->out_port)) {
|
||||||
GST_ERROR_OBJECT (self, "No corresponding frame found");
|
GST_DEBUG_OBJECT (self, "Flushing");
|
||||||
|
|
||||||
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);
|
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);
|
GST_BASE_VIDEO_CODEC_STREAM_LOCK (self);
|
||||||
} else if (buf->omx_buf->nFilledLen > 0) {
|
frame = _find_nearest_frame (self, buf);
|
||||||
if (GST_BASE_VIDEO_CODEC (self)->state.bytes_per_picture == 0) {
|
|
||||||
/* FIXME: If the sinkpad caps change we have currently no way
|
is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS);
|
||||||
* to allocate new src buffers because basevideodecoder assumes
|
|
||||||
* that the caps on both pads are equivalent all the time
|
if (frame
|
||||||
*/
|
&& (deadline = gst_base_video_decoder_get_max_decode_time
|
||||||
|
(GST_BASE_VIDEO_DECODER (self), frame)) < 0) {
|
||||||
GST_WARNING_OBJECT (self,
|
GST_WARNING_OBJECT (self,
|
||||||
"Caps change pending and still have buffers for old caps -- dropping");
|
"Frame is too late, dropping (deadline %" GST_TIME_FORMAT ")",
|
||||||
} else
|
GST_TIME_ARGS (-deadline));
|
||||||
if (gst_base_video_decoder_alloc_src_frame (GST_BASE_VIDEO_DECODER
|
flow_ret =
|
||||||
(self), frame) == GST_FLOW_OK) {
|
gst_base_video_decoder_drop_frame (GST_BASE_VIDEO_DECODER (self),
|
||||||
/* FIXME: This currently happens because of a race condition too.
|
frame);
|
||||||
* We first need to reconfigure the output port and then the input
|
} else if (!frame && buf->omx_buf->nFilledLen > 0) {
|
||||||
* port if both need reconfiguration.
|
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);
|
GST_ERROR_OBJECT (self, "No corresponding frame found");
|
||||||
flow_ret =
|
|
||||||
gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER (self),
|
outbuf =
|
||||||
frame);
|
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);
|
gst_omx_port_release_buffer (self->out_port, buf);
|
||||||
goto invalid_buffer;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_eos || flow_ret == GST_FLOW_EOS) {
|
flow_ret = gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (self), outbuf);
|
||||||
g_mutex_lock (self->drain_lock);
|
} else if (buf->omx_buf->nFilledLen > 0) {
|
||||||
if (self->draining) {
|
if (GST_BASE_VIDEO_CODEC (self)->state.bytes_per_picture == 0) {
|
||||||
GST_DEBUG_OBJECT (self, "Drained");
|
/* FIXME: If the sinkpad caps change we have currently no way
|
||||||
self->draining = FALSE;
|
* to allocate new src buffers because basevideodecoder assumes
|
||||||
g_cond_broadcast (self->drain_cond);
|
* that the caps on both pads are equivalent all the time
|
||||||
} else if (flow_ret == GST_FLOW_OK) {
|
*/
|
||||||
GST_DEBUG_OBJECT (self, "Component signalled EOS");
|
GST_WARNING_OBJECT (self,
|
||||||
flow_ret = GST_FLOW_EOS;
|
"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);
|
||||||
}
|
}
|
||||||
g_mutex_unlock (self->drain_lock);
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_omx_port_release_buffer (port, buf);
|
||||||
|
|
||||||
|
self->downstream_flow_ret = flow_ret;
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
|
g_assert ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER));
|
||||||
|
GST_BASE_VIDEO_CODEC_STREAM_LOCK (self);
|
||||||
|
flow_ret = GST_FLOW_EOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_omx_port_release_buffer (port, buf);
|
|
||||||
|
|
||||||
self->downstream_flow_ret = flow_ret;
|
|
||||||
|
|
||||||
if (flow_ret != GST_FLOW_OK)
|
if (flow_ret != GST_FLOW_OK)
|
||||||
goto flow_error;
|
goto flow_error;
|
||||||
|
|
||||||
|
@ -1311,10 +1322,12 @@ static GstFlowReturn
|
||||||
gst_omx_video_dec_finish (GstBaseVideoDecoder * decoder)
|
gst_omx_video_dec_finish (GstBaseVideoDecoder * decoder)
|
||||||
{
|
{
|
||||||
GstOMXVideoDec *self;
|
GstOMXVideoDec *self;
|
||||||
|
GstOMXVideoDecClass *klass;
|
||||||
GstOMXBuffer *buf;
|
GstOMXBuffer *buf;
|
||||||
GstOMXAcquireBufferReturn acq_ret;
|
GstOMXAcquireBufferReturn acq_ret;
|
||||||
|
|
||||||
self = GST_OMX_VIDEO_DEC (decoder);
|
self = GST_OMX_VIDEO_DEC (decoder);
|
||||||
|
klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Sending EOS to the component");
|
GST_DEBUG_OBJECT (self, "Sending EOS to the component");
|
||||||
|
|
||||||
|
@ -1325,6 +1338,18 @@ gst_omx_video_dec_finish (GstBaseVideoDecoder * decoder)
|
||||||
}
|
}
|
||||||
self->eos = TRUE;
|
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
|
/* Make sure to release the base class stream lock, otherwise
|
||||||
* _loop() can't call _finish_frame() and we might block forever
|
* _loop() can't call _finish_frame() and we might block forever
|
||||||
* because no input buffers are released */
|
* because no input buffers are released */
|
||||||
|
@ -1355,11 +1380,14 @@ gst_omx_video_dec_finish (GstBaseVideoDecoder * decoder)
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_omx_video_dec_drain (GstOMXVideoDec * self)
|
gst_omx_video_dec_drain (GstOMXVideoDec * self)
|
||||||
{
|
{
|
||||||
|
GstOMXVideoDecClass *klass;
|
||||||
GstOMXBuffer *buf;
|
GstOMXBuffer *buf;
|
||||||
GstOMXAcquireBufferReturn acq_ret;
|
GstOMXAcquireBufferReturn acq_ret;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Draining component");
|
GST_DEBUG_OBJECT (self, "Draining component");
|
||||||
|
|
||||||
|
klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
|
||||||
|
|
||||||
if (!self->started) {
|
if (!self->started) {
|
||||||
GST_DEBUG_OBJECT (self, "Component not started yet");
|
GST_DEBUG_OBJECT (self, "Component not started yet");
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
@ -1372,6 +1400,11 @@ gst_omx_video_dec_drain (GstOMXVideoDec * self)
|
||||||
return GST_FLOW_OK;
|
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
|
/* Make sure to release the base class stream lock, otherwise
|
||||||
* _loop() can't call _finish_frame() and we might block forever
|
* _loop() can't call _finish_frame() and we might block forever
|
||||||
* because no input buffers are released */
|
* because no input buffers are released */
|
||||||
|
|
Loading…
Reference in a new issue