videodecoder: refactor and document finish_frame some more

* Move the in-flight iteration and handling code into the main block
* Document the intent a bit more

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4694>
This commit is contained in:
Edward Hervey 2023-05-07 09:27:16 +02:00 committed by GStreamer Marge Bot
parent bce9f3327d
commit 386a8dbae5

View file

@ -2976,7 +2976,9 @@ gst_video_decoder_prepare_finish_frame (GstVideoDecoder *
{ {
GstVideoDecoderPrivate *priv = decoder->priv; GstVideoDecoderPrivate *priv = decoder->priv;
GList *l, *events = NULL; GList *l, *events = NULL;
gboolean sync; gboolean sync, frames_without_dts, frames_without_pts;
GstClockTime min_dts, min_pts;
GstVideoCodecFrame *earliest_dts_frame, *earliest_pts_frame;
#ifndef GST_DISABLE_GST_DEBUG #ifndef GST_DISABLE_GST_DEBUG
GST_LOG_OBJECT (decoder, "n %d in %" G_GSIZE_FORMAT " out %" G_GSIZE_FORMAT, GST_LOG_OBJECT (decoder, "n %d in %" G_GSIZE_FORMAT " out %" G_GSIZE_FORMAT,
@ -3046,15 +3048,20 @@ gst_video_decoder_prepare_finish_frame (GstVideoDecoder *
GST_TIME_ARGS (frame->duration)); GST_TIME_ARGS (frame->duration));
} }
/* PTS is expected monotone ascending, /* The following code is to fix issues with PTS and DTS:
* so a good guess is lowest unsent DTS */ * * Because the input PTS and/or DTS was mis-used (using DTS as PTS, or PTS
{ * as DTS)
GstClockTime min_dts = GST_CLOCK_TIME_NONE; * * Because the input was missing PTS and/or DTS
GstClockTime min_pts = GST_CLOCK_TIME_NONE; *
GstVideoCodecFrame *earliest_dts_frame = NULL; * For that, we will collected 3 important information from the frames in
GstVideoCodecFrame *earliest_pts_frame = NULL; * flight:
gboolean frames_without_dts = FALSE; * * Whether all frames had a valid PTS or a valid DTS
gboolean frames_without_pts = FALSE; * * Which frame has the lowest PTS (and its value)
* * Which frame has the lowest DTS (And its value)
*/
frames_without_pts = frames_without_dts = FALSE;
min_dts = min_pts = GST_CLOCK_TIME_NONE;
earliest_pts_frame = earliest_dts_frame = NULL;
/* Check what is the earliest PTS and DTS in our pendings frames */ /* Check what is the earliest PTS and DTS in our pendings frames */
for (l = priv->frames.head; l; l = l->next) { for (l = priv->frames.head; l; l = l->next) {
@ -3087,10 +3094,14 @@ gst_video_decoder_prepare_finish_frame (GstVideoDecoder *
earliest_pts_frame->abidata.ABI.ts2 = frame->abidata.ABI.ts2; earliest_pts_frame->abidata.ABI.ts2 = frame->abidata.ABI.ts2;
} }
/* and set if needed; /* First attempt at recovering missing PTS:
* valid delta means we have reasonable DTS input */ * * If we figured out the PTS<->DTS delta (from a keyframe)
/* also, if we ended up reordered, means this approach is conflicting * * AND all frames have a valid DTS (i.e. it is not sparsely timestamped
* with some sparse existing PTS, and so it does not work out */ * input)
* * AND we are not dealing with ordering issues
*
* We can figure out the pts from the lowest DTS and the PTS<->DTS delta
*/
if (!priv->reordered_output && if (!priv->reordered_output &&
!GST_CLOCK_TIME_IS_VALID (frame->pts) && !frames_without_dts && !GST_CLOCK_TIME_IS_VALID (frame->pts) && !frames_without_dts &&
GST_CLOCK_TIME_IS_VALID (priv->pts_delta)) { GST_CLOCK_TIME_IS_VALID (priv->pts_delta)) {
@ -3100,10 +3111,8 @@ gst_video_decoder_prepare_finish_frame (GstVideoDecoder *
GST_TIME_ARGS (frame->pts)); GST_TIME_ARGS (frame->pts));
} }
} /* if we detected reordered output, then PTS are void, however those were
* obtained; bogus input, subclass etc */
/* if we detected reordered output, then PTS are void,
* however those were obtained; bogus input, subclass etc */
if (priv->reordered_output && !frames_without_pts) { if (priv->reordered_output && !frames_without_pts) {
GST_DEBUG_OBJECT (decoder, "invalidating PTS"); GST_DEBUG_OBJECT (decoder, "invalidating PTS");
frame->pts = GST_CLOCK_TIME_NONE; frame->pts = GST_CLOCK_TIME_NONE;
@ -3117,8 +3126,6 @@ gst_video_decoder_prepare_finish_frame (GstVideoDecoder *
"no valid PTS, using oldest PTS %" GST_TIME_FORMAT, "no valid PTS, using oldest PTS %" GST_TIME_FORMAT,
GST_TIME_ARGS (frame->pts)); GST_TIME_ARGS (frame->pts));
} }
}
if (frame->pts == GST_CLOCK_TIME_NONE) { if (frame->pts == GST_CLOCK_TIME_NONE) {
/* Last ditch timestamp guess: Just add the duration to the previous /* Last ditch timestamp guess: Just add the duration to the previous
@ -3145,17 +3152,15 @@ gst_video_decoder_prepare_finish_frame (GstVideoDecoder *
} }
} }
if (GST_CLOCK_TIME_IS_VALID (priv->last_timestamp_out)) { if (GST_CLOCK_TIME_IS_VALID (priv->last_timestamp_out) &&
if (frame->pts < priv->last_timestamp_out) { frame->pts < priv->last_timestamp_out) {
GST_WARNING_OBJECT (decoder, GST_WARNING_OBJECT (decoder,
"decreasing timestamp (%" GST_TIME_FORMAT " < %" "decreasing timestamp (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
GST_TIME_FORMAT ")",
GST_TIME_ARGS (frame->pts), GST_TIME_ARGS (priv->last_timestamp_out)); GST_TIME_ARGS (frame->pts), GST_TIME_ARGS (priv->last_timestamp_out));
priv->reordered_output = TRUE; priv->reordered_output = TRUE;
/* make it a bit less weird downstream */ /* make it a bit less weird downstream */
frame->pts = priv->last_timestamp_out; frame->pts = priv->last_timestamp_out;
} }
}
if (GST_CLOCK_TIME_IS_VALID (frame->pts)) if (GST_CLOCK_TIME_IS_VALID (frame->pts))
priv->last_timestamp_out = frame->pts; priv->last_timestamp_out = frame->pts;