[FFmpeg-devel] [RFC] mpegts: Provide a monotonic timestamp to the outside world
Harald Axmann
harald.axmann at hotmail.com
Sun Oct 21 23:36:36 CEST 2012
Hello,
I am using XBMC with PVR extension and came across the issue concerning
PCR wraps in TS recordings, as already mentioned by [1] and [2] for
example. After some discussion on XBMC's Github page Joakim Plate came
up with the idea, to patch all the time stamps directly on demuxing, so
that the outside world will see a monotonic time stamp starting at zero
[3]. I have implemented this approach and successfully tested it with a
couple of recordings. Please see the attached patch, which is also
available on Github [4]. It only deals with mpegts, since I have not
found any mpegtsraw material for testing.
Could you please have a look at it?
Thanks & kind regards,
Harald Axmann
[1] http://ffmpeg.org/pipermail/ffmpeg-devel/2012-August/129660.html
[2] http://ffmpeg.org/pipermail/ffmpeg-devel/2012-August/129632.html
[3] https://github.com/xbmc/xbmc/pull/1509
[4]
https://github.com/axmhari/FFmpeg/commit/1398b555981f6dd79a0b59cd374f3753117f0c60
-------------- next part --------------
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 33a0eaf..f4c0162 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -105,6 +105,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_mask; /**< mask for the time stamp */
+
int64_t cur_pcr; /**< used to estimate the exact PCR */
int pcr_incr; /**< used to estimate the exact PCR */
@@ -719,6 +722,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;
@@ -772,9 +776,9 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf
}
if (dts != AV_NOPTS_VALUE)
- pes->dts = dts;
+ pes->dts = (dts - ts->initial_ts) & ts->ts_mask;
if (cts != AV_NOPTS_VALUE)
- pes->pts = cts;
+ pes->pts = (cts - ts->initial_ts) & ts->ts_mask;
if (sl->timestamp_len && sl->timestamp_res)
avpriv_set_pts_info(pes->st, sl->timestamp_len, 1, sl->timestamp_res);
@@ -916,6 +920,8 @@ static int mpegts_push_data(MpegTSFilter *filter,
pes->dts = ff_parse_pes_pts(r);
r += 5;
}
+ pes->dts = (pes->dts - ts->initial_ts) & ts->ts_mask;
+ pes->pts = (pes->pts - ts->initial_ts) & ts->ts_mask;
pes->extended_stream_id = -1;
if (flags & 0x01) { /* PES extension */
pes_ext = *r++;
@@ -1680,6 +1686,10 @@ 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)
{
@@ -1730,6 +1740,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;
@@ -1947,6 +1965,8 @@ static int mpegts_read_header(AVFormatContext *s)
}
ts->stream = s;
ts->auto_guess = 0;
+ ts->ts_mask = (1LL << 33) - 1;
+ ts->initial_ts = AV_NOPTS_VALUE;
if (s->iformat == &ff_mpegts_demuxer) {
/* normal demux */
@@ -2134,6 +2154,7 @@ static av_unused 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) {
+ timestamp = (timestamp - ts->initial_ts) & ts->ts_mask;
*ppos = pos;
return timestamp;
}
More information about the ffmpeg-devel
mailing list