v4l2codecs: Wait for buffers to come back

This code add required mechanism to try and allocate (not implemented yet)
otherwise wait for more buffers. This also comes with mechanism to terminate
the wait on flush or PAUSED_TO_READY transitions.
This commit is contained in:
Nicolas Dufresne 2020-03-20 12:37:41 -04:00
parent 09a9ffcda6
commit e70993bf43
3 changed files with 89 additions and 17 deletions

View file

@ -107,14 +107,9 @@ gst_v4l2_codec_h264_dec_close (GstVideoDecoder * decoder)
return TRUE; return TRUE;
} }
static gboolean static void
gst_v4l2_codec_h264_dec_stop (GstVideoDecoder * decoder) gst_v4l2_codec_h264_dec_reset_allocation (GstV4l2CodecH264Dec * self)
{ {
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
if (self->sink_allocator) { if (self->sink_allocator) {
gst_v4l2_codec_allocator_detach (self->sink_allocator); gst_v4l2_codec_allocator_detach (self->sink_allocator);
g_clear_object (&self->sink_allocator); g_clear_object (&self->sink_allocator);
@ -125,6 +120,17 @@ gst_v4l2_codec_h264_dec_stop (GstVideoDecoder * decoder)
g_clear_object (&self->src_allocator); g_clear_object (&self->src_allocator);
g_clear_object (&self->src_pool); g_clear_object (&self->src_pool);
} }
}
static gboolean
gst_v4l2_codec_h264_dec_stop (GstVideoDecoder * decoder)
{
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
gst_v4l2_codec_h264_dec_reset_allocation (self);
if (self->output_state) if (self->output_state)
gst_video_codec_state_unref (self->output_state); gst_video_codec_state_unref (self->output_state);
@ -156,11 +162,7 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder)
GST_DEBUG_OBJECT (self, "Negotiate"); GST_DEBUG_OBJECT (self, "Negotiate");
if (self->sink_allocator) gst_v4l2_codec_h264_dec_reset_allocation (self);
gst_v4l2_codec_allocator_detach (self->sink_allocator);
if (self->src_allocator)
gst_v4l2_codec_allocator_detach (self->src_allocator);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK); gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC); gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
@ -729,7 +731,9 @@ gst_v4l2_codec_h264_dec_end_picture (GstH264Decoder * decoder,
flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->src_pool), flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->src_pool),
&buffer, NULL); &buffer, NULL);
if (flow_ret != GST_FLOW_OK) { if (flow_ret != GST_FLOW_OK) {
/* FIXME our pool does not wait */ if (flow_ret == GST_FLOW_FLUSHING)
GST_DEBUG_OBJECT (self, "Frame decoding aborted, we are flushing.");
else
GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE, GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE,
("No more picture buffer available."), (NULL)); ("No more picture buffer available."), (NULL));
goto fail; goto fail;
@ -808,6 +812,16 @@ gst_v4l2_codec_h264_dec_decode_slice (GstH264Decoder * decoder,
return TRUE; return TRUE;
} }
static void
gst_v4l2_codec_h264_dec_set_flushing (GstV4l2CodecH264Dec * self,
gboolean flushing)
{
if (self->sink_allocator)
gst_v4l2_codec_allocator_set_flushing (self->sink_allocator, flushing);
if (self->src_allocator)
gst_v4l2_codec_allocator_set_flushing (self->src_allocator, flushing);
}
static gboolean static gboolean
gst_v4l2_codec_h264_dec_flush (GstVideoDecoder * decoder) gst_v4l2_codec_h264_dec_flush (GstVideoDecoder * decoder)
{ {
@ -816,10 +830,40 @@ gst_v4l2_codec_h264_dec_flush (GstVideoDecoder * decoder)
GST_DEBUG_OBJECT (self, "Flushing decoder state."); GST_DEBUG_OBJECT (self, "Flushing decoder state.");
gst_v4l2_decoder_flush (self->decoder); gst_v4l2_decoder_flush (self->decoder);
gst_v4l2_codec_h264_dec_set_flushing (self, FALSE);
return GST_VIDEO_DECODER_CLASS (parent_class)->flush (decoder); return GST_VIDEO_DECODER_CLASS (parent_class)->flush (decoder);
} }
static gboolean
gst_v4l2_codec_h264_dec_sink_event (GstVideoDecoder * decoder, GstEvent * event)
{
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_START:
GST_DEBUG_OBJECT (self, "flush start");
gst_v4l2_codec_h264_dec_set_flushing (self, TRUE);
break;
default:
break;
}
return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
}
static GstStateChangeReturn
gst_v4l2_codec_h264_dec_change_state (GstElement * element,
GstStateChange transition)
{
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (element);
if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
gst_v4l2_codec_h264_dec_set_flushing (self, TRUE);
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
}
static void static void
gst_v4l2_codec_h264_dec_set_property (GObject * object, guint prop_id, gst_v4l2_codec_h264_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec) const GValue * value, GParamSpec * pspec)
@ -900,6 +944,8 @@ gst_v4l2_codec_h264_dec_subclass_init (GstV4l2CodecH264DecClass * klass,
gst_element_class_add_static_pad_template (element_class, &sink_template); gst_element_class_add_static_pad_template (element_class, &sink_template);
gst_element_class_add_static_pad_template (element_class, &src_template); gst_element_class_add_static_pad_template (element_class, &src_template);
element_class->change_state =
GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_change_state);
decoder_class->open = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_open); decoder_class->open = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_open);
decoder_class->close = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_close); decoder_class->close = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_close);
@ -909,6 +955,8 @@ gst_v4l2_codec_h264_dec_subclass_init (GstV4l2CodecH264DecClass * klass,
decoder_class->decide_allocation = decoder_class->decide_allocation =
GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_decide_allocation); GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_decide_allocation);
decoder_class->flush = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_flush); decoder_class->flush = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_flush);
decoder_class->sink_event =
GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_sink_event);
h264decoder_class->new_sequence = h264decoder_class->new_sequence =
GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_new_sequence); GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_new_sequence);

View file

@ -60,9 +60,28 @@ gst_v4l2_codec_pool_acquire_buffer (GstBufferPool * pool, GstBuffer ** buffer,
if (!buf) if (!buf)
buf = gst_v4l2_codec_pool_create_empty_buffer (); buf = gst_v4l2_codec_pool_create_empty_buffer ();
/* First, just try and obtain a buffer. */
if (!gst_v4l2_codec_allocator_prepare_buffer (self->allocator, buf)) { if (!gst_v4l2_codec_allocator_prepare_buffer (self->allocator, buf)) {
GstFlowReturn flow_ret = GST_FLOW_OK;
/* If none were available, try and allocate one. */
if (!gst_v4l2_codec_allocator_create_buffer (self->allocator)) {
/* Otherwise, wait if this is allowed. */
if (params && params->flags & GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT) {
flow_ret = GST_FLOW_EOS;
} else {
if (!gst_v4l2_codec_allocator_wait_for_buffer (self->allocator))
flow_ret = GST_FLOW_FLUSHING;
}
}
if (flow_ret != GST_FLOW_OK) {
gst_atomic_queue_push (self->queue, buf); gst_atomic_queue_push (self->queue, buf);
return GST_FLOW_ERROR; return flow_ret;
}
/* Finally, pop the buffer we created or waited for. */
gst_v4l2_codec_allocator_prepare_buffer (self->allocator, buf);
} }
vmeta = gst_buffer_get_video_meta (buf); vmeta = gst_buffer_get_video_meta (buf);

View file

@ -688,11 +688,14 @@ gst_v4l2_request_free (GstV4l2Request * request)
request->decoder = NULL; request->decoder = NULL;
if (request->pending) { if (request->pending) {
GST_DEBUG_OBJECT (decoder, "Freeing pending request %p.", request);
gst_v4l2_request_free (request); gst_v4l2_request_free (request);
g_object_unref (decoder); g_object_unref (decoder);
return; return;
} }
GST_DEBUG_OBJECT (decoder, "Recycling request %p.", request);
ret = ioctl (request->fd, MEDIA_REQUEST_IOC_REINIT, NULL); ret = ioctl (request->fd, MEDIA_REQUEST_IOC_REINIT, NULL);
if (ret < 0) { if (ret < 0) {
GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_REINIT failed: %s", GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_REINIT failed: %s",
@ -711,6 +714,8 @@ gst_v4l2_request_queue (GstV4l2Request * request)
{ {
gint ret; gint ret;
GST_DEBUG_OBJECT (request->decoder, "Queuing request %p.", request);
ret = ioctl (request->fd, MEDIA_REQUEST_IOC_QUEUE, NULL); ret = ioctl (request->fd, MEDIA_REQUEST_IOC_QUEUE, NULL);
if (ret < 0) { if (ret < 0) {
GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_QUEUE, failed: %s", GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_QUEUE, failed: %s",