codecs: Keep track of non-decoding-essential input state change
authorSeungha Yang <seungha@centricular.com>
Fri, 4 Nov 2022 16:07:02 +0000 (01:07 +0900)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 16 Nov 2022 13:12:38 +0000 (13:12 +0000)
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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3328>

18 files changed:
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1decoder.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1picture.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstav1picture.h
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264decoder.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264picture.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth264picture.h
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265decoder.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265picture.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gsth265picture.h
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2decoder.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2picture.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstmpeg2picture.h
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8decoder.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8picture.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp8picture.h
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9decoder.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.c
subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.h

index 7208821..9808af8 100644 (file)
@@ -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;
index 733522f..10ea594 100644 (file)
@@ -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);
 }
 
index f0d8a70..25ae059 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <gst/codecs/codecs-prelude.h>
 #include <gst/codecparsers/gstav1parser.h>
+#include <gst/video/video.h>
 
 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;
 };
index 7afe50b..d62cdca 100644 (file)
@@ -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);
 
@@ -1442,6 +1456,17 @@ gst_h264_decoder_set_format (GstVideoDecoder * decoder,
 }
 
 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)
 {
index abb4bfb..f3ba1ba 100644 (file)
@@ -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);
 }
 
index 3893381..19f865d 100644 (file)
@@ -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;
 };
index 3b7757c..3126517 100644 (file)
@@ -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);
 
@@ -1152,6 +1158,17 @@ gst_h265_decoder_set_format (GstVideoDecoder * decoder,
 }
 
 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)
 {
   GstH265Decoder *self = GST_H265_DECODER (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);
 
index 995e4f9..dc0aa61 100644 (file)
@@ -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);
 }
 
index a96a162..ac2e3fd 100644 (file)
@@ -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;
 };
index 988eb7c..7a45be6 100644 (file)
@@ -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;
 
index 7a72cab..fd87ab3 100644 (file)
@@ -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);
 }
 
index bd5ac37..c961489 100644 (file)
@@ -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;
 };
index 9afb8d8..97d72fa 100644 (file)
@@ -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);
 
@@ -222,6 +228,17 @@ gst_vp8_decoder_set_format (GstVideoDecoder * decoder,
 }
 
 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)
 {
   GstVp8FrameHdr *frame_hdr = &picture->frame_hdr;
@@ -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;
index b40e207..4a56605 100644 (file)
@@ -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);
 }
 
index abfc07a..9fc3f65 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <gst/codecs/codecs-prelude.h>
 #include <gst/codecparsers/gstvp8parser.h>
+#include <gst/video/video.h>
 
 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;
 };
index f5ad4d2..1740e75 100644 (file)
@@ -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;
index 64b5a18..e3e09c3 100644 (file)
@@ -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);
 }
 
index 6caf18b..4c60491 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <gst/codecs/codecs-prelude.h>
 #include <gst/codecs/gstvp9statefulparser.h>
+#include <gst/video/video.h>
 
 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;
 };