diff options
author | Harald Axmann <harald.axmann@hotmail.com> | 2012-12-02 19:27:21 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-12-15 21:28:45 +0100 |
commit | 2d74dea84f3d2dea04c77a9c02b01efab4d03a3b (patch) | |
tree | d0ae909ab717970874fc3b0f1dedf420a4f17b31 | |
parent | 388241efa2dfc4937fa5c9940ed0bc078e484b9d (diff) | |
download | ffmpeg-2d74dea84f3d2dea04c77a9c02b01efab4d03a3b.tar.gz |
lavf: Provide a monotonic timestamp to the outside world
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | libavformat/avformat.h | 34 | ||||
-rw-r--r-- | libavformat/options_table.h | 1 | ||||
-rw-r--r-- | libavformat/utils.c | 123 | ||||
-rw-r--r-- | tests/ref/fate/nuv-rtjpeg-fh | 100 |
4 files changed, 198 insertions, 60 deletions
diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 7500881330..c907d4e961 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -630,6 +630,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. * Removal, reordering and changes to existing fields require a major @@ -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 diff --git a/libavformat/options_table.h b/libavformat/options_table.h index 84fb5eeff9..300334f39b 100644 --- a/libavformat/options_table.h +++ b/libavformat/options_table.h @@ -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}, }; diff --git a/libavformat/utils.c b/libavformat/utils.c index 596253b0f2..f627f884b0 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -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; diff --git a/tests/ref/fate/nuv-rtjpeg-fh b/tests/ref/fate/nuv-rtjpeg-fh index 151ef881b2..beb6ccde06 100644 --- a/tests/ref/fate/nuv-rtjpeg-fh +++ b/tests/ref/fate/nuv-rtjpeg-fh @@ -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 |