From 706498cb6ea5ccd5395f715f81200e70d3193d4a Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 10 Oct 2012 15:04:07 +0200 Subject: [PATCH] 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. --- gst-libs/gst/video/gstvideodecoder.c | 50 ++++++++++++++++++++++++++++++++++-- gst-libs/gst/video/gstvideoutils.h | 1 + 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/video/gstvideodecoder.c b/gst-libs/gst/video/gstvideodecoder.c index 788ac21..4292a9c 100644 --- a/gst-libs/gst/video/gstvideodecoder.c +++ b/gst-libs/gst/video/gstvideodecoder.c @@ -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); diff --git a/gst-libs/gst/video/gstvideoutils.h b/gst-libs/gst/video/gstvideoutils.h index a3ff4f9..63833e2 100644 --- a/gst-libs/gst/video/gstvideoutils.h +++ b/gst-libs/gst/video/gstvideoutils.h @@ -249,6 +249,7 @@ struct _GstVideoCodecFrame union { struct { GstClockTime ts; + GstClockTime ts2; } ABI; void *padding[GST_PADDING_LARGE]; } abidata; -- 2.7.4