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

Reply via email to