[FFmpeg-devel] [RFC] mpegts: Provide a monotonic timestamp to the outside world

Harald Axmann harald.axmann at hotmail.com
Mon Oct 29 01:18:59 CET 2012


Am 26.10.2012 02:00, schrieb Michael Niedermayer:
> I think the easiest way to support a single wrap is to fix the
> output from ->read_timestamp() and ->read_packet() so it doesnt wrap.
> This fixup should also not change the lower bits that are known, just
> fill in the higher ones so as to avoid wraping.

But you mean for mpegts.c only, do you? Please see the attached patch 
against current XBMC FFmpeg version, if I got it right. I am again 
saving the first PCR, but instead of substracting it, I add 1<<33 if I 
encounter a time stamp below the first PCR, which I consider as the 
condition for a wrap.

At the end of the patch you also see a change to utils.c, where I 
supplied the file size as maximum position for time stamp reading. Is 
there a point for doing it in the original way? The reason for the 
change is, that there is possibly a bug in current XBMC or the PVR 
addon, where a read from a position after the file end seems to be 
possible, resulting in wrong maximum time stamps and again seeking problems.
-------------- next part --------------
diff --git a/lib/ffmpeg/libavformat/mpegts.c b/lib/ffmpeg/libavformat/mpegts.c
index 6da6db5..1bf34cb 100644
--- a/lib/ffmpeg/libavformat/mpegts.c
+++ b/lib/ffmpeg/libavformat/mpegts.c
@@ -108,6 +108,9 @@ struct MpegTSContext {
     /** compute exact PCR for each transport stream packet   */
     int mpeg2ts_compute_pcr;
 
+    int64_t initial_ts; /**< save the first time stamp       */
+    int64_t ts_wrap;    /**< maximum possible time stamp     */
+
     int64_t cur_pcr;    /**< used to estimate the exact PCR  */
     int pcr_incr;       /**< used to estimate the exact PCR  */
 
@@ -716,6 +719,7 @@ static uint64_t get_bits64(GetBitContext *gb, int bits)
 static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf, int buf_size)
 {
     GetBitContext gb;
+    MpegTSContext *ts = pes->ts;
     int au_start_flag = 0, au_end_flag = 0, ocr_flag = 0, idle_flag = 0;
     int padding_flag = 0, padding_bits = 0, inst_bitrate_flag = 0;
     int dts_flag = -1, cts_flag = -1;
@@ -767,10 +771,16 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf
             skip_bits_long(&gb, sl->inst_bitrate_len);
     }
 
-    if (dts != AV_NOPTS_VALUE)
+    if (dts != AV_NOPTS_VALUE) {
+        if (dts < ts->initial_ts)
+            dts += ts->ts_wrap;
         pes->dts = dts;
-    if (cts != AV_NOPTS_VALUE)
+    }
+    if (cts != AV_NOPTS_VALUE) {
+        if (cts < ts->initial_ts)
+            cts += ts->ts_wrap;
         pes->pts = cts;
+    }
 
     if (sl->timestamp_len && sl->timestamp_res)
         avpriv_set_pts_info(pes->st, sl->timestamp_len, 1, sl->timestamp_res);
@@ -911,6 +921,10 @@ static int mpegts_push_data(MpegTSFilter *filter,
                     pes->dts = ff_parse_pes_pts(r);
                     r += 5;
                 }
+                if (pes->dts < ts->initial_ts)
+                    pes->dts += ts->ts_wrap;
+                if (pes->pts < ts->initial_ts)
+                    pes->pts += ts->ts_wrap;
                 pes->extended_stream_id = -1;
                 if (flags & 0x01) { /* PES extension */
                     pes_ext = *r++;
@@ -1676,6 +1690,9 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
     }
 }
 
+/* get PCR from TS header */
+static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, const uint8_t *packet);
+
 /* handle one TS packet */
 static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
 {
@@ -1726,6 +1743,14 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
         }
     }
 
+    /* fill initial PCR, which is contained in the adaption field */
+    if (has_adaptation && ts->initial_ts == AV_NOPTS_VALUE) {
+        int64_t timestamp;
+        int pcr_l;
+        if (parse_pcr(&timestamp, &pcr_l, packet) == 0)
+            ts->initial_ts = timestamp;
+    }
+
     if (!has_payload)
         return 0;
     p = packet + 4;
@@ -1991,6 +2016,8 @@ static int mpegts_read_header(AVFormatContext *s,
     }
     ts->stream = s;
     ts->auto_guess = 0;
+    ts->ts_wrap = (1LL << 33);
+    ts->initial_ts = AV_NOPTS_VALUE;
 
     if (s->iformat == &ff_mpegts_demuxer) {
         /* normal demux */
@@ -2181,11 +2208,15 @@ static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
         if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
             parse_pcr(&timestamp, &pcr_l, buf) == 0) {
             *ppos = pos;
+            if (timestamp < ts->initial_ts)
+                timestamp += ts->ts_wrap;
             return timestamp;
         }
         if ((pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pid) &&
             parse_timestamp(&timestamp, buf) == 0) {
             *ppos = pos;
+            if (timestamp < ts->initial_ts)
+                timestamp += ts->ts_wrap;
             return timestamp;
         }
         pos += ts->raw_packet_size;
diff --git a/lib/ffmpeg/libavformat/utils.c b/lib/ffmpeg/libavformat/utils.c
index 63f89dd..87c1a62 100644
--- a/lib/ffmpeg/libavformat/utils.c
+++ b/lib/ffmpeg/libavformat/utils.c
@@ -1713,7 +1713,7 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
 
         for(;;){
             int64_t tmp_pos= pos_max + 1;
-            int64_t tmp_ts= read_timestamp(s, stream_index, &tmp_pos, INT64_MAX);
+            int64_t tmp_ts= read_timestamp(s, stream_index, &tmp_pos, filesize);
             if(tmp_ts == AV_NOPTS_VALUE)
                 break;
             ts_max= tmp_ts;


More information about the ffmpeg-devel mailing list