From: Nicolas Dufresne Date: Fri, 20 Mar 2020 16:37:41 +0000 (-0400) Subject: v4l2codecs: Wait for buffers to come back X-Git-Tag: 1.19.3~507^2~2119 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e70993bf4305652bb39e58fa0448c2ca78e617e9;p=platform%2Fupstream%2Fgstreamer.git 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. --- diff --git a/sys/v4l2codecs/gstv4l2codech264dec.c b/sys/v4l2codecs/gstv4l2codech264dec.c index db088a9..7ac430c 100644 --- a/sys/v4l2codecs/gstv4l2codech264dec.c +++ b/sys/v4l2codecs/gstv4l2codech264dec.c @@ -107,14 +107,9 @@ gst_v4l2_codec_h264_dec_close (GstVideoDecoder * decoder) return TRUE; } -static gboolean -gst_v4l2_codec_h264_dec_stop (GstVideoDecoder * decoder) +static void +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) { gst_v4l2_codec_allocator_detach (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_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) 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"); - if (self->sink_allocator) - gst_v4l2_codec_allocator_detach (self->sink_allocator); - - if (self->src_allocator) - gst_v4l2_codec_allocator_detach (self->src_allocator); + gst_v4l2_codec_h264_dec_reset_allocation (self); gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK); gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC); @@ -729,9 +731,11 @@ gst_v4l2_codec_h264_dec_end_picture (GstH264Decoder * decoder, flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->src_pool), &buffer, NULL); if (flow_ret != GST_FLOW_OK) { - /* FIXME our pool does not wait */ - GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE, - ("No more picture buffer available."), (NULL)); + if (flow_ret == GST_FLOW_FLUSHING) + GST_DEBUG_OBJECT (self, "Frame decoding aborted, we are flushing."); + else + GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE, + ("No more picture buffer available."), (NULL)); goto fail; } @@ -808,6 +812,16 @@ gst_v4l2_codec_h264_dec_decode_slice (GstH264Decoder * decoder, 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 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_v4l2_decoder_flush (self->decoder); + gst_v4l2_codec_h264_dec_set_flushing (self, FALSE); 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 gst_v4l2_codec_h264_dec_set_property (GObject * object, guint prop_id, 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, &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->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 = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_decide_allocation); 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 = GST_DEBUG_FUNCPTR (gst_v4l2_codec_h264_dec_new_sequence); diff --git a/sys/v4l2codecs/gstv4l2codecpool.c b/sys/v4l2codecs/gstv4l2codecpool.c index 69a01d4..9f6d696 100644 --- a/sys/v4l2codecs/gstv4l2codecpool.c +++ b/sys/v4l2codecs/gstv4l2codecpool.c @@ -60,9 +60,28 @@ gst_v4l2_codec_pool_acquire_buffer (GstBufferPool * pool, GstBuffer ** buffer, if (!buf) 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)) { - gst_atomic_queue_push (self->queue, buf); - return GST_FLOW_ERROR; + 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); + 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); diff --git a/sys/v4l2codecs/gstv4l2decoder.c b/sys/v4l2codecs/gstv4l2decoder.c index beb2e56..d23dd5a 100644 --- a/sys/v4l2codecs/gstv4l2decoder.c +++ b/sys/v4l2codecs/gstv4l2decoder.c @@ -688,11 +688,14 @@ gst_v4l2_request_free (GstV4l2Request * request) request->decoder = NULL; if (request->pending) { + GST_DEBUG_OBJECT (decoder, "Freeing pending request %p.", request); gst_v4l2_request_free (request); g_object_unref (decoder); return; } + GST_DEBUG_OBJECT (decoder, "Recycling request %p.", request); + ret = ioctl (request->fd, MEDIA_REQUEST_IOC_REINIT, NULL); if (ret < 0) { GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_REINIT failed: %s", @@ -711,6 +714,8 @@ gst_v4l2_request_queue (GstV4l2Request * request) { gint ret; + GST_DEBUG_OBJECT (request->decoder, "Queuing request %p.", request); + ret = ioctl (request->fd, MEDIA_REQUEST_IOC_QUEUE, NULL); if (ret < 0) { GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_QUEUE, failed: %s",