lavf: Provide a monotonic timestamp to the outside world

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Harald Axmann 2012-12-02 19:27:21 +01:00 committed by Michael Niedermayer
parent 388241efa2
commit 2d74dea84f
4 changed files with 198 additions and 60 deletions

View File

@ -629,6 +629,13 @@ typedef struct AVIndexEntry {
*/
#define AV_DISPOSITION_ATTACHED_PIC 0x0400
/**
* Options for behavior on timestamp wrap detection.
*/
#define AV_PTS_WRAP_IGNORE 0 ///< ignore the wrap
#define AV_PTS_WRAP_ADD_OFFSET 1 ///< add the format specific offset on wrap detection
#define AV_PTS_WRAP_SUB_OFFSET -1 ///< subtract the format specific offset on wrap detection
/**
* Stream structure.
* New fields can be added to the end with minor version bumps.
@ -847,6 +854,23 @@ typedef struct AVStream {
*/
int64_t mux_ts_offset;
/**
* Internal data to check for wrapping of the time stamp
*/
int64_t pts_wrap_reference;
/**
* Options for behavior, when a wrap is detected.
*
* Defined by AV_PTS_WRAP_ values.
*
* If correction is enabled, there are two possibilities:
* If the first time stamp is near the wrap point, the wrap offset
* will be subtracted, which will create negative time stamps.
* Otherwise the offset will be added.
*/
int pts_wrap_behavior;
} AVStream;
#define AV_PROGRAM_RUNNING 1
@ -878,6 +902,9 @@ typedef struct AVProgram {
*/
int64_t start_time;
int64_t end_time;
int64_t pts_wrap_reference; ///< reference dts for wrap detection
int pts_wrap_behavior; ///< behavior on wrap detection
} AVProgram;
#define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present
@ -1169,6 +1196,13 @@ typedef struct AVFormatContext {
*/
unsigned int skip_initial_bytes;
/**
* Correct single timestamp overflows
* - encoding: unused
* - decoding: Set by user via AVOPtions (NO direct access)
*/
unsigned int correct_ts_overflow;
/*****************************************************************
* All fields below this line are not part of the public API. They
* may not be used outside of libavformat and can be changed and

View File

@ -73,6 +73,7 @@ static const AVOption options[]={
{"use_wallclock_as_timestamps", "use wallclock as timestamps", OFFSET(use_wallclock_as_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, D},
{"avoid_negative_ts", "shift timestamps to make them positive. 1 enables, 0 disables, default of -1 enables when required by target format.", OFFSET(avoid_negative_ts), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, E},
{"skip_initial_bytes", "skip initial bytes", OFFSET(skip_initial_bytes), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, D},
{"correct_ts_overflow", "correct single timestamp overflows", OFFSET(correct_ts_overflow), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, D},
{NULL},
};

View File

@ -78,6 +78,27 @@ static int is_relative(int64_t ts) {
return ts > (RELATIVE_TS_BASE - (1LL<<48));
}
/**
* Wrap a given time stamp, if there is an indication for an overflow
*
* @param st stream
* @param timestamp the time stamp to wrap
* @return resulting time stamp
*/
static int64_t wrap_timestamp(AVStream *st, int64_t timestamp)
{
if (st->pts_wrap_behavior != AV_PTS_WRAP_IGNORE && st->pts_wrap_bits < 64 &&
st->pts_wrap_reference != AV_NOPTS_VALUE && timestamp != AV_NOPTS_VALUE) {
if (st->pts_wrap_behavior == AV_PTS_WRAP_ADD_OFFSET &&
timestamp < st->pts_wrap_reference)
return timestamp + (1LL<<st->pts_wrap_bits);
else if (st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET &&
timestamp >= st->pts_wrap_reference)
return timestamp - (1LL<<st->pts_wrap_bits);
}
return timestamp;
}
/** head of registered input format linked list */
static AVInputFormat *first_iformat = NULL;
/** head of registered output format linked list */
@ -751,6 +772,8 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
}
st= s->streams[pkt->stream_index];
pkt->dts = wrap_timestamp(st, pkt->dts);
pkt->pts = wrap_timestamp(st, pkt->pts);
force_codec_ids(s, st);
@ -900,8 +923,67 @@ static AVPacketList *get_next_pkt(AVFormatContext *s, AVStream *st, AVPacketList
return NULL;
}
static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index)
{
if (s->correct_ts_overflow && st->pts_wrap_bits != 64 &&
st->pts_wrap_reference == AV_NOPTS_VALUE && st->first_dts != AV_NOPTS_VALUE) {
int i;
// reference time stamp should be 60 s before first time stamp
int64_t pts_wrap_reference = st->first_dts - av_rescale(60, st->time_base.den, st->time_base.num);
// if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset
int pts_wrap_behavior = (st->first_dts < (1LL<<st->pts_wrap_bits) - (1LL<<st->pts_wrap_bits-3)) ||
(st->first_dts < (1LL<<st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ?
AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET;
AVProgram *first_program = av_find_program_from_stream(s, NULL, stream_index);
if (!first_program) {
int default_stream_index = av_find_default_stream_index(s);
if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) {
for (i=0; i<s->nb_streams; i++) {
s->streams[i]->pts_wrap_reference = pts_wrap_reference;
s->streams[i]->pts_wrap_behavior = pts_wrap_behavior;
}
}
else {
st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference;
st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior;
}
}
else {
AVProgram *program = first_program;
while (program) {
if (program->pts_wrap_reference != AV_NOPTS_VALUE) {
pts_wrap_reference = program->pts_wrap_reference;
pts_wrap_behavior = program->pts_wrap_behavior;
break;
}
program = av_find_program_from_stream(s, program, stream_index);
}
// update every program with differing pts_wrap_reference
program = first_program;
while(program) {
if (program->pts_wrap_reference != pts_wrap_reference) {
for (i=0; i<program->nb_stream_indexes; i++) {
s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference;
s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior;
}
program->pts_wrap_reference = pts_wrap_reference;
program->pts_wrap_behavior = pts_wrap_behavior;
}
program = av_find_program_from_stream(s, program, stream_index);
}
}
return 1;
}
return 0;
}
static void update_initial_timestamps(AVFormatContext *s, int stream_index,
int64_t dts, int64_t pts)
int64_t dts, int64_t pts, AVPacket *pkt)
{
AVStream *st= s->streams[stream_index];
AVPacketList *pktl= s->parse_queue ? s->parse_queue : s->packet_buffer;
@ -943,6 +1025,16 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index,
pktl->pkt.dts= pts_buffer[0];
}
}
if (update_wrap_reference(s, st, stream_index) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
// correct first time stamps to negative values
st->first_dts = wrap_timestamp(st, st->first_dts);
st->cur_dts = wrap_timestamp(st, st->cur_dts);
pkt->dts = wrap_timestamp(st, pkt->dts);
pkt->pts = wrap_timestamp(st, pkt->pts);
pts = wrap_timestamp(st, pts);
}
if (st->start_time == AV_NOPTS_VALUE)
st->start_time = pts;
}
@ -1088,7 +1180,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
/* PTS = presentation timestamp */
if (pkt->dts == AV_NOPTS_VALUE)
pkt->dts = st->last_IP_pts;
update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts);
update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt);
if (pkt->dts == AV_NOPTS_VALUE)
pkt->dts = st->cur_dts;
@ -1125,7 +1217,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
if (pkt->pts == AV_NOPTS_VALUE)
pkt->pts = pkt->dts;
update_initial_timestamps(s, pkt->stream_index, pkt->pts,
pkt->pts);
pkt->pts, pkt);
if (pkt->pts == AV_NOPTS_VALUE)
pkt->pts = st->cur_dts;
pkt->dts = pkt->pts;
@ -1142,7 +1234,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
pkt->dts= st->pts_buffer[0];
}
if(st->codec->codec_id == AV_CODEC_ID_H264){ // we skipped it above so we try here
update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts); // this should happen on the first packet
update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt); // this should happen on the first packet
}
if(pkt->dts > st->cur_dts)
st->cur_dts = pkt->dts;
@ -1629,6 +1721,7 @@ int ff_add_index_entry(AVIndexEntry **index_entries,
int av_add_index_entry(AVStream *st,
int64_t pos, int64_t timestamp, int size, int distance, int flags)
{
timestamp = wrap_timestamp(st, timestamp);
return ff_add_index_entry(&st->index_entries, &st->nb_index_entries,
&st->index_entries_allocated_size, pos,
timestamp, size, distance, flags);
@ -1675,6 +1768,12 @@ int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp,
wanted_timestamp, flags);
}
static int64_t ff_read_timestamp(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit,
int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t ))
{
return wrap_timestamp(s->streams[stream_index], read_timestamp(s, stream_index, ppos, pos_limit));
}
int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags)
{
AVInputFormat *avif= s->iformat;
@ -1750,7 +1849,7 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
if(ts_min == AV_NOPTS_VALUE){
pos_min = s->data_offset;
ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
if (ts_min == AV_NOPTS_VALUE)
return -1;
}
@ -1766,7 +1865,7 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
pos_max = filesize - 1;
do{
pos_max -= step;
ts_max = read_timestamp(s, stream_index, &pos_max, pos_max + step);
ts_max = ff_read_timestamp(s, stream_index, &pos_max, pos_max + step, read_timestamp);
step += step;
}while(ts_max == AV_NOPTS_VALUE && pos_max >= step);
if (ts_max == AV_NOPTS_VALUE)
@ -1774,7 +1873,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= ff_read_timestamp(s, stream_index, &tmp_pos, INT64_MAX, read_timestamp);
if(tmp_ts == AV_NOPTS_VALUE)
break;
ts_max= tmp_ts;
@ -1821,7 +1920,7 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
pos= pos_limit;
start_pos= pos;
ts = read_timestamp(s, stream_index, &pos, INT64_MAX); //may pass pos_limit instead of -1
ts = ff_read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp); //may pass pos_limit instead of -1
if(pos == pos_max)
no_change++;
else
@ -1850,9 +1949,9 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
ts = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min : ts_max;
#if 0
pos_min = pos;
ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
pos_min++;
ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
ts_max = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
av_dlog(s, "pos=0x%"PRIx64" %s<=%s<=%s\n",
pos, av_ts2str(ts_min), av_ts2str(target_ts), av_ts2str(ts_max));
#endif
@ -3191,6 +3290,8 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
st->cur_dts = s->iformat ? RELATIVE_TS_BASE : 0;
st->first_dts = AV_NOPTS_VALUE;
st->probe_packets = MAX_PROBE_PACKETS;
st->pts_wrap_reference = AV_NOPTS_VALUE;
st->pts_wrap_behavior = AV_PTS_WRAP_IGNORE;
/* default pts setting is MPEG-like */
avpriv_set_pts_info(st, 33, 1, 90000);
@ -3230,6 +3331,8 @@ AVProgram *av_new_program(AVFormatContext *ac, int id)
program->discard = AVDISCARD_NONE;
}
program->id = id;
program->pts_wrap_reference = AV_NOPTS_VALUE;
program->pts_wrap_behavior = AV_PTS_WRAP_IGNORE;
program->start_time =
program->end_time = AV_NOPTS_VALUE;

View File

@ -1,51 +1,51 @@
#tb 0: 1/50
0, 0, 0, 1, 221184, 0xf48c94f6
0, 2, 2, 1, 221184, 0x89b625b2
0, 3, 3, 1, 221184, 0x37e04714
0, 4, 4, 1, 221184, 0x4f4c5224
0, 5, 5, 1, 221184, 0x9193c9f1
0, 6, 6, 1, 221184, 0x5d1a6197
0, 7, 7, 1, 221184, 0x40cd51e7
0, 8, 8, 1, 221184, 0xb2c1a729
0, 10, 10, 1, 221184, 0x998d6144
0, 11, 11, 1, 221184, 0xf5d52311
0, 12, 12, 1, 221184, 0xea9dd6bf
0, 13, 13, 1, 221184, 0x0e2ed854
0, 14, 14, 1, 221184, 0xe295ba58
0, 15, 15, 1, 221184, 0x8aedbb69
0, 16, 16, 1, 221184, 0x253c9aaa
0, 17, 17, 1, 221184, 0x5eaf9fb1
0, 18, 18, 1, 221184, 0xcdb5a0cb
0, 19, 19, 1, 221184, 0xcdb5a0cb
0, 20, 20, 1, 221184, 0x23f89994
0, 21, 21, 1, 221184, 0x23f89994
0, 22, 22, 1, 221184, 0x10dc98d6
0, 23, 23, 1, 221184, 0x799b9d98
0, 24, 24, 1, 221184, 0xb226996c
0, 25, 25, 1, 221184, 0x0ac59a42
0, 26, 26, 1, 221184, 0x87c2a654
0, 27, 27, 1, 221184, 0xf4c1a711
0, 28, 28, 1, 221184, 0xf60fa72e
0, 29, 29, 1, 221184, 0xc8f8b6fc
0, 30, 30, 1, 221184, 0xd709b813
0, 31, 31, 1, 221184, 0x5fdfb76b
0, 32, 32, 1, 221184, 0x5798b0aa
0, 33, 33, 1, 221184, 0xf572b1c3
0, 34, 34, 1, 221184, 0x14b0afdf
0, 35, 35, 1, 221184, 0x0a66b5b8
0, 36, 36, 1, 221184, 0xe316c620
0, 37, 37, 1, 221184, 0xbc76c5c2
0, 38, 38, 1, 221184, 0x77c7c5e5
0, 39, 39, 1, 221184, 0xfc7ac63e
0, 40, 40, 1, 221184, 0x05a29ffe
0, 41, 41, 1, 221184, 0x9bffbf6c
0, 42, 42, 1, 221184, 0x3c55be40
0, 43, 43, 1, 221184, 0x6f46c14e
0, 44, 44, 1, 221184, 0x9cf4ae70
0, 45, 45, 1, 221184, 0xf205b2f8
0, 46, 46, 1, 221184, 0x7180aff8
0, 47, 47, 1, 221184, 0x125eaffe
0, 48, 48, 1, 221184, 0x6970a32d
0, 49, 49, 1, 221184, 0xaea79f62
0, 50, 50, 1, 221184, 0x48d2a093
0, 51, 51, 1, 221184, 0x10a59eb5
0, 80, 80, 1, 221184, 0xf48c94f6
0, 82, 82, 1, 221184, 0x89b625b2
0, 83, 83, 1, 221184, 0x37e04714
0, 84, 84, 1, 221184, 0x4f4c5224
0, 85, 85, 1, 221184, 0x9193c9f1
0, 86, 86, 1, 221184, 0x5d1a6197
0, 87, 87, 1, 221184, 0x40cd51e7
0, 88, 88, 1, 221184, 0xb2c1a729
0, 90, 90, 1, 221184, 0x998d6144
0, 91, 91, 1, 221184, 0xf5d52311
0, 92, 92, 1, 221184, 0xea9dd6bf
0, 93, 93, 1, 221184, 0x0e2ed854
0, 94, 94, 1, 221184, 0xe295ba58
0, 95, 95, 1, 221184, 0x8aedbb69
0, 96, 96, 1, 221184, 0x253c9aaa
0, 97, 97, 1, 221184, 0x5eaf9fb1
0, 98, 98, 1, 221184, 0xcdb5a0cb
0, 99, 99, 1, 221184, 0xcdb5a0cb
0, 100, 100, 1, 221184, 0x23f89994
0, 101, 101, 1, 221184, 0x23f89994
0, 102, 102, 1, 221184, 0x10dc98d6
0, 103, 103, 1, 221184, 0x799b9d98
0, 104, 104, 1, 221184, 0xb226996c
0, 105, 105, 1, 221184, 0x0ac59a42
0, 106, 106, 1, 221184, 0x87c2a654
0, 107, 107, 1, 221184, 0xf4c1a711
0, 108, 108, 1, 221184, 0xf60fa72e
0, 109, 109, 1, 221184, 0xc8f8b6fc
0, 110, 110, 1, 221184, 0xd709b813
0, 111, 111, 1, 221184, 0x5fdfb76b
0, 112, 112, 1, 221184, 0x5798b0aa
0, 113, 113, 1, 221184, 0xf572b1c3
0, 114, 114, 1, 221184, 0x14b0afdf
0, 115, 115, 1, 221184, 0x0a66b5b8
0, 116, 116, 1, 221184, 0xe316c620
0, 117, 117, 1, 221184, 0xbc76c5c2
0, 118, 118, 1, 221184, 0x77c7c5e5
0, 119, 119, 1, 221184, 0xfc7ac63e
0, 120, 120, 1, 221184, 0x05a29ffe
0, 121, 121, 1, 221184, 0x9bffbf6c
0, 122, 122, 1, 221184, 0x3c55be40
0, 123, 123, 1, 221184, 0x6f46c14e
0, 124, 124, 1, 221184, 0x9cf4ae70
0, 125, 125, 1, 221184, 0xf205b2f8
0, 126, 126, 1, 221184, 0x7180aff8
0, 127, 127, 1, 221184, 0x125eaffe
0, 128, 128, 1, 221184, 0x6970a32d
0, 129, 129, 1, 221184, 0xaea79f62
0, 130, 130, 1, 221184, 0x48d2a093
0, 131, 131, 1, 221184, 0x10a59eb5