h264decoder: Update latency dynamically

The actual number of reorder frames is unknown
unless frame reordering is disabled
(e.g., POC type 2 or constrained-* profiles).
Also derived maximum DPB size or max_num_reorder_frames in VUI
is not the upper bound of output delay.

Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2702
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5326>
This commit is contained in:
Seungha Yang 2023-09-14 01:18:59 +09:00
parent bd25c2738e
commit 48a0c01570
2 changed files with 55 additions and 8 deletions

View file

@ -153,6 +153,12 @@ struct _GstH264DecoderPrivate
/* Return value from output_picture() */
GstFlowReturn last_flow;
/* Latency report params */
guint32 max_reorder_count;
guint32 last_reorder_frame_number;
gint fps_n;
gint fps_d;
};
typedef struct
@ -405,6 +411,17 @@ gst_h264_decoder_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_h264_decoder_reset_latency_infos (GstH264Decoder * self)
{
GstH264DecoderPrivate *priv = self->priv;
priv->max_reorder_count = 0;
priv->last_reorder_frame_number = 0;
priv->fps_n = 25;
priv->fps_d = 1;
}
static void
gst_h264_decoder_reset (GstH264Decoder * self)
{
@ -420,6 +437,8 @@ gst_h264_decoder_reset (GstH264Decoder * self)
priv->height = 0;
priv->nal_length_size = 4;
priv->last_flow = GST_FLOW_OK;
gst_h264_decoder_reset_latency_infos (self);
}
static gboolean
@ -1290,6 +1309,9 @@ gst_h264_decoder_parse_slice (GstH264Decoder * self, GstH264NalUnit * nalu)
gst_h264_picture_unref (picture);
return ret;
}
priv->last_reorder_frame_number++;
picture->reorder_frame_number = priv->last_reorder_frame_number;
}
/* This allows accessing the frame from the picture. */
@ -1797,6 +1819,28 @@ gst_h264_decoder_do_output_picture (GstH264Decoder * self,
}
#endif
if (priv->last_reorder_frame_number > picture->reorder_frame_number) {
guint64 diff = priv->last_reorder_frame_number -
picture->reorder_frame_number;
guint64 total_delay = diff + priv->preferred_output_delay;
if (diff > priv->max_reorder_count && total_delay < G_MAXUINT32) {
GstClockTime latency;
priv->max_reorder_count = (guint32) diff;
latency = gst_util_uint64_scale_int (GST_SECOND * total_delay,
priv->fps_d, priv->fps_n);
if (latency != G_MAXUINT64) {
GST_DEBUG_OBJECT (self, "Updating latency to %" GST_TIME_FORMAT
", reorder count: %" G_GUINT64_FORMAT ", output-delay: %u",
GST_TIME_ARGS (latency), diff, priv->preferred_output_delay);
gst_video_decoder_set_latency (GST_VIDEO_DECODER (self),
latency, latency);
}
}
}
frame = gst_video_decoder_get_frame (GST_VIDEO_DECODER (self),
GST_CODEC_PICTURE_FRAME_NUMBER (picture));
@ -2309,16 +2353,14 @@ gst_h264_decoder_set_latency (GstH264Decoder * self, const GstH264SPS * sps,
bump_level = get_bump_level (self);
if (bump_level != GST_H264_DPB_BUMP_NORMAL_LATENCY) {
if (sps->pic_order_cnt_type == 2) {
/* POC type 2 has does not allow frame reordering */
frames_delay = 0;
} else {
guint32 max_reorder_frames =
gst_h264_dpb_get_max_num_reorder_frames (priv->dpb);
frames_delay = MIN (max_dpb_size, max_reorder_frames);
}
GST_DEBUG_OBJECT (self, "Actual latency will be updated later");
frames_delay = 0;
}
priv->max_reorder_count = frames_delay;
priv->fps_n = fps_n;
priv->fps_d = fps_d;
/* Consider output delay wanted by subclass */
frames_delay += priv->preferred_output_delay;
@ -2433,6 +2475,8 @@ gst_h264_decoder_process_sps (GstH264Decoder * self, GstH264SPS * sps)
if (ret != GST_FLOW_OK)
return ret;
gst_h264_decoder_reset_latency_infos (self);
g_assert (klass->new_sequence);
if (klass->get_preferred_output_delay) {

View file

@ -153,6 +153,9 @@ struct _GstH264Picture
GstH264DecRefPicMarking dec_ref_pic_marking;
/* Set by decoder to trace the number of delayed output pictures */
guint32 reorder_frame_number;
/* For interlaced decoding */
gboolean second_field;
GstH264Picture * other_field;