From 2ede4011bfd6d4c0820fa1b5e9597ad76244ebfb Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sat, 5 Nov 2022 01:07:02 +0900 Subject: [PATCH] codecs: Keep track of non-decoding-essential input state change In theory, input caps can be updated anytime at non-keyframe or sequence boundary, such as HDR10 metadata, framerate, aspect-ratio or so. Those information update might not trigger ::new_sequence() or subclass may ignore the changes. By this commit, input state change will be tracked by baseclass and subclass will be able to know the non-decoding-essential update by checking the codec specific picture struct on ::output_picture() Part-of: --- .../gst-libs/gst/codecs/gstav1decoder.c | 25 +++++++++++++++++++ .../gst-libs/gst/codecs/gstav1picture.c | 3 +++ .../gst-libs/gst/codecs/gstav1picture.h | 4 +++ .../gst-libs/gst/codecs/gsth264decoder.c | 25 +++++++++++++++++++ .../gst-libs/gst/codecs/gsth264picture.c | 3 +++ .../gst-libs/gst/codecs/gsth264picture.h | 3 +++ .../gst-libs/gst/codecs/gsth265decoder.c | 25 +++++++++++++++++++ .../gst-libs/gst/codecs/gsth265picture.c | 3 +++ .../gst-libs/gst/codecs/gsth265picture.h | 3 +++ .../gst-libs/gst/codecs/gstmpeg2decoder.c | 25 +++++++++++++++++++ .../gst-libs/gst/codecs/gstmpeg2picture.c | 3 +++ .../gst-libs/gst/codecs/gstmpeg2picture.h | 3 +++ .../gst-libs/gst/codecs/gstvp8decoder.c | 24 ++++++++++++++++++ .../gst-libs/gst/codecs/gstvp8picture.c | 3 +++ .../gst-libs/gst/codecs/gstvp8picture.h | 5 ++++ .../gst-libs/gst/codecs/gstvp9decoder.c | 24 ++++++++++++++++++ .../gst-libs/gst/codecs/gstvp9picture.c | 3 +++ .../gst-libs/gst/codecs/gstvp9picture.h | 4 +++ 18 files changed, 188 insertions(+) diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1decoder.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1decoder.c index 7208821dfd..9808af8292 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1decoder.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1decoder.c @@ -48,6 +48,8 @@ struct _GstAV1DecoderPrivate guint preferred_output_delay; GstQueueArray *output_queue; gboolean is_live; + + gboolean input_state_changed; }; typedef struct @@ -83,6 +85,7 @@ static gboolean gst_av1_decoder_start (GstVideoDecoder * decoder); static gboolean gst_av1_decoder_stop (GstVideoDecoder * decoder); static gboolean gst_av1_decoder_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state); +static gboolean gst_av1_decoder_negotiate (GstVideoDecoder * decoder); static GstFlowReturn gst_av1_decoder_finish (GstVideoDecoder * decoder); static gboolean gst_av1_decoder_flush (GstVideoDecoder * decoder); static GstFlowReturn gst_av1_decoder_drain (GstVideoDecoder * decoder); @@ -102,6 +105,7 @@ gst_av1_decoder_class_init (GstAV1DecoderClass * klass) decoder_class->start = GST_DEBUG_FUNCPTR (gst_av1_decoder_start); decoder_class->stop = GST_DEBUG_FUNCPTR (gst_av1_decoder_stop); decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_av1_decoder_set_format); + decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_av1_decoder_negotiate); decoder_class->finish = GST_DEBUG_FUNCPTR (gst_av1_decoder_finish); decoder_class->flush = GST_DEBUG_FUNCPTR (gst_av1_decoder_flush); decoder_class->drain = GST_DEBUG_FUNCPTR (gst_av1_decoder_drain); @@ -210,6 +214,8 @@ gst_av1_decoder_set_format (GstVideoDecoder * decoder, GST_DEBUG_OBJECT (decoder, "Set format"); + priv->input_state_changed = TRUE; + if (self->input_state) gst_video_codec_state_unref (self->input_state); @@ -227,6 +233,17 @@ gst_av1_decoder_set_format (GstVideoDecoder * decoder, return TRUE; } +static gboolean +gst_av1_decoder_negotiate (GstVideoDecoder * decoder) +{ + GstAV1Decoder *self = GST_AV1_DECODER (decoder); + + /* output state must be updated by subclass using new input state already */ + self->priv->input_state_changed = FALSE; + + return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); +} + static void gst_av1_decoder_drain_output_queue (GstAV1Decoder * self, guint num, GstFlowReturn * ret) @@ -731,6 +748,14 @@ out: } else { GstAV1DecoderOutputFrame output_frame; + /* If subclass didn't update output state at this point, + * marking this picture as a discont and stores current input state */ + if (priv->input_state_changed) { + priv->current_picture->discont_state = + gst_video_codec_state_ref (self->input_state); + priv->input_state_changed = FALSE; + } + output_frame.frame = frame; output_frame.picture = priv->current_picture; output_frame.self = self; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1picture.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1picture.c index 733522feec..10ea59449c 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1picture.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1picture.c @@ -36,6 +36,9 @@ _gst_av1_picture_free (GstAV1Picture * picture) if (picture->notify) picture->notify (picture->user_data); + if (picture->discont_state) + gst_video_codec_state_unref (picture->discont_state); + g_free (picture); } diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1picture.h b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1picture.h index f0d8a706d0..25ae05908c 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1picture.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1picture.h @@ -22,6 +22,7 @@ #include #include +#include G_BEGIN_DECLS @@ -84,6 +85,9 @@ struct _GstAV1Picture gboolean showable_frame; gboolean apply_grain; + /* decoder input state if this picture is discont point */ + GstVideoCodecState *discont_state; + gpointer user_data; GDestroyNotify notify; }; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264decoder.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264decoder.c index 7afe50b908..d62cdca299 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264decoder.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264decoder.c @@ -150,6 +150,8 @@ struct _GstH264DecoderPrivate /* For delayed output */ GstQueueArray *output_queue; + + gboolean input_state_changed; }; typedef struct @@ -179,6 +181,7 @@ static gboolean gst_h264_decoder_start (GstVideoDecoder * decoder); static gboolean gst_h264_decoder_stop (GstVideoDecoder * decoder); static gboolean gst_h264_decoder_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state); +static gboolean gst_h264_decoder_negotiate (GstVideoDecoder * decoder); static GstFlowReturn gst_h264_decoder_finish (GstVideoDecoder * decoder); static gboolean gst_h264_decoder_flush (GstVideoDecoder * decoder); static GstFlowReturn gst_h264_decoder_drain (GstVideoDecoder * decoder); @@ -307,6 +310,7 @@ gst_h264_decoder_class_init (GstH264DecoderClass * klass) decoder_class->start = GST_DEBUG_FUNCPTR (gst_h264_decoder_start); decoder_class->stop = GST_DEBUG_FUNCPTR (gst_h264_decoder_stop); decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_h264_decoder_set_format); + decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_h264_decoder_negotiate); decoder_class->finish = GST_DEBUG_FUNCPTR (gst_h264_decoder_finish); decoder_class->flush = GST_DEBUG_FUNCPTR (gst_h264_decoder_flush); decoder_class->drain = GST_DEBUG_FUNCPTR (gst_h264_decoder_drain); @@ -1023,6 +1027,14 @@ gst_h264_decoder_start_current_picture (GstH264Decoder * self) g_assert (priv->active_sps != NULL); g_assert (priv->active_pps != NULL); + /* If subclass didn't update output state at this point, + * marking this picture as a discont and stores current input state */ + if (priv->input_state_changed) { + priv->current_picture->discont_state = + gst_video_codec_state_ref (self->input_state); + priv->input_state_changed = FALSE; + } + sps = priv->active_sps; priv->max_frame_num = sps->max_frame_num; @@ -1369,6 +1381,8 @@ gst_h264_decoder_set_format (GstVideoDecoder * decoder, GST_DEBUG_OBJECT (decoder, "Set format"); + priv->input_state_changed = TRUE; + if (self->input_state) gst_video_codec_state_unref (self->input_state); @@ -1441,6 +1455,17 @@ gst_h264_decoder_set_format (GstVideoDecoder * decoder, return TRUE; } +static gboolean +gst_h264_decoder_negotiate (GstVideoDecoder * decoder) +{ + GstH264Decoder *self = GST_H264_DECODER (decoder); + + /* output state must be updated by subclass using new input state already */ + self->priv->input_state_changed = FALSE; + + return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); +} + static gboolean gst_h264_decoder_fill_picture_from_slice (GstH264Decoder * self, const GstH264Slice * slice, GstH264Picture * picture) diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264picture.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264picture.c index abb4bfb202..f3ba1ba672 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264picture.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264picture.c @@ -35,6 +35,9 @@ _gst_h264_picture_free (GstH264Picture * picture) if (picture->notify) picture->notify (picture->user_data); + if (picture->discont_state) + gst_video_codec_state_unref (picture->discont_state); + g_free (picture); } diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264picture.h b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264picture.h index 3893381fb6..19f865d6c3 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264picture.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264picture.h @@ -161,6 +161,9 @@ struct _GstH264Picture GstVideoBufferFlags buffer_flags; + /* decoder input state if this picture is discont point */ + GstVideoCodecState *discont_state; + gpointer user_data; GDestroyNotify notify; }; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265decoder.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265decoder.c index 3b7757cafb..31265171f4 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265decoder.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265decoder.c @@ -134,6 +134,8 @@ struct _GstH265DecoderPrivate guint preferred_output_delay; gboolean is_live; GstQueueArray *output_queue; + + gboolean input_state_changed; }; typedef struct @@ -173,6 +175,7 @@ static gboolean gst_h265_decoder_start (GstVideoDecoder * decoder); static gboolean gst_h265_decoder_stop (GstVideoDecoder * decoder); static gboolean gst_h265_decoder_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state); +static gboolean gst_h265_decoder_negotiate (GstVideoDecoder * decoder); static GstFlowReturn gst_h265_decoder_finish (GstVideoDecoder * decoder); static gboolean gst_h265_decoder_flush (GstVideoDecoder * decoder); static GstFlowReturn gst_h265_decoder_drain (GstVideoDecoder * decoder); @@ -201,6 +204,7 @@ gst_h265_decoder_class_init (GstH265DecoderClass * klass) decoder_class->start = GST_DEBUG_FUNCPTR (gst_h265_decoder_start); decoder_class->stop = GST_DEBUG_FUNCPTR (gst_h265_decoder_stop); decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_h265_decoder_set_format); + decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_h265_decoder_negotiate); decoder_class->finish = GST_DEBUG_FUNCPTR (gst_h265_decoder_finish); decoder_class->flush = GST_DEBUG_FUNCPTR (gst_h265_decoder_flush); decoder_class->drain = GST_DEBUG_FUNCPTR (gst_h265_decoder_drain); @@ -1083,6 +1087,8 @@ gst_h265_decoder_set_format (GstVideoDecoder * decoder, GST_DEBUG_OBJECT (decoder, "Set format"); + priv->input_state_changed = TRUE; + if (self->input_state) gst_video_codec_state_unref (self->input_state); @@ -1151,6 +1157,17 @@ gst_h265_decoder_set_format (GstVideoDecoder * decoder, return TRUE; } +static gboolean +gst_h265_decoder_negotiate (GstVideoDecoder * decoder) +{ + GstH265Decoder *self = GST_H265_DECODER (decoder); + + /* output state must be updated by subclass using new input state already */ + self->priv->input_state_changed = FALSE; + + return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); +} + static gboolean gst_h265_decoder_flush (GstVideoDecoder * decoder) { @@ -1785,6 +1802,14 @@ gst_h265_decoder_start_current_picture (GstH265Decoder * self) return GST_FLOW_OK; } + /* If subclass didn't update output state at this point, + * marking this picture as a discont and stores current input state */ + if (priv->input_state_changed) { + priv->current_picture->discont_state = + gst_video_codec_state_ref (self->input_state); + priv->input_state_changed = FALSE; + } + gst_h265_decoder_prepare_rps (self, &priv->current_slice, priv->current_picture); diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265picture.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265picture.c index 995e4f93a2..dc0aa61207 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265picture.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265picture.c @@ -34,6 +34,9 @@ _gst_h265_picture_free (GstH265Picture * picture) if (picture->notify) picture->notify (picture->user_data); + if (picture->discont_state) + gst_video_codec_state_unref (picture->discont_state); + g_free (picture); } diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265picture.h b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265picture.h index a96a1629c9..ac2e3fd58a 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265picture.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265picture.h @@ -90,6 +90,9 @@ struct _GstH265Picture GstVideoBufferFlags buffer_flags; + /* decoder input state if this picture is discont point */ + GstVideoCodecState *discont_state; + gpointer user_data; GDestroyNotify notify; }; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2decoder.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2decoder.c index 988eb7cc36..7a45be6b91 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2decoder.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2decoder.c @@ -267,6 +267,8 @@ struct _GstMpeg2DecoderPrivate GstQueueArray *output_queue; /* used for low-latency vs. high throughput mode decision */ gboolean is_live; + + gboolean input_state_changed; }; #define UPDATE_FLOW_RETURN(ret,new_ret) G_STMT_START { \ @@ -293,6 +295,7 @@ static gboolean gst_mpeg2_decoder_start (GstVideoDecoder * decoder); static gboolean gst_mpeg2_decoder_stop (GstVideoDecoder * decoder); static gboolean gst_mpeg2_decoder_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state); +static gboolean gst_mpeg2_decoder_negotiate (GstVideoDecoder * decoder); static GstFlowReturn gst_mpeg2_decoder_finish (GstVideoDecoder * decoder); static gboolean gst_mpeg2_decoder_flush (GstVideoDecoder * decoder); static GstFlowReturn gst_mpeg2_decoder_drain (GstVideoDecoder * decoder); @@ -314,6 +317,7 @@ gst_mpeg2_decoder_class_init (GstMpeg2DecoderClass * klass) decoder_class->start = GST_DEBUG_FUNCPTR (gst_mpeg2_decoder_start); decoder_class->stop = GST_DEBUG_FUNCPTR (gst_mpeg2_decoder_stop); decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_mpeg2_decoder_set_format); + decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_mpeg2_decoder_negotiate); decoder_class->finish = GST_DEBUG_FUNCPTR (gst_mpeg2_decoder_finish); decoder_class->flush = GST_DEBUG_FUNCPTR (gst_mpeg2_decoder_flush); decoder_class->drain = GST_DEBUG_FUNCPTR (gst_mpeg2_decoder_drain); @@ -379,6 +383,8 @@ gst_mpeg2_decoder_set_format (GstVideoDecoder * decoder, GST_DEBUG_OBJECT (decoder, "Set format"); + priv->input_state_changed = TRUE; + if (self->input_state) gst_video_codec_state_unref (self->input_state); @@ -395,6 +401,17 @@ gst_mpeg2_decoder_set_format (GstVideoDecoder * decoder, return TRUE; } +static gboolean +gst_mpeg2_decoder_negotiate (GstVideoDecoder * decoder) +{ + GstMpeg2Decoder *self = GST_MPEG2_DECODER (decoder); + + /* output state must be updated by subclass using new input state already */ + self->priv->input_state_changed = FALSE; + + return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); +} + static GstFlowReturn gst_mpeg2_decoder_drain (GstVideoDecoder * decoder) { @@ -817,6 +834,14 @@ gst_mpeg2_decoder_start_current_picture (GstMpeg2Decoder * decoder, GstMpeg2Picture *prev_picture, *next_picture; GstFlowReturn ret; + /* If subclass didn't update output state at this point, + * marking this picture as a discont and stores current input state */ + if (priv->input_state_changed) { + priv->current_picture->discont_state = + gst_video_codec_state_ref (decoder->input_state); + priv->input_state_changed = FALSE; + } + if (!klass->start_picture) return GST_FLOW_OK; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2picture.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2picture.c index 7a72cab8e3..fd87ab39f1 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2picture.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2picture.c @@ -40,6 +40,9 @@ _gst_mpeg2_picture_free (GstMpeg2Picture * picture) if (picture->notify) picture->notify (picture->user_data); + if (picture->discont_state) + gst_video_codec_state_unref (picture->discont_state); + g_free (picture); } diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2picture.h b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2picture.h index bd5ac3794e..c9614895b3 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2picture.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2picture.h @@ -94,6 +94,9 @@ struct _GstMpeg2Picture GstMpegVideoPictureStructure structure; GstMpegVideoPictureType type; + /* decoder input state if this picture is discont point */ + GstVideoCodecState *discont_state; + gpointer user_data; GDestroyNotify notify; }; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8decoder.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8decoder.c index 9afb8d833c..97d72fa03d 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8decoder.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8decoder.c @@ -47,6 +47,8 @@ struct _GstVp8DecoderPrivate /* for delayed output */ GstQueueArray *output_queue; gboolean is_live; + + gboolean input_state_changed; }; typedef struct @@ -67,6 +69,7 @@ static gboolean gst_vp8_decoder_start (GstVideoDecoder * decoder); static gboolean gst_vp8_decoder_stop (GstVideoDecoder * decoder); static gboolean gst_vp8_decoder_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state); +static gboolean gst_vp8_decoder_negotiate (GstVideoDecoder * decoder); static GstFlowReturn gst_vp8_decoder_finish (GstVideoDecoder * decoder); static gboolean gst_vp8_decoder_flush (GstVideoDecoder * decoder); static GstFlowReturn gst_vp8_decoder_drain (GstVideoDecoder * decoder); @@ -87,6 +90,7 @@ gst_vp8_decoder_class_init (GstVp8DecoderClass * klass) decoder_class->start = GST_DEBUG_FUNCPTR (gst_vp8_decoder_start); decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vp8_decoder_stop); decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_vp8_decoder_set_format); + decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_vp8_decoder_negotiate); decoder_class->finish = GST_DEBUG_FUNCPTR (gst_vp8_decoder_finish); decoder_class->flush = GST_DEBUG_FUNCPTR (gst_vp8_decoder_flush); decoder_class->drain = GST_DEBUG_FUNCPTR (gst_vp8_decoder_drain); @@ -205,6 +209,8 @@ gst_vp8_decoder_set_format (GstVideoDecoder * decoder, GST_DEBUG_OBJECT (decoder, "Set format"); + priv->input_state_changed = TRUE; + if (self->input_state) gst_video_codec_state_unref (self->input_state); @@ -221,6 +227,17 @@ gst_vp8_decoder_set_format (GstVideoDecoder * decoder, return TRUE; } +static gboolean +gst_vp8_decoder_negotiate (GstVideoDecoder * decoder) +{ + GstVp8Decoder *self = GST_VP8_DECODER (decoder); + + /* output state must be updated by subclass using new input state already */ + self->priv->input_state_changed = FALSE; + + return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); +} + static gboolean gst_vp8_decoder_update_reference (GstVp8Decoder * self, GstVp8Picture * picture) { @@ -452,6 +469,13 @@ gst_vp8_decoder_handle_frame (GstVideoDecoder * decoder, ret = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); } else { + /* If subclass didn't update output state at this point, + * marking this picture as a discont and stores current input state */ + if (priv->input_state_changed) { + picture->discont_state = gst_video_codec_state_ref (self->input_state); + priv->input_state_changed = FALSE; + } + output_frame.frame = frame; output_frame.picture = picture; output_frame.self = self; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8picture.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8picture.c index b40e207c2e..4a56605ef3 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8picture.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8picture.c @@ -36,6 +36,9 @@ _gst_vp8_picture_free (GstVp8Picture * picture) if (picture->notify) picture->notify (picture->user_data); + if (picture->discont_state) + gst_video_codec_state_unref (picture->discont_state); + g_free (picture); } diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8picture.h b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8picture.h index abfc07adb9..9fc3f65f53 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8picture.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8picture.h @@ -22,6 +22,7 @@ #include #include +#include G_BEGIN_DECLS @@ -34,6 +35,7 @@ typedef struct _GstVp8Picture GstVp8Picture; struct _GstVp8Picture { + /*< private >*/ GstMiniObject parent; GstClockTime pts; @@ -46,6 +48,9 @@ struct _GstVp8Picture const guint8 * data; gsize size; + /* decoder input state if this picture is discont point */ + GstVideoCodecState *discont_state; + gpointer user_data; GDestroyNotify notify; }; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9decoder.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9decoder.c index f5ad4d2e06..1740e75595 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9decoder.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9decoder.c @@ -84,6 +84,8 @@ struct _GstVp9DecoderPrivate guint preferred_output_delay; GstQueueArray *output_queue; gboolean is_live; + + gboolean input_state_changed; }; typedef struct @@ -104,6 +106,7 @@ static gboolean gst_vp9_decoder_start (GstVideoDecoder * decoder); static gboolean gst_vp9_decoder_stop (GstVideoDecoder * decoder); static gboolean gst_vp9_decoder_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state); +static gboolean gst_vp9_decoder_negotiate (GstVideoDecoder * decoder); static GstFlowReturn gst_vp9_decoder_finish (GstVideoDecoder * decoder); static gboolean gst_vp9_decoder_flush (GstVideoDecoder * decoder); static GstFlowReturn gst_vp9_decoder_drain (GstVideoDecoder * decoder); @@ -125,6 +128,7 @@ gst_vp9_decoder_class_init (GstVp9DecoderClass * klass) decoder_class->start = GST_DEBUG_FUNCPTR (gst_vp9_decoder_start); decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vp9_decoder_stop); decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_vp9_decoder_set_format); + decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_vp9_decoder_negotiate); decoder_class->finish = GST_DEBUG_FUNCPTR (gst_vp9_decoder_finish); decoder_class->flush = GST_DEBUG_FUNCPTR (gst_vp9_decoder_flush); decoder_class->drain = GST_DEBUG_FUNCPTR (gst_vp9_decoder_drain); @@ -264,6 +268,8 @@ gst_vp9_decoder_set_format (GstVideoDecoder * decoder, GST_DEBUG_OBJECT (decoder, "Set format"); + priv->input_state_changed = TRUE; + if (self->input_state) gst_video_codec_state_unref (self->input_state); @@ -277,6 +283,17 @@ gst_vp9_decoder_set_format (GstVideoDecoder * decoder, return TRUE; } +static gboolean +gst_vp9_decoder_negotiate (GstVideoDecoder * decoder) +{ + GstVp9Decoder *self = GST_VP9_DECODER (decoder); + + /* output state must be updated by subclass using new input state already */ + self->priv->input_state_changed = FALSE; + + return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); +} + static void gst_vp9_decoder_reset (GstVp9Decoder * self) { @@ -529,6 +546,13 @@ gst_vp9_decoder_handle_frame (GstVideoDecoder * decoder, ret = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); } else { + /* If subclass didn't update output state at this point, + * marking this picture as a discont and stores current input state */ + if (priv->input_state_changed) { + picture->discont_state = gst_video_codec_state_ref (self->input_state); + priv->input_state_changed = FALSE; + } + output_frame.frame = frame; output_frame.picture = picture; output_frame.self = self; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.c index 64b5a18b67..e3e09c33f7 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.c @@ -36,6 +36,9 @@ _gst_vp9_picture_free (GstVp9Picture * picture) if (picture->notify) picture->notify (picture->user_data); + if (picture->discont_state) + gst_video_codec_state_unref (picture->discont_state); + g_free (picture); } diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.h b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.h index 6caf18bd2b..4c60491872 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.h @@ -22,6 +22,7 @@ #include #include +#include G_BEGIN_DECLS @@ -46,6 +47,9 @@ struct _GstVp9Picture const guint8 * data; gsize size; + /* decoder input state if this picture is discont point */ + GstVideoCodecState *discont_state; + gpointer user_data; GDestroyNotify notify; };