[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(×tamp, &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(×tamp, &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(×tamp, 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