From 0d740a184e70415fc2818b51fe6b13e4af2e2b0f Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sun, 16 Feb 2020 14:53:08 -0500 Subject: [PATCH] v4l2codech264dec: Implement finish frame This enables the request to be processed by the HW (STREAMON) and to be pushed downstream for further processing. --- sys/v4l2codecs/gstv4l2codech264dec.c | 87 ++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/sys/v4l2codecs/gstv4l2codech264dec.c b/sys/v4l2codecs/gstv4l2codech264dec.c index 27309b35ba..732b06a9f2 100644 --- a/sys/v4l2codecs/gstv4l2codech264dec.c +++ b/sys/v4l2codecs/gstv4l2codech264dec.c @@ -110,6 +110,9 @@ 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); + if (self->sink_allocator) { gst_v4l2_codec_allocator_detach (self->sink_allocator); g_clear_object (&self->sink_allocator); @@ -142,6 +145,9 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder) 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_SRC); + if (!gst_v4l2_decoder_set_sink_fmt (self->decoder, V4L2_PIX_FMT_H264_SLICE, self->coded_width, self->coded_height)) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, @@ -174,7 +180,25 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder) self->output_state->caps = gst_video_info_to_caps (&self->output_state->info); - return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); + if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) { + if (!gst_v4l2_decoder_streamon (self->decoder, GST_PAD_SINK)) { + GST_ELEMENT_ERROR (self, RESOURCE, FAILED, + ("Could not enable the decoder driver."), + ("VIDIOC_STREAMON(SINK) failed: %s", g_strerror (errno))); + return FALSE; + } + + if (!gst_v4l2_decoder_streamon (self->decoder, GST_PAD_SRC)) { + GST_ELEMENT_ERROR (self, RESOURCE, FAILED, + ("Could not enable the decoder driver."), + ("VIDIOC_STREAMON(SRC) failed: %s", g_strerror (errno))); + return FALSE; + } + + return TRUE; + } + + return FALSE; } static gboolean @@ -440,6 +464,10 @@ gst_v4l2_codec_h264_dec_start_picture (GstH264Decoder * decoder, { GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder); + /* FIXME base class should not call us if negotiation failed */ + if (!self->sink_allocator) + return FALSE; + /* Ensure we have a bitstream to write into */ if (!self->bitstream) { self->bitstream = gst_v4l2_codec_allocator_alloc (self->sink_allocator); @@ -474,10 +502,57 @@ static GstFlowReturn gst_v4l2_codec_h264_dec_output_picture (GstH264Decoder * decoder, GstH264Picture * picture) { - /* We dequeue frames, until the system_frame_number matches, this ensure - * that the frame we want to output is actually decoded now */ - /* TODO implement */ - return GST_FLOW_OK; + GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder); + GstV4l2Request *request = gst_h264_picture_get_user_data (picture); + gint ret; + guint32 frame_num; + GstVideoCodecFrame *frame, *other_frame; + GstH264Picture *other_pic; + GstV4l2Request *other_request; + + if (gst_v4l2_request_is_done (request)) + goto finish_frame; + + ret = gst_v4l2_request_poll (request, GST_SECOND); + if (ret == 0) { + GST_ELEMENT_ERROR (self, STREAM, DECODE, + ("Decoding frame took too long"), (NULL)); + return GST_FLOW_ERROR; + } else if (ret < 0) { + GST_ELEMENT_ERROR (self, STREAM, DECODE, + ("Decoding request failed: %s", g_strerror (errno)), (NULL)); + return GST_FLOW_ERROR; + } + + while (TRUE) { + if (!gst_v4l2_decoder_dequeue_src (self->decoder, &frame_num)) { + GST_ELEMENT_ERROR (self, STREAM, DECODE, + ("Decoder did not produce a frame"), (NULL)); + return GST_FLOW_ERROR; + } + + if (frame_num == picture->system_frame_number) + break; + + other_frame = gst_video_decoder_get_frame (GST_VIDEO_DECODER (self), + frame_num); + g_return_val_if_fail (other_frame, GST_FLOW_ERROR); + + other_pic = gst_video_codec_frame_get_user_data (other_frame); + other_request = gst_h264_picture_get_user_data (other_pic); + gst_v4l2_request_set_done (other_request); + gst_video_codec_frame_unref (other_frame); + } + +finish_frame: + gst_v4l2_request_set_done (request); + frame = gst_video_decoder_get_frame (GST_VIDEO_DECODER (self), + picture->system_frame_number); + + g_return_val_if_fail (frame, GST_FLOW_ERROR); + + gst_h264_picture_set_user_data (picture, NULL, NULL); + return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); } static void @@ -570,7 +645,9 @@ gst_v4l2_codec_h264_dec_end_picture (GstH264Decoder * decoder, frame = gst_video_decoder_get_frame (GST_VIDEO_DECODER (self), picture->system_frame_number); g_return_val_if_fail (frame, FALSE); + g_warn_if_fail (frame->output_buffer == NULL); frame->output_buffer = buffer; + gst_video_codec_frame_unref (frame); if (!gst_v4l2_decoder_queue_src_buffer (self->decoder, buffer, picture->system_frame_number)) {