From 24408bce96e85a4788e551d250fc2aa66537cdd2 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 10 Jan 2012 11:37:13 +0100 Subject: [PATCH] tsdemux: Handle rollover in PTS and DTS Also hands back-rollover which can happen with PTS --- gst/mpegtsdemux/tsdemux.c | 88 +++++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 13 deletions(-) diff --git a/gst/mpegtsdemux/tsdemux.c b/gst/mpegtsdemux/tsdemux.c index 118ffb598a..58f3a82743 100644 --- a/gst/mpegtsdemux/tsdemux.c +++ b/gst/mpegtsdemux/tsdemux.c @@ -63,6 +63,7 @@ #define PCR_SMALL 17775000 /* maximal PCR time */ #define PCR_MAX_VALUE (((((guint64)1)<<33) * 300) + 298) +#define PTS_DTS_MAX_VALUE (((guint64)1) << 33) /* seek to SEEK_TIMESTAMP_OFFSET before the desired offset and search then * either accurately or for the next timestamp @@ -72,6 +73,8 @@ GST_DEBUG_CATEGORY_STATIC (ts_demux_debug); #define GST_CAT_DEFAULT ts_demux_debug +#define ABSDIFF(a,b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) + static GQuark QUARK_TSDEMUX; static GQuark QUARK_PID; static GQuark QUARK_PCR; @@ -116,8 +119,15 @@ struct _TSDemuxStream GstBufferListIterator *currentit; GList *currentlist; - /* Current PTS for this stream */ + /* Current PTS/DTS for this stream */ GstClockTime pts; + GstClockTime dts; + /* Raw value of current PTS/DTS */ + guint64 raw_pts; + guint64 raw_dts; + /* Number of rollover seen for PTS/DTS (default:0) */ + guint nb_pts_rollover; + guint nb_dts_rollover; }; #define VIDEO_CAPS \ @@ -1229,7 +1239,13 @@ gst_ts_demux_stream_added (MpegTSBase * base, MpegTSBaseStream * bstream, /* Create the pad */ if (bstream->stream_type != 0xff) stream->pad = create_pad_for_stream (base, bstream, program); + stream->pts = GST_CLOCK_TIME_NONE; + stream->dts = GST_CLOCK_TIME_NONE; + stream->raw_pts = 0; + stream->raw_dts = 0; + stream->nb_pts_rollover = 0; + stream->nb_dts_rollover = 0; } stream->flow_return = GST_FLOW_OK; } @@ -1865,9 +1881,33 @@ gst_ts_demux_record_pts (GstTSDemux * demux, TSDemuxStream * stream, { MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; - GST_LOG ("pid 0x%04x pts:%" GST_TIME_FORMAT " at offset %" - G_GUINT64_FORMAT, bs->pid, - GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pts)), offset); + GST_LOG ("pid 0x%04x pts:%" G_GUINT64_FORMAT " at offset %" + G_GUINT64_FORMAT, bs->pid, pts, offset); + + if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (stream->pts) && + ABSDIFF (stream->raw_pts, pts) > 900000)) { + /* Detect rollover if diff > 10s */ + GST_LOG ("Detected rollover (previous:%" G_GUINT64_FORMAT " new:%" + G_GUINT64_FORMAT ")", stream->raw_pts, pts); + if (pts < stream->raw_pts) { + /* Forward rollover */ + GST_LOG ("Forward rollover, incrementing nb_pts_rollover"); + stream->nb_pts_rollover++; + } else { + /* Reverse rollover */ + GST_LOG ("Reverse rollover, decrementing nb_pts_rollover"); + stream->nb_pts_rollover--; + } + } + + /* Compute PTS in GstClockTime */ + stream->raw_pts = pts; + stream->pts = + MPEGTIME_TO_GSTTIME (pts + stream->nb_pts_rollover * PTS_DTS_MAX_VALUE); + + GST_LOG ("pid 0x%04x Stored PTS %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")", + bs->pid, stream->raw_pts, GST_TIME_ARGS (stream->pts)); + if (G_UNLIKELY (demux->emit_statistics)) { GstStructure *st; @@ -1887,9 +1927,32 @@ gst_ts_demux_record_dts (GstTSDemux * demux, TSDemuxStream * stream, { MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; - GST_LOG ("pid 0x%04x dts:%" GST_TIME_FORMAT " at offset %" - G_GUINT64_FORMAT, bs->pid, - GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (dts)), offset); + GST_LOG ("pid 0x%04x dts:%" G_GUINT64_FORMAT " at offset %" + G_GUINT64_FORMAT, bs->pid, dts, offset); + + if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (stream->dts) && + ABSDIFF (stream->raw_dts, dts) > 900000)) { + /* Detect rollover if diff > 10s */ + GST_LOG ("Detected rollover (previous:%" G_GUINT64_FORMAT " new:%" + G_GUINT64_FORMAT ")", stream->raw_dts, dts); + if (dts < stream->raw_dts) { + /* Forward rollover */ + GST_LOG ("Forward rollover, incrementing nb_dts_rollover"); + stream->nb_dts_rollover++; + } else { + /* Reverse rollover */ + GST_LOG ("Reverse rollover, decrementing nb_dts_rollover"); + stream->nb_dts_rollover--; + } + } + + /* Compute DTS in GstClockTime */ + stream->raw_dts = dts; + stream->dts = + MPEGTIME_TO_GSTTIME (dts + stream->nb_dts_rollover * PTS_DTS_MAX_VALUE); + + GST_LOG ("pid 0x%04x Stored DTS %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")", + bs->pid, stream->raw_dts, GST_TIME_ARGS (stream->dts)); if (G_UNLIKELY (demux->emit_statistics)) { GstStructure *st; @@ -1939,7 +2002,6 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream) guint8 *data; guint32 length; guint64 bufferoffset; - GstClockTime time; PESParsingResult parseres; data = GST_BUFFER_DATA (stream->pendingbuffers[0]); @@ -1957,6 +2019,9 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream) goto discont; } + if (header.DTS != -1) + gst_ts_demux_record_dts (demux, stream, header.DTS, bufferoffset); + if (header.PTS != -1) { gst_ts_demux_record_pts (demux, stream, header.PTS, bufferoffset); @@ -1980,7 +2045,6 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream) time = calc_gsttime_from_pts (&demux->index_pcr, pts); #endif - stream->pts = time = MPEGTIME_TO_GSTTIME (header.PTS); GST_DEBUG_OBJECT (base, "stream PTS %" GST_TIME_FORMAT, GST_TIME_ARGS (stream->pts)); @@ -2012,12 +2076,10 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream) if (!GST_CLOCK_TIME_IS_VALID (base->in_gap)) base->in_gap = 0; - GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0]) = time + base->in_gap; + GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0]) = + stream->pts + base->in_gap; } - if (header.DTS != -1) - gst_ts_demux_record_dts (demux, stream, header.DTS, bufferoffset); - /* Remove PES headers */ GST_DEBUG ("Moving data forward by %d bytes", header.header_size); GST_BUFFER_DATA (stream->pendingbuffers[0]) += header.header_size;