From 21652a8e5228d213e240023979b03f3ea1d67adc Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 12 Mar 2020 16:15:40 -0400 Subject: [PATCH] v4l2h264dec: Copy frames when GstVideoMeta is not supported In some case, when downstream does not support GstVideoMeta, we need to normalize the stride and offset of the buffer so that downstream can render properly with a GstVideoMeta. This code is not called when GstVideoMeta is supported downstream. --- sys/v4l2codecs/gstv4l2codech264dec.c | 74 ++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/sys/v4l2codecs/gstv4l2codech264dec.c b/sys/v4l2codecs/gstv4l2codech264dec.c index 73071f7..7422aa8 100644 --- a/sys/v4l2codecs/gstv4l2codech264dec.c +++ b/sys/v4l2codecs/gstv4l2codech264dec.c @@ -66,6 +66,7 @@ struct _GstV4l2CodecH264Dec gint min_pool_size; gboolean has_videometa; gboolean need_negotiation; + gboolean copy_frames; struct v4l2_ctrl_h264_sps sps; struct v4l2_ctrl_h264_pps pps; @@ -462,6 +463,27 @@ gst_v4l2_codec_h264_dec_new_sequence (GstH264Decoder * decoder, } } + /* Check if we can zero-copy buffers */ + if (!self->has_videometa) { + GstVideoInfo ref_vinfo; + gint i; + + gst_video_info_set_format (&ref_vinfo, GST_VIDEO_INFO_FORMAT (&self->vinfo), + self->display_width, self->display_height); + + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->vinfo); i++) { + if (self->vinfo.stride[i] != ref_vinfo.stride[i] || + self->vinfo.offset[i] != ref_vinfo.offset[i]) { + GST_WARNING_OBJECT (self, + "GstVideoMeta support required, copying frames."); + self->copy_frames = TRUE; + break; + } + } + } else { + self->copy_frames = FALSE; + } + return TRUE; } @@ -505,6 +527,54 @@ gst_v4l2_codec_h264_dec_start_picture (GstH264Decoder * decoder, return TRUE; } +static gboolean +gst_v4l2_codec_h264_dec_copy_output_buffer (GstV4l2CodecH264Dec * self, + GstVideoCodecFrame * codec_frame) +{ + GstVideoFrame src_frame; + GstVideoFrame dest_frame; + GstVideoInfo dest_vinfo; + GstBuffer *buffer; + + gst_video_info_set_format (&dest_vinfo, GST_VIDEO_INFO_FORMAT (&self->vinfo), + self->display_width, self->display_height); + + buffer = gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self)); + if (!buffer) + goto fail; + + if (!gst_video_frame_map (&src_frame, &self->vinfo, + codec_frame->output_buffer, GST_MAP_READ)) + goto fail; + + if (!gst_video_frame_map (&dest_frame, &dest_vinfo, buffer, GST_MAP_WRITE)) { + gst_video_frame_unmap (&dest_frame); + goto fail; + } + + /* gst_video_frame_copy can crop this, but does not know, so let make it + * think it's all right */ + GST_VIDEO_INFO_WIDTH (&src_frame.info) = self->display_width; + GST_VIDEO_INFO_HEIGHT (&src_frame.info) = self->display_height; + + if (!gst_video_frame_copy (&dest_frame, &src_frame)) { + gst_video_frame_unmap (&src_frame); + gst_video_frame_unmap (&dest_frame); + goto fail; + } + + gst_video_frame_unmap (&src_frame); + gst_video_frame_unmap (&dest_frame); + gst_buffer_replace (&codec_frame->output_buffer, buffer); + gst_buffer_unref (buffer); + + return TRUE; + +fail: + GST_ERROR_OBJECT (self, "Failed copy output buffer."); + return FALSE; +} + static GstFlowReturn gst_v4l2_codec_h264_dec_output_picture (GstH264Decoder * decoder, GstH264Picture * picture) @@ -561,6 +631,10 @@ finish_frame: /* Hold on reference buffers for the rest of the picture lifetime */ gst_h264_picture_set_user_data (picture, gst_buffer_ref (frame->output_buffer), (GDestroyNotify) gst_buffer_unref); + + if (self->copy_frames) + gst_v4l2_codec_h264_dec_copy_output_buffer (self, frame); + return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); } -- 2.7.4