v4l2codecs: Allow output caps to be updated

This change allow output caps to be updated even though we stay in
streaming state. This is needed so that any upstream updated to fields
like framerate, hdr data, etc. can result in a downstream caps event
being pushed.

Previously, any of these changes was being ignored and the downstream
caps would not reflect it.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3328>
This commit is contained in:
Nicolas Dufresne 2022-11-14 15:53:00 -05:00 committed by GStreamer Marge Bot
parent 0e4c520cf3
commit d3c5fc815e
5 changed files with 154 additions and 55 deletions

View file

@ -75,7 +75,7 @@ struct _GstV4l2CodecH264Dec
GstV4l2CodecPool *src_pool;
gint min_pool_size;
gboolean has_videometa;
gboolean need_negotiation;
gboolean streaming;
gboolean interlaced;
gboolean need_sequence;
gboolean copy_frames;
@ -233,6 +233,16 @@ gst_v4l2_codec_h264_dec_close (GstVideoDecoder * decoder)
return TRUE;
}
static void
gst_v4l2_codec_h264_dec_streamoff (GstV4l2CodecH264Dec * self)
{
if (self->streaming) {
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
self->streaming = FALSE;
}
}
static void
gst_v4l2_codec_h264_dec_reset_allocation (GstV4l2CodecH264Dec * self)
{
@ -253,9 +263,7 @@ 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_streamoff (self);
gst_v4l2_codec_h264_dec_reset_allocation (self);
if (self->output_state)
@ -314,15 +322,11 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder)
GstCaps *filter, *caps;
/* Ignore downstream renegotiation request. */
if (!self->need_negotiation)
return TRUE;
self->need_negotiation = FALSE;
if (self->streaming)
goto done;
GST_DEBUG_OBJECT (self, "Negotiate");
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 (!gst_v4l2_decoder_set_sink_fmt (self->decoder, V4L2_PIX_FMT_H264_SLICE,
@ -366,6 +370,7 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder)
if (self->output_state)
gst_video_codec_state_unref (self->output_state);
done:
self->output_state =
gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
self->vinfo.finfo->format, self->display_width,
@ -377,6 +382,9 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder)
self->output_state->caps = gst_video_info_to_caps (&self->output_state->info);
if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) {
if (self->streaming)
return TRUE;
if (!gst_v4l2_decoder_streamon (self->decoder, GST_PAD_SINK)) {
GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
("Could not enable the decoder driver."),
@ -391,6 +399,8 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder)
return FALSE;
}
self->streaming = TRUE;
return TRUE;
}
@ -404,6 +414,11 @@ gst_v4l2_codec_h264_dec_decide_allocation (GstVideoDecoder * decoder,
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
guint min = 0, num_bitstream;
/* If we are streaming here, then it means there is nothing allocation
* related in the new state and allocation can be ignored */
if (self->streaming)
return TRUE;
self->has_videometa = gst_query_find_allocation_meta (query,
GST_VIDEO_META_API_TYPE, NULL);
@ -894,7 +909,7 @@ gst_v4l2_codec_h264_dec_new_sequence (GstH264Decoder * decoder,
self->need_sequence = TRUE;
if (negotiation_needed) {
self->need_negotiation = TRUE;
gst_v4l2_codec_h264_dec_streamoff (self);
if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
return GST_FLOW_NOT_NEGOTIATED;
@ -1046,6 +1061,13 @@ gst_v4l2_codec_h264_dec_output_picture (GstH264Decoder * decoder,
GstV4l2Request *request = gst_h264_picture_get_user_data (picture);
gint ret;
if (picture->discont_state) {
if (!gst_video_decoder_negotiate (vdec)) {
GST_ERROR_OBJECT (vdec, "Could not re-negotiate with updated state");
return FALSE;
}
}
GST_DEBUG_OBJECT (self, "Output picture %u", picture->system_frame_number);
ret = gst_v4l2_request_set_done (request);

View file

@ -76,7 +76,7 @@ struct _GstV4l2CodecH265Dec
GstV4l2CodecPool *src_pool;
gint min_pool_size;
gboolean has_videometa;
gboolean need_negotiation;
gboolean streaming;
gboolean copy_frames;
gboolean need_sequence;
@ -267,6 +267,16 @@ gst_v4l2_codec_h265_dec_close (GstVideoDecoder * decoder)
return TRUE;
}
static void
gst_v4l2_codec_h265_dec_streamoff (GstV4l2CodecH265Dec * self)
{
if (self->streaming) {
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
self->streaming = FALSE;
}
}
static void
gst_v4l2_codec_h265_dec_reset_allocation (GstV4l2CodecH265Dec * self)
{
@ -287,9 +297,7 @@ gst_v4l2_codec_h265_dec_stop (GstVideoDecoder * decoder)
{
GstV4l2CodecH265Dec *self = GST_V4L2_CODEC_H265_DEC (decoder);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
gst_v4l2_codec_h265_dec_streamoff (self);
gst_v4l2_codec_h265_dec_reset_allocation (self);
if (self->output_state)
@ -348,15 +356,11 @@ gst_v4l2_codec_h265_dec_negotiate (GstVideoDecoder * decoder)
GstCaps *filter, *caps;
/* Ignore downstream renegotiation request. */
if (!self->need_negotiation)
return TRUE;
self->need_negotiation = FALSE;
if (self->streaming)
goto done;
GST_DEBUG_OBJECT (self, "Negotiate");
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
gst_v4l2_codec_h265_dec_reset_allocation (self);
if (!gst_v4l2_decoder_set_sink_fmt (self->decoder, V4L2_PIX_FMT_HEVC_SLICE,
@ -397,6 +401,7 @@ gst_v4l2_codec_h265_dec_negotiate (GstVideoDecoder * decoder)
}
gst_caps_unref (caps);
done:
if (self->output_state)
gst_video_codec_state_unref (self->output_state);
@ -408,6 +413,9 @@ gst_v4l2_codec_h265_dec_negotiate (GstVideoDecoder * decoder)
self->output_state->caps = gst_video_info_to_caps (&self->output_state->info);
if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) {
if (self->streaming)
return TRUE;
if (!gst_v4l2_decoder_streamon (self->decoder, GST_PAD_SINK)) {
GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
("Could not enable the decoder driver."),
@ -422,6 +430,8 @@ gst_v4l2_codec_h265_dec_negotiate (GstVideoDecoder * decoder)
return FALSE;
}
self->streaming = TRUE;
return TRUE;
}
@ -435,6 +445,9 @@ gst_v4l2_codec_h265_dec_decide_allocation (GstVideoDecoder * decoder,
GstV4l2CodecH265Dec *self = GST_V4L2_CODEC_H265_DEC (decoder);
guint min = 0;
if (self->streaming)
return TRUE;
self->has_videometa = gst_query_find_allocation_meta (query,
GST_VIDEO_META_API_TYPE, NULL);
@ -902,7 +915,7 @@ gst_v4l2_codec_h265_dec_new_sequence (GstH265Decoder * decoder,
gst_v4l2_codec_h265_dec_fill_sequence (self, sps);
if (negotiation_needed) {
self->need_negotiation = TRUE;
gst_v4l2_codec_h265_dec_streamoff (self);
if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
return GST_FLOW_NOT_NEGOTIATED;
@ -1174,9 +1187,17 @@ gst_v4l2_codec_h265_dec_output_picture (GstH265Decoder * decoder,
GstVideoCodecFrame * frame, GstH265Picture * picture)
{
GstV4l2CodecH265Dec *self = GST_V4L2_CODEC_H265_DEC (decoder);
GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
GstV4l2Request *request = gst_h265_picture_get_user_data (picture);
gint ret;
if (picture->discont_state) {
if (!gst_video_decoder_negotiate (vdec)) {
GST_ERROR_OBJECT (vdec, "Could not re-negotiate with updated state");
return FALSE;
}
}
GST_DEBUG_OBJECT (self, "Output picture %u", picture->system_frame_number);
ret = gst_v4l2_request_set_done (request);
@ -1207,10 +1228,10 @@ gst_v4l2_codec_h265_dec_output_picture (GstH265Decoder * decoder,
gst_h265_picture_unref (picture);
return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
return gst_video_decoder_finish_frame (vdec, frame);
error:
gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
gst_video_decoder_drop_frame (vdec, frame);
gst_h265_picture_unref (picture);
return GST_FLOW_ERROR;

View file

@ -84,7 +84,7 @@ struct _GstV4l2CodecMpeg2Dec
GstV4l2CodecPool *src_pool;
gint min_pool_size;
gboolean has_videometa;
gboolean need_negotiation;
gboolean streaming;
GstMemory *bitstream;
GstMapInfo bitstream_map;
@ -149,6 +149,16 @@ gst_v4l2_codec_mpeg2_dec_close (GstVideoDecoder * decoder)
return gst_v4l2_decoder_close (self->decoder);
}
static void
gst_v4l2_codec_mpeg2_dec_streamoff (GstV4l2CodecMpeg2Dec * self)
{
if (self->streaming) {
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
self->streaming = FALSE;
}
}
static void
gst_v4l2_codec_mpeg2_dec_reset_allocation (GstV4l2CodecMpeg2Dec * self)
{
@ -169,9 +179,7 @@ gst_v4l2_codec_mpeg2_dec_stop (GstVideoDecoder * decoder)
{
GstV4l2CodecMpeg2Dec *self = GST_V4L2_CODEC_MPEG2_DEC (decoder);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
gst_v4l2_codec_mpeg2_dec_streamoff (self);
gst_v4l2_codec_mpeg2_dec_reset_allocation (self);
if (self->output_state)
@ -236,15 +244,11 @@ gst_v4l2_codec_mpeg2_dec_negotiate (GstVideoDecoder * decoder)
GstCaps *filter, *caps;
/* Ignore downstream renegotiation request. */
if (!self->need_negotiation)
return TRUE;
self->need_negotiation = FALSE;
if (self->streaming)
goto done;
GST_DEBUG_OBJECT (self, "Negotiate");
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
gst_v4l2_codec_mpeg2_dec_reset_allocation (self);
if (!gst_v4l2_decoder_set_sink_fmt (self->decoder, V4L2_PIX_FMT_MPEG2_SLICE,
@ -285,6 +289,7 @@ gst_v4l2_codec_mpeg2_dec_negotiate (GstVideoDecoder * decoder)
}
gst_caps_unref (caps);
done:
if (self->output_state)
gst_video_codec_state_unref (self->output_state);
@ -300,6 +305,9 @@ gst_v4l2_codec_mpeg2_dec_negotiate (GstVideoDecoder * decoder)
self->output_state->caps = gst_video_info_to_caps (&self->output_state->info);
if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) {
if (self->streaming)
return TRUE;
if (!gst_v4l2_decoder_streamon (self->decoder, GST_PAD_SINK)) {
GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
("Could not enable the decoder driver."),
@ -314,6 +322,8 @@ gst_v4l2_codec_mpeg2_dec_negotiate (GstVideoDecoder * decoder)
return FALSE;
}
self->streaming = TRUE;
return TRUE;
}
@ -418,7 +428,7 @@ gst_v4l2_codec_mpeg2_dec_new_sequence (GstMpeg2Decoder * decoder,
GST_INFO_OBJECT (self, "Profile change %d -> %d",
self->profile, mpeg_profile);
self->profile = mpeg_profile;
self->need_negotiation = TRUE;
self->streaming = TRUE;
}
if (self->vinfo.finfo->format == GST_VIDEO_FORMAT_UNKNOWN)
@ -449,7 +459,7 @@ gst_v4l2_codec_mpeg2_dec_new_sequence (GstMpeg2Decoder * decoder,
/* *INDENT-ON* */
if (negotiation_needed) {
self->need_negotiation = TRUE;
gst_v4l2_codec_mpeg2_dec_streamoff (self);
if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
return GST_FLOW_ERROR;
@ -672,6 +682,13 @@ gst_v4l2_codec_mpeg2_dec_output_picture (GstMpeg2Decoder * decoder,
GstV4l2Request *request = gst_mpeg2_picture_get_user_data (picture);
gint ret;
if (picture->discont_state) {
if (!gst_video_decoder_negotiate (vdec)) {
GST_ERROR_OBJECT (vdec, "Could not re-negotiate with updated state");
return FALSE;
}
}
GST_DEBUG_OBJECT (self, "Output picture %u", picture->system_frame_number);
ret = gst_v4l2_request_set_done (request);

View file

@ -73,7 +73,7 @@ struct _GstV4l2CodecVp8Dec
GstV4l2CodecPool *src_pool;
gint min_pool_size;
gboolean has_videometa;
gboolean need_negotiation;
gboolean streaming;
gboolean copy_frames;
struct v4l2_ctrl_vp8_frame frame_header;
@ -136,6 +136,16 @@ gst_v4l2_codec_vp8_dec_close (GstVideoDecoder * decoder)
return TRUE;
}
static void
gst_v4l2_codec_vp8_dec_streamoff (GstV4l2CodecVp8Dec * self)
{
if (self->streaming) {
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
self->streaming = FALSE;
}
}
static void
gst_v4l2_codec_vp8_dec_reset_allocation (GstV4l2CodecVp8Dec * self)
{
@ -156,9 +166,7 @@ gst_v4l2_codec_vp8_dec_stop (GstVideoDecoder * decoder)
{
GstV4l2CodecVp8Dec *self = GST_V4L2_CODEC_VP8_DEC (decoder);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
gst_v4l2_codec_vp8_dec_streamoff (self);
gst_v4l2_codec_vp8_dec_reset_allocation (self);
if (self->output_state)
@ -185,15 +193,11 @@ gst_v4l2_codec_vp8_dec_negotiate (GstVideoDecoder * decoder)
GstCaps *filter, *caps;
/* Ignore downstream renegotiation request. */
if (!self->need_negotiation)
return TRUE;
self->need_negotiation = FALSE;
if (self->streaming)
goto done;
GST_DEBUG_OBJECT (self, "Negotiate");
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
gst_v4l2_codec_vp8_dec_reset_allocation (self);
if (!gst_v4l2_decoder_set_sink_fmt (self->decoder, V4L2_PIX_FMT_VP8_FRAME,
@ -234,6 +238,7 @@ gst_v4l2_codec_vp8_dec_negotiate (GstVideoDecoder * decoder)
}
gst_caps_unref (caps);
done:
if (self->output_state)
gst_video_codec_state_unref (self->output_state);
@ -245,6 +250,9 @@ gst_v4l2_codec_vp8_dec_negotiate (GstVideoDecoder * decoder)
self->output_state->caps = gst_video_info_to_caps (&self->output_state->info);
if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) {
if (self->streaming)
return TRUE;
if (!gst_v4l2_decoder_streamon (self->decoder, GST_PAD_SINK)) {
GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
("Could not enable the decoder driver."),
@ -259,6 +267,8 @@ gst_v4l2_codec_vp8_dec_negotiate (GstVideoDecoder * decoder)
return FALSE;
}
self->streaming = TRUE;
return TRUE;
}
@ -273,6 +283,9 @@ gst_v4l2_codec_vp8_dec_decide_allocation (GstVideoDecoder * decoder,
guint min = 0;
guint num_bitstream;
if (self->streaming)
return TRUE;
self->has_videometa = gst_query_find_allocation_meta (query,
GST_VIDEO_META_API_TYPE, NULL);
@ -470,7 +483,7 @@ gst_v4l2_codec_vp8_dec_new_sequence (GstVp8Decoder * decoder,
gst_v4l2_codec_vp8_dec_fill_frame_header (self, frame_hdr);
if (negotiation_needed) {
self->need_negotiation = TRUE;
gst_v4l2_codec_vp8_dec_streamoff (self);
if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
return GST_FLOW_NOT_NEGOTIATED;
@ -710,6 +723,13 @@ gst_v4l2_codec_vp8_dec_output_picture (GstVp8Decoder * decoder,
GstV4l2Request *request = gst_vp8_picture_get_user_data (picture);
gint ret;
if (picture->discont_state) {
if (!gst_video_decoder_negotiate (vdec)) {
GST_ERROR_OBJECT (vdec, "Could not re-negotiate with updated state");
return FALSE;
}
}
GST_DEBUG_OBJECT (self, "Output picture %u", picture->system_frame_number);
ret = gst_v4l2_request_set_done (request);

View file

@ -73,7 +73,7 @@ struct _GstV4l2CodecVp9Dec
GstV4l2CodecAllocator *src_allocator;
GstV4l2CodecPool *src_pool;
gboolean has_videometa;
gboolean need_negotiation;
gboolean streaming;
gboolean copy_frames;
struct v4l2_ctrl_vp9_frame v4l2_vp9_frame;
@ -401,6 +401,16 @@ gst_v4l2_codec_vp9_dec_close (GstVideoDecoder * decoder)
return TRUE;
}
static void
gst_v4l2_codec_vp9_dec_streamoff (GstV4l2CodecVp9Dec * self)
{
if (self->streaming) {
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
self->streaming = FALSE;
}
}
static void
gst_v4l2_codec_vp9_dec_reset_allocation (GstV4l2CodecVp9Dec * self)
{
@ -451,15 +461,11 @@ gst_v4l2_codec_vp9_dec_negotiate (GstVideoDecoder * decoder)
GstCaps *filter, *caps;
/* Ignore downstream renegotiation request. */
if (!self->need_negotiation)
return TRUE;
self->need_negotiation = FALSE;
if (self->streaming)
goto done;
GST_DEBUG_OBJECT (self, "Negotiate");
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SINK);
gst_v4l2_decoder_streamoff (self->decoder, GST_PAD_SRC);
gst_v4l2_codec_vp9_dec_reset_allocation (self);
if (!gst_v4l2_decoder_set_sink_fmt (self->decoder, V4L2_PIX_FMT_VP9_FRAME,
@ -499,6 +505,7 @@ gst_v4l2_codec_vp9_dec_negotiate (GstVideoDecoder * decoder)
}
gst_caps_unref (caps);
done:
if (self->output_state)
gst_video_codec_state_unref (self->output_state);
@ -510,6 +517,9 @@ gst_v4l2_codec_vp9_dec_negotiate (GstVideoDecoder * decoder)
self->output_state->caps = gst_video_info_to_caps (&self->output_state->info);
if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) {
if (self->streaming)
return TRUE;
if (!gst_v4l2_decoder_streamon (self->decoder, GST_PAD_SINK)) {
GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
("Could not enable the decoder driver."),
@ -524,6 +534,8 @@ gst_v4l2_codec_vp9_dec_negotiate (GstVideoDecoder * decoder)
return FALSE;
}
self->streaming = TRUE;
return TRUE;
}
@ -645,7 +657,7 @@ gst_v4l2_codec_vp9_dec_new_sequence (GstVp9Decoder * decoder,
gst_v4l2_codec_vp9_dec_fill_prob_updates (self, frame_hdr);
if (negotiation_needed) {
self->need_negotiation = TRUE;
gst_v4l2_codec_vp9_dec_streamoff (self);
if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
return GST_FLOW_ERROR;
@ -932,6 +944,13 @@ gst_v4l2_codec_vp9_dec_output_picture (GstVp9Decoder * decoder,
GstV4l2Request *request = NULL;
gint ret;
if (picture->discont_state) {
if (!gst_video_decoder_negotiate (vdec)) {
GST_ERROR_OBJECT (vdec, "Could not re-negotiate with updated state");
return FALSE;
}
}
GST_DEBUG_OBJECT (self, "Output picture %u", picture->system_frame_number);
if (!GST_MINI_OBJECT_FLAG_IS_SET (picture, FLAG_PICTURE_HOLDS_BUFFER))