Merge branch 'DTS_H264_H265' into 'main'

vah26{4,5}enc: Set DTS offset before PTS

See merge request gstreamer/gstreamer!6791
This commit is contained in:
He Junyan 2024-05-03 16:12:11 +00:00
commit 4f67cfa40a
4 changed files with 118 additions and 50 deletions

View file

@ -557,6 +557,8 @@ gst_va_base_enc_drain (GstVideoEncoder * venc)
g_queue_clear_full (&base->ref_list,
(GDestroyNotify) gst_video_codec_frame_unref);
gst_queue_array_clear (base->dts_queue);
return GST_FLOW_OK;
error_and_purge_all:
@ -591,6 +593,8 @@ error_and_purge_all:
g_queue_clear_full (&base->ref_list,
(GDestroyNotify) gst_video_codec_frame_unref);
gst_queue_array_clear (base->dts_queue);
return ret;
}
@ -744,7 +748,12 @@ gst_va_base_enc_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
static gboolean
gst_va_base_enc_flush (GstVideoEncoder * venc)
{
GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
_flush_all_frames (GST_VA_BASE_ENC (venc));
gst_queue_array_clear (base->dts_queue);
return TRUE;
}
@ -882,14 +891,19 @@ gst_va_base_enc_init (GstVaBaseEnc * self)
g_queue_init (&self->output_list);
gst_video_info_init (&self->in_info);
self->dts_queue = gst_queue_array_new_for_struct (sizeof (GstClockTime), 8);
self->priv = gst_va_base_enc_get_instance_private (self);
}
static void
gst_va_base_enc_dispose (GObject * object)
{
GstVaBaseEnc *base = GST_VA_BASE_ENC (object);
_flush_all_frames (GST_VA_BASE_ENC (object));
gst_va_base_enc_close (GST_VIDEO_ENCODER (object));
g_clear_pointer (&base->dts_queue, gst_queue_array_free);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@ -1134,6 +1148,48 @@ gst_va_base_enc_add_codec_tag (GstVaBaseEnc * base, const gchar * codec_name)
gst_tag_list_unref (tags);
}
void
gst_va_base_enc_push_dts (GstVaBaseEnc * base,
GstVideoCodecFrame * frame, guint max_reorder_num)
{
/* We need to manually insert max_reorder_num slots before the
first frame to ensure DTS never bigger than PTS. */
if (gst_queue_array_get_length (base->dts_queue) == 0 && max_reorder_num > 0) {
GstClockTime dts_diff = 0, dts;
if (GST_CLOCK_TIME_IS_VALID (frame->duration))
dts_diff = frame->duration;
if (GST_CLOCK_TIME_IS_VALID (base->frame_duration))
dts_diff = MAX (base->frame_duration, dts_diff);
while (max_reorder_num > 0) {
if (GST_CLOCK_TIME_IS_VALID (frame->pts)) {
dts = frame->pts - dts_diff * max_reorder_num;
} else {
dts = frame->pts;
}
gst_queue_array_push_tail_struct (base->dts_queue, &dts);
max_reorder_num--;
}
}
gst_queue_array_push_tail_struct (base->dts_queue, &frame->pts);
}
GstClockTime
gst_va_base_enc_pop_dts (GstVaBaseEnc * base)
{
GstClockTime dts;
g_return_val_if_fail (gst_queue_array_get_length (base->dts_queue) > 0,
GST_CLOCK_TIME_NONE);
dts = *((GstClockTime *) gst_queue_array_pop_head_struct (base->dts_queue));
return dts;
}
void
gst_va_base_enc_reset_state (GstVaBaseEnc * base)
{

View file

@ -23,6 +23,7 @@
#include "gstvadevice.h"
#include "gstvaencoder.h"
#include "gstvaprofile.h"
#include <gst/base/gstqueuearray.h>
G_BEGIN_DECLS
@ -60,6 +61,7 @@ struct _GstVaBaseEnc
GQueue reorder_list;
GQueue ref_list;
GQueue output_list;
GstQueueArray *dts_queue;
GstVideoCodecState *input_state;
union {
@ -142,6 +144,10 @@ gint gst_va_base_enc_copy_output_data (GstVaBaseEnc * base,
GstVaEncodePicture * picture,
guint8 * data,
gint size);
void gst_va_base_enc_push_dts (GstVaBaseEnc * base,
GstVideoCodecFrame * frame,
guint max_reorder_num);
GstClockTime gst_va_base_enc_pop_dts (GstVaBaseEnc * base);
void gst_va_base_enc_update_property_uint (GstVaBaseEnc * base,
guint32 * old_val,
guint32 new_val,

View file

@ -255,7 +255,6 @@ struct _GstVaH264Enc
guint cpb_length_bits;
} rc;
GstClockTime last_dts;
GstH264SPS sequence_hdr;
};
@ -277,7 +276,6 @@ struct _GstVaH264EncFrame
gint unused_for_reference_pic_num;
gboolean last_frame;
gboolean reorder;
};
/**
@ -380,7 +378,6 @@ gst_va_enc_frame_new (void)
frame->unused_for_reference_pic_num = -1;
frame->picture = NULL;
frame->last_frame = FALSE;
frame->reorder = FALSE;
return frame;
}
@ -1552,7 +1549,6 @@ gst_va_h264_enc_reset_state (GstVaBaseEnc * base)
self->rc.target_bitrate_bits = 0;
self->rc.cpb_length_bits = 0;
self->last_dts = GST_CLOCK_TIME_NONE;
memset (&self->sequence_hdr, 0, sizeof (GstH264SPS));
}
@ -1883,9 +1879,6 @@ again:
/* it will unref at pop_frame */
f = g_queue_pop_nth (&base->reorder_list, index);
g_assert (f == b_frame);
if (index > 0)
_enc_frame (f)->reorder = TRUE;
} else {
b_frame = NULL;
}
@ -1914,9 +1907,6 @@ _pop_one_frame (GstVaBaseEnc * base, GstVideoCodecFrame ** out_frame)
vaframe = _enc_frame (frame);
if (vaframe->type != GST_H264_B_SLICE) {
frame = g_queue_pop_tail (&base->reorder_list);
if (!g_queue_is_empty (&base->reorder_list))
vaframe->reorder = TRUE;
goto get_one;
}
@ -3079,27 +3069,19 @@ static gboolean
gst_va_h264_enc_prepare_output (GstVaBaseEnc * base,
GstVideoCodecFrame * frame, gboolean * complete)
{
GstVaH264Enc *self = GST_VA_H264_ENC (base);
GstVaH264EncFrame *frame_enc;
GstBuffer *buf;
frame_enc = _enc_frame (frame);
if (frame_enc->reorder) {
if (!GST_CLOCK_TIME_IS_VALID (self->last_dts)) {
GST_WARNING_OBJECT (base, "Reorder frame poc: %d, system frame "
"number: %d without previous valid DTS.", frame_enc->poc,
frame->system_frame_number);
frame->dts = frame->pts;
} else {
GST_LOG_OBJECT (base, "Set reorder frame poc: %d, system frame "
"number: %d with DTS: %" GST_TIME_FORMAT, frame_enc->poc,
frame->system_frame_number, GST_TIME_ARGS (self->last_dts));
frame->dts = self->last_dts;
}
} else {
frame->dts = gst_va_base_enc_pop_dts (base);
if (!GST_CLOCK_TIME_IS_VALID (frame->dts)) {
GST_DEBUG_OBJECT (base, "Pop invalid DTS.");
} else if (GST_CLOCK_TIME_IS_VALID (frame->pts) && frame->dts > frame->pts) {
GST_WARNING_OBJECT (base, "Pop DTS: %" GST_TIME_FORMAT " > PTS: %"
GST_TIME_FORMAT, GST_TIME_ARGS (frame->dts),
GST_TIME_ARGS (frame->pts));
frame->dts = frame->pts;
self->last_dts = frame->dts;
}
buf = gst_va_base_enc_create_output_buffer (base,
@ -3250,14 +3232,27 @@ gst_va_h264_enc_encode_frame (GstVaBaseEnc * base,
static gboolean
gst_va_h264_enc_new_frame (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
{
GstVaH264Enc *self = GST_VA_H264_ENC (base);
GstVaH264EncFrame *frame_in;
frame_in = gst_va_enc_frame_new ();
gst_video_codec_frame_set_user_data (frame, frame_in, gst_va_enc_frame_free);
gst_va_base_enc_push_dts (base, frame, self->gop.num_reorder_frames);
return TRUE;
}
static gboolean
gst_va_h264_enc_start (GstVideoEncoder * venc)
{
/* Set the minimum pts to some huge value (1000 hours). This keeps
* the dts at the start of the stream from needing to be negative. */
gst_video_encoder_set_min_pts (venc, GST_SECOND * 60 * 60 * 1000);
return GST_VIDEO_ENCODER_CLASS (parent_class)->start (venc);
}
/* *INDENT-OFF* */
static const gchar *sink_caps_str =
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_VA,
@ -3605,6 +3600,7 @@ gst_va_h264_enc_class_init (gpointer g_klass, gpointer class_data)
object_class->get_property = gst_va_h264_enc_get_property;
venc_class->flush = GST_DEBUG_FUNCPTR (gst_va_h264_enc_flush);
venc_class->start = GST_DEBUG_FUNCPTR (gst_va_h264_enc_start);
va_enc_class->reset_state = GST_DEBUG_FUNCPTR (gst_va_h264_enc_reset_state);
va_enc_class->reconfig = GST_DEBUG_FUNCPTR (gst_va_h264_enc_reconfig);

View file

@ -333,7 +333,6 @@ struct _GstVaH265Enc
guint cpb_length_bits;
} rc;
GstClockTime last_dts;
GstH265VPS vps_hdr;
GstH265SPS sps_hdr;
};
@ -350,7 +349,6 @@ struct _GstVaH265EncFrame
gint poc;
gboolean last_frame;
gboolean reorder;
};
/**
@ -452,7 +450,6 @@ gst_va_h265_enc_frame_new (void)
frame = g_new (GstVaH265EncFrame, 1);
frame->last_frame = FALSE;
frame->picture = NULL;
frame->reorder = FALSE;
return frame;
}
@ -2193,9 +2190,6 @@ again:
/* it will unref at pop_frame */
f = g_queue_pop_nth (&base->reorder_list, index);
g_assert (f == b_frame);
if (index > 0)
_enc_frame (f)->reorder = TRUE;
} else {
b_frame = NULL;
}
@ -2224,9 +2218,6 @@ _h265_pop_one_frame (GstVaBaseEnc * base, GstVideoCodecFrame ** out_frame)
vaframe = _enc_frame (frame);
if (vaframe->type != GST_H265_B_SLICE) {
frame = g_queue_pop_tail (&base->reorder_list);
if (!g_queue_is_empty (&base->reorder_list))
vaframe->reorder = TRUE;
goto get_one;
}
@ -2542,7 +2533,6 @@ gst_va_h265_enc_reset_state (GstVaBaseEnc * base)
self->rc.target_bitrate_bits = 0;
self->rc.cpb_length_bits = 0;
self->last_dts = GST_CLOCK_TIME_NONE;
memset (&self->vps_hdr, 0, sizeof (GstH265VPS));
memset (&self->sps_hdr, 0, sizeof (GstH265SPS));
}
@ -4668,15 +4658,28 @@ gst_va_h265_enc_flush (GstVideoEncoder * venc)
return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (venc);
}
static gboolean
gst_va_h265_enc_start (GstVideoEncoder * venc)
{
/* Set the minimum pts to some huge value (1000 hours). This keeps
* the dts at the start of the stream from needing to be negative. */
gst_video_encoder_set_min_pts (venc, GST_SECOND * 60 * 60 * 1000);
return GST_VIDEO_ENCODER_CLASS (parent_class)->start (venc);
}
static gboolean
gst_va_h265_enc_new_frame (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
{
GstVaH265Enc *self = GST_VA_H265_ENC (base);
GstVaH265EncFrame *frame_in;
frame_in = gst_va_h265_enc_frame_new ();
gst_video_codec_frame_set_user_data (frame, frame_in,
gst_va_h265_enc_frame_free);
gst_va_base_enc_push_dts (base, frame, self->gop.num_reorder_frames);
return TRUE;
}
@ -4684,27 +4687,19 @@ static gboolean
gst_va_h265_enc_prepare_output (GstVaBaseEnc * base,
GstVideoCodecFrame * frame, gboolean * complete)
{
GstVaH265Enc *self = GST_VA_H265_ENC (base);
GstVaH265EncFrame *frame_enc;
GstBuffer *buf;
frame_enc = _enc_frame (frame);
if (frame_enc->reorder) {
if (!GST_CLOCK_TIME_IS_VALID (self->last_dts)) {
GST_WARNING_OBJECT (base, "Reorder frame poc: %d, system frame "
"number: %d without previous valid DTS.", frame_enc->poc,
frame->system_frame_number);
frame->dts = frame->pts;
} else {
GST_LOG_OBJECT (base, "Set reorder frame poc: %d, system frame "
"number: %d with DTS: %" GST_TIME_FORMAT, frame_enc->poc,
frame->system_frame_number, GST_TIME_ARGS (self->last_dts));
frame->dts = self->last_dts;
}
} else {
frame->dts = gst_va_base_enc_pop_dts (base);
if (!GST_CLOCK_TIME_IS_VALID (frame->dts)) {
GST_DEBUG_OBJECT (base, "Pop invalid DTS.");
} else if (GST_CLOCK_TIME_IS_VALID (frame->pts) && frame->dts > frame->pts) {
GST_WARNING_OBJECT (base, "Pop DTS: %" GST_TIME_FORMAT " > PTS: %"
GST_TIME_FORMAT, GST_TIME_ARGS (frame->dts),
GST_TIME_ARGS (frame->pts));
frame->dts = frame->pts;
self->last_dts = frame->dts;
}
buf = gst_va_base_enc_create_output_buffer (base,
@ -5007,6 +5002,19 @@ gst_va_h265_enc_get_property (GObject * object, guint prop_id,
GST_OBJECT_UNLOCK (self);
}
static void
gst_va_h265_enc_dispose (GObject * object)
{
GstVaH265Enc *self = GST_VA_H265_ENC (object);
g_clear_pointer (&self->partition.slice_segment_address, g_free);
g_clear_pointer (&self->partition.num_ctu_in_slice, g_free);
g_clear_pointer (&self->partition.tile_ctu_cols, g_free);
g_clear_pointer (&self->partition.tile_ctu_rows, g_free);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_va_h265_enc_class_init (gpointer g_klass, gpointer class_data)
{
@ -5067,8 +5075,10 @@ gst_va_h265_enc_class_init (gpointer g_klass, gpointer class_data)
object_class->set_property = gst_va_h265_enc_set_property;
object_class->get_property = gst_va_h265_enc_get_property;
object_class->dispose = gst_va_h265_enc_dispose;
venc_class->flush = GST_DEBUG_FUNCPTR (gst_va_h265_enc_flush);
venc_class->start = GST_DEBUG_FUNCPTR (gst_va_h265_enc_start);
va_enc_class->reset_state = GST_DEBUG_FUNCPTR (gst_va_h265_enc_reset_state);
va_enc_class->reconfig = GST_DEBUG_FUNCPTR (gst_va_h265_enc_reconfig);