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

Harald Axmann harald.axmann at hotmail.com
Mon Oct 29 17:17:09 CET 2012


Am 29.10.2012 02:46, schrieb Michael Niedermayer:
> On Mon, Oct 29, 2012 at 01:18:59AM +0100, Harald Axmann wrote:
>> But you mean for mpegts.c only, do you? Please see the attached 
> i meant utils.c, mpeg-ps at least can wrap too

I think a common fix is a little complex. E.g. programs seem to be TS 
specific. So the condition for the wrap is depending on the stream type. 
Than the index is filled from mpegts directly. So it is needed to check 
for the wrap there too. That's why I am stuck to mpegts again. I think 
mpegps should be fixed separately.

>
>> 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.
> that sounds good in principle. One change i would recommand is to
> subtract 1 minute from the first timestamp before using it as wrap
> reference. Just incase theres something wrong with the first timestamps
> so nothing gets wraped that should not.

Done.

> Another problem is that the timestamps are per program you cannot
> use a single reference per mpeg-ts file, you need one per program,
> they can use very different zero points. that is you need to put it
> in AVProgram if there are more than 1 programs.

I had a look at it, but saving the zero point in AVProgram seems not 
optimal, because there is no reference from the PES context yet. Instead 
I save the reference time stamp directly in the every PES context now. I 
use the first encountered PCR, if its PID matches the pcr_pid of the 
PES. If the pcr_pid is -1, I use any PCR, as it is implemented in 
mpegts_get_pcr.

> Is there some way to reproduce this problem with ffmpeg ?
> I dont think theres a reason for the int64max there but changing it
> to the correct filesize shouldnt make a difference

I think producing a test case for ffmpeg without side effects is hard. I 
am still trying to track the issue down.
-------------- next part --------------
diff --git a/lib/ffmpeg/libavformat/mpegts.c b/lib/ffmpeg/libavformat/mpegts.c
index 6da6db5..4718364 100644
--- a/lib/ffmpeg/libavformat/mpegts.c
+++ b/lib/ffmpeg/libavformat/mpegts.c
@@ -110,6 +110,7 @@ struct MpegTSContext {
 
     int64_t cur_pcr;    /**< used to estimate the exact PCR  */
     int pcr_incr;       /**< used to estimate the exact PCR  */
+    int pcr_pid;        /**< PID from the current PCR value  */
 
     /* data needed to handle file based ts */
     /** stop parsing loop                                    */
@@ -176,6 +177,7 @@ typedef struct PESContext {
     int extended_stream_id;
     int64_t pts, dts;
     int64_t ts_packet_pos; /**< position of first TS packet of this PES packet */
+    int64_t initial_ts;
     uint8_t header[MAX_PES_HEADER_SIZE];
     uint8_t *buffer;
     SLConfigDescr sl;
@@ -713,6 +715,13 @@ static uint64_t get_bits64(GetBitContext *gb, int bits)
     return ret;
 }
 
+static int64_t wrap_timestamp(PESContext *pes, int64_t timestamp)
+{
+    if (timestamp < pes->initial_ts - (60*pes->st->time_base.den))
+        return timestamp + (1LL<<pes->st->pts_wrap_bits);
+    return timestamp;
+}
+
 static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf, int buf_size)
 {
     GetBitContext gb;
@@ -768,9 +777,9 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf
     }
 
     if (dts != AV_NOPTS_VALUE)
-        pes->dts = dts;
+        pes->dts = wrap_timestamp(pes, dts);
     if (cts != AV_NOPTS_VALUE)
-        pes->pts = cts;
+        pes->pts = wrap_timestamp(pes, cts);
 
     if (sl->timestamp_len && sl->timestamp_res)
         avpriv_set_pts_info(pes->st, sl->timestamp_len, 1, sl->timestamp_res);
@@ -839,6 +848,11 @@ static int mpegts_push_data(MpegTSFilter *filter,
                     if (!pes->total_size)
                         pes->total_size = MAX_PES_PAYLOAD;
 
+                    /* get initial PES time stamp */
+                    if (pes->initial_ts == AV_NOPTS_VALUE && ts->cur_pcr != AV_NOPTS_VALUE &&
+                        (pes->pcr_pid < 0 || pes->pcr_pid == ts->pcr_pid))
+                        pes->initial_ts = ts->cur_pcr / 300;
+
                     /* allocate pes buffer */
                     pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE);
                     if (!pes->buffer)
@@ -903,12 +917,12 @@ static int mpegts_push_data(MpegTSFilter *filter,
                 pes->pts = AV_NOPTS_VALUE;
                 pes->dts = AV_NOPTS_VALUE;
                 if ((flags & 0xc0) == 0x80) {
-                    pes->dts = pes->pts = ff_parse_pes_pts(r);
+                    pes->dts = pes->pts = wrap_timestamp(pes, ff_parse_pes_pts(r));
                     r += 5;
                 } else if ((flags & 0xc0) == 0xc0) {
-                    pes->pts = ff_parse_pes_pts(r);
+                    pes->pts = wrap_timestamp(pes, ff_parse_pes_pts(r));
                     r += 5;
-                    pes->dts = ff_parse_pes_pts(r);
+                    pes->dts = wrap_timestamp(pes, ff_parse_pes_pts(r));
                     r += 5;
                 }
                 pes->extended_stream_id = -1;
@@ -991,6 +1005,7 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid)
     pes->state = MPEGTS_SKIP;
     pes->pts = AV_NOPTS_VALUE;
     pes->dts = AV_NOPTS_VALUE;
+    pes->initial_ts = AV_NOPTS_VALUE;
     tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes);
     if (!tss) {
         av_free(pes);
@@ -1676,6 +1691,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 +1744,16 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
         }
     }
 
+    /* fill initial PCR, which is contained in the adaption field */
+    if (has_adaptation && ts->cur_pcr == AV_NOPTS_VALUE) {
+        int64_t timestamp;
+        int pcr_l;
+        if (parse_pcr(&timestamp, &pcr_l, packet) == 0) {
+            ts->cur_pcr = timestamp * 300 + pcr_l;
+            ts->pcr_pid = pid;
+        }
+    }
+
     if (!has_payload)
         return 0;
     p = packet + 4;
@@ -1991,6 +2019,7 @@ static int mpegts_read_header(AVFormatContext *s,
     }
     ts->stream = s;
     ts->auto_guess = 0;
+    ts->cur_pcr = AV_NOPTS_VALUE;
 
     if (s->iformat == &ff_mpegts_demuxer) {
         /* normal demux */
@@ -2162,10 +2191,11 @@ static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
                               int64_t *ppos, int64_t pos_limit)
 {
     MpegTSContext *ts = s->priv_data;
+    PESContext *pes = (PESContext*)s->streams[stream_index]->priv_data;
     int64_t pos, timestamp;
     uint8_t buf[TS_PACKET_SIZE];
-    int pcr_l, pcr_pid = ((PESContext*)s->streams[stream_index]->priv_data)->pcr_pid;
-    int pid = ((PESContext*)s->streams[stream_index]->priv_data)->pid;
+    int pcr_l, pcr_pid = pes->pcr_pid;
+    int pid = pes->pid;
     pos = ((*ppos  + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47;
     while(pos < pos_limit) {
         if (avio_seek(s->pb, pos, SEEK_SET) < 0)
@@ -2181,12 +2211,12 @@ 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;
-            return timestamp;
+            return wrap_timestamp(pes, timestamp);
         }
         if ((pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pid) &&
             parse_timestamp(&timestamp, buf) == 0) {
             *ppos = pos;
-            return timestamp;
+            return wrap_timestamp(pes, timestamp);
         }
         pos += ts->raw_packet_size;
     }
diff --git a/lib/ffmpeg/libavformat/utils.c b/lib/ffmpeg/libavformat/utils.c
index 63f89dd..5e65971 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