Presently the mpegts demuxer passes the timestamps from received packets directly to the output AVPackets. 2^33 / 90000 seconds is about 26.5 hours at which point applications start having a fit, and that's assuming timestamps begin at time 0.
So here's a first revision of a patch to fix that issue. Improvements possible: * In its current form intended for continuous sources like over-the-air receivers and multicast sources. When used on files there will be problems with seeking. * Constants such as 2^33 could be turned into macros for readability
>From d06a3bd39fc4f01b9ce6132d80634dd31be7b1aa Mon Sep 17 00:00:00 2001 From: DHE <g...@dehacked.net> Date: Mon, 30 May 2016 18:31:43 -0400 Subject: [PATCH] libavformat/mpegts: Prevent wrapping of PTS & DTS --- libavformat/mpegts.c | 56 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index 7d78c41..a4d6bce 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -237,6 +237,10 @@ typedef struct PESContext { int extended_stream_id; uint8_t stream_id; int64_t pts, dts; + /* for makings pts/dts consistent on long-running feeds */ + int64_t last_dts; + unsigned int dts_wraps; + int64_t ts_packet_pos; /**< position of first TS packet of this PES packet */ uint8_t header[MAX_PES_HEADER_SIZE]; AVBufferRef *buffer; @@ -341,6 +345,39 @@ static void set_pcr_pid(AVFormatContext *s, unsigned int programid, unsigned int } } +static void fix_pts_dts(PESContext *pes) { + int64_t currdts; + + if (pes->last_dts == AV_NOPTS_VALUE) { + pes->last_dts = pes->dts; + return; + } + + // calculate the value we use for measurements against the last good value + currdts = pes->dts + (1ULL << 33) * pes->dts_wraps; + + if (currdts < pes->last_dts) { + /* While wrapping backwards should never happen unless we overflow, bad + * input does happen. Don't wrap if the reverse in timestamps is small. + * I have selected 90000 (1 second) semi-arbitrarily. + */ + if ((pes->last_dts - currdts) < 90000) { + pes->last_dts = currdts; + return; + } + currdts += 1ULL << 33; + pes->dts_wraps++; + av_log(pes->ts->stream, AV_LOG_INFO, "Stream timestamps wrapping\n"); + } + + pes->last_dts = pes->dts = currdts; + + // Now fix the pts in the much the same way. It is always true that dts <= pts + pes->pts += (1ULL << 33) * pes->dts_wraps; + while (pes->pts < pes->dts) + pes->pts += 1ULL << 33; +} + /** * @brief discard_pid() decides if the pid is to be discarded according * to caller's programs selection @@ -1136,6 +1173,7 @@ skip: pes->dts = ff_parse_pes_pts(r); r += 5; } + fix_pts_dts(pes); pes->extended_stream_id = -1; if (flags & 0x01) { /* PES extension */ pes_ext = *r++; @@ -1268,14 +1306,16 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid) pes = av_mallocz(sizeof(PESContext)); if (!pes) return 0; - pes->ts = ts; - pes->stream = ts->stream; - pes->pid = pid; - pes->pcr_pid = pcr_pid; - pes->state = MPEGTS_SKIP; - pes->pts = AV_NOPTS_VALUE; - pes->dts = AV_NOPTS_VALUE; - tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); + pes->ts = ts; + pes->stream = ts->stream; + pes->pid = pid; + pes->pcr_pid = pcr_pid; + pes->state = MPEGTS_SKIP; + pes->pts = AV_NOPTS_VALUE; + pes->dts = AV_NOPTS_VALUE; + pes->last_dts = AV_NOPTS_VALUE; + pes->dts_wraps = 0; + tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); if (!tss) { av_free(pes); return 0; -- 1.8.4.1
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel