guint preferred_output_delay;
GstQueueArray *output_queue;
gboolean is_live;
+
+ gboolean input_state_changed;
};
typedef struct
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);
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);
GST_DEBUG_OBJECT (decoder, "Set format");
+ priv->input_state_changed = TRUE;
+
if (self->input_state)
gst_video_codec_state_unref (self->input_state);
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)
} 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;
if (picture->notify)
picture->notify (picture->user_data);
+ if (picture->discont_state)
+ gst_video_codec_state_unref (picture->discont_state);
+
g_free (picture);
}
#include <gst/codecs/codecs-prelude.h>
#include <gst/codecparsers/gstav1parser.h>
+#include <gst/video/video.h>
G_BEGIN_DECLS
gboolean showable_frame;
gboolean apply_grain;
+ /* decoder input state if this picture is discont point */
+ GstVideoCodecState *discont_state;
+
gpointer user_data;
GDestroyNotify notify;
};
/* For delayed output */
GstQueueArray *output_queue;
+
+ gboolean input_state_changed;
};
typedef struct
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);
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);
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;
GST_DEBUG_OBJECT (decoder, "Set format");
+ priv->input_state_changed = TRUE;
+
if (self->input_state)
gst_video_codec_state_unref (self->input_state);
}
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)
{
if (picture->notify)
picture->notify (picture->user_data);
+ if (picture->discont_state)
+ gst_video_codec_state_unref (picture->discont_state);
+
g_free (picture);
}
GstVideoBufferFlags buffer_flags;
+ /* decoder input state if this picture is discont point */
+ GstVideoCodecState *discont_state;
+
gpointer user_data;
GDestroyNotify notify;
};
guint preferred_output_delay;
gboolean is_live;
GstQueueArray *output_queue;
+
+ gboolean input_state_changed;
};
typedef struct
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);
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);
GST_DEBUG_OBJECT (decoder, "Set format");
+ priv->input_state_changed = TRUE;
+
if (self->input_state)
gst_video_codec_state_unref (self->input_state);
}
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);
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);
if (picture->notify)
picture->notify (picture->user_data);
+ if (picture->discont_state)
+ gst_video_codec_state_unref (picture->discont_state);
+
g_free (picture);
}
GstVideoBufferFlags buffer_flags;
+ /* decoder input state if this picture is discont point */
+ GstVideoCodecState *discont_state;
+
gpointer user_data;
GDestroyNotify notify;
};
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 { \
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);
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);
GST_DEBUG_OBJECT (decoder, "Set format");
+ priv->input_state_changed = TRUE;
+
if (self->input_state)
gst_video_codec_state_unref (self->input_state);
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)
{
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;
if (picture->notify)
picture->notify (picture->user_data);
+ if (picture->discont_state)
+ gst_video_codec_state_unref (picture->discont_state);
+
g_free (picture);
}
GstMpegVideoPictureStructure structure;
GstMpegVideoPictureType type;
+ /* decoder input state if this picture is discont point */
+ GstVideoCodecState *discont_state;
+
gpointer user_data;
GDestroyNotify notify;
};
/* for delayed output */
GstQueueArray *output_queue;
gboolean is_live;
+
+ gboolean input_state_changed;
};
typedef struct
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);
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);
GST_DEBUG_OBJECT (decoder, "Set format");
+ priv->input_state_changed = TRUE;
+
if (self->input_state)
gst_video_codec_state_unref (self->input_state);
}
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;
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;
if (picture->notify)
picture->notify (picture->user_data);
+ if (picture->discont_state)
+ gst_video_codec_state_unref (picture->discont_state);
+
g_free (picture);
}
#include <gst/codecs/codecs-prelude.h>
#include <gst/codecparsers/gstvp8parser.h>
+#include <gst/video/video.h>
G_BEGIN_DECLS
struct _GstVp8Picture
{
+ /*< private >*/
GstMiniObject parent;
GstClockTime pts;
const guint8 * data;
gsize size;
+ /* decoder input state if this picture is discont point */
+ GstVideoCodecState *discont_state;
+
gpointer user_data;
GDestroyNotify notify;
};
guint preferred_output_delay;
GstQueueArray *output_queue;
gboolean is_live;
+
+ gboolean input_state_changed;
};
typedef struct
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);
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);
GST_DEBUG_OBJECT (decoder, "Set format");
+ priv->input_state_changed = TRUE;
+
if (self->input_state)
gst_video_codec_state_unref (self->input_state);
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)
{
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;
if (picture->notify)
picture->notify (picture->user_data);
+ if (picture->discont_state)
+ gst_video_codec_state_unref (picture->discont_state);
+
g_free (picture);
}
#include <gst/codecs/codecs-prelude.h>
#include <gst/codecs/gstvp9statefulparser.h>
+#include <gst/video/video.h>
G_BEGIN_DECLS
const guint8 * data;
gsize size;
+ /* decoder input state if this picture is discont point */
+ GstVideoCodecState *discont_state;
+
gpointer user_data;
GDestroyNotify notify;
};