videodecoder: finetune missing timestamp estimating

Monitor for reordered output timestamps, and then avoid oldest DTS
as PTS approach, and try for an oldest PTS as out PTS approach,
if at least all valid PTS available.

Avoids bogus estimating upon sparse available input PTS, and tries
to handle all-keyframe input, or input PTS which are actually DTS.
This commit is contained in:
Mark Nauwelaerts 2012-10-10 15:04:07 +02:00
parent 80e4f3e912
commit 706498cb6e
2 changed files with 49 additions and 2 deletions

View file

@ -352,6 +352,7 @@ struct _GstVideoDecoderPrivate
GstClockTime last_timestamp_out;
/* incoming pts - dts */
GstClockTime pts_delta;
gboolean reordered_output;
/* reverse playback */
/* collect input */
@ -1620,6 +1621,7 @@ gst_video_decoder_reset (GstVideoDecoder * decoder, gboolean full)
gst_tag_list_unref (priv->tags);
priv->tags = NULL;
priv->tags_changed = FALSE;
priv->reordered_output = FALSE;
}
priv->discont = TRUE;
@ -2174,13 +2176,51 @@ gst_video_decoder_prepare_finish_frame (GstVideoDecoder *
/* and set if needed;
* valid delta means we have reasonable DTS input */
if (!GST_CLOCK_TIME_IS_VALID (frame->pts) && !seen_none &&
/* also, if we ended up reordered, means this approach is conflicting
* with some sparse existing PTS, and so it does not work out */
if (!priv->reordered_output &&
!GST_CLOCK_TIME_IS_VALID (frame->pts) && !seen_none &&
GST_CLOCK_TIME_IS_VALID (priv->pts_delta)) {
frame->pts = min_ts + priv->pts_delta;
GST_DEBUG_OBJECT (decoder,
"no valid PTS, using oldest DTS %" GST_TIME_FORMAT,
GST_TIME_ARGS (frame->pts));
}
/* some more maintenance, ts2 holds PTS */
min_ts = GST_CLOCK_TIME_NONE;
seen_none = FALSE;
for (l = priv->frames; l; l = l->next) {
GstVideoCodecFrame *tmp = l->data;
if (!GST_CLOCK_TIME_IS_VALID (tmp->abidata.ABI.ts2)) {
seen_none = TRUE;
continue;
}
if (!GST_CLOCK_TIME_IS_VALID (min_ts) || tmp->abidata.ABI.ts2 < min_ts) {
min_ts = tmp->abidata.ABI.ts2;
oframe = tmp;
}
}
/* save a ts if needed */
if (oframe && oframe != frame) {
oframe->abidata.ABI.ts2 = frame->abidata.ABI.ts2;
}
/* if we detected reordered output, then PTS are void,
* however those were obtained; bogus input, subclass etc */
if (priv->reordered_output && !seen_none) {
GST_DEBUG_OBJECT (decoder, "invaliding PTS");
frame->pts = GST_CLOCK_TIME_NONE;
}
if (!GST_CLOCK_TIME_IS_VALID (frame->pts) && !seen_none) {
frame->pts = min_ts;
GST_DEBUG_OBJECT (decoder,
"no valid PTS, using oldest PTS %" GST_TIME_FORMAT,
GST_TIME_ARGS (frame->pts));
}
}
@ -2202,6 +2242,7 @@ gst_video_decoder_prepare_finish_frame (GstVideoDecoder *
"decreasing timestamp (%" GST_TIME_FORMAT " < %"
GST_TIME_FORMAT ")",
GST_TIME_ARGS (frame->pts), GST_TIME_ARGS (priv->last_timestamp_out));
priv->reordered_output = TRUE;
}
}
@ -2590,9 +2631,11 @@ gst_video_decoder_decode_frame (GstVideoDecoder * decoder,
frame->pts = GST_BUFFER_PTS (frame->input_buffer);
frame->dts = GST_BUFFER_DTS (frame->input_buffer);
frame->duration = GST_BUFFER_DURATION (frame->input_buffer);
frame->abidata.ABI.ts = frame->dts;
/* For keyframes, PTS = DTS */
/* FIXME upstream can be quite wrong about the keyframe aspect,
* so we could be going off here as well,
* maybe let subclass decide if it really is/was a keyframe */
if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
if (!GST_CLOCK_TIME_IS_VALID (frame->pts)) {
frame->pts = frame->dts;
@ -2605,6 +2648,9 @@ gst_video_decoder_decode_frame (GstVideoDecoder * decoder,
}
}
frame->abidata.ABI.ts = frame->dts;
frame->abidata.ABI.ts2 = frame->pts;
GST_LOG_OBJECT (decoder, "PTS %" GST_TIME_FORMAT ", DTS %" GST_TIME_FORMAT,
GST_TIME_ARGS (frame->pts), GST_TIME_ARGS (frame->dts));
GST_LOG_OBJECT (decoder, "dist %d", frame->distance_from_sync);

View file

@ -249,6 +249,7 @@ struct _GstVideoCodecFrame
union {
struct {
GstClockTime ts;
GstClockTime ts2;
} ABI;
void *padding[GST_PADDING_LARGE];
} abidata;