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.
This commit is contained in:
Nicolas Dufresne 2020-03-12 16:15:40 -04:00
parent 3c2d25eebf
commit 21652a8e52

View file

@ -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);
}