From ad53c7f9ece7f95cd9538775fb6fd7a17eb1d301 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Wed, 7 Mar 2012 22:13:39 +0100 Subject: [PATCH] lavf: Add system to seperate relative timestamps from absolute ones. With this we can always know if a timestamp is based on added durations from an unknown origin or if it is based on a correct timestamp (and possibly added durations) This should fix some bugs where this distinction was mixed up. Signed-off-by: Michael Niedermayer --- ffmpeg.c | 1 + libavformat/utils.c | 56 ++++++++++++++++++++++++++++------------- tests/ref/lavf/wtv | 2 +- tests/ref/seek/lavf_wtv | 2 +- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index 609d1121fb..4714b616a7 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -4258,6 +4258,7 @@ static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const ch // FIXME: a more elegant solution is needed memcpy(st, ic->streams[i], sizeof(AVStream)); + st->cur_dts = 0; st->info = av_malloc(sizeof(*st->info)); memcpy(st->info, ic->streams[i]->info, sizeof(*st->info)); st->codec= avctx; diff --git a/libavformat/utils.c b/libavformat/utils.c index e4cc393c00..9df01339f4 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -72,6 +72,12 @@ const char *avformat_license(void) return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; } +#define RELATIVE_TS_BASE (INT64_MAX - (1LL<<32)) + +static int is_relative(int64_t ts) { + return ts > (RELATIVE_TS_BASE - (1LL<<32)); +} + /* fraction handling */ /** @@ -870,21 +876,23 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index, AVStream *st= s->streams[stream_index]; AVPacketList *pktl= s->parse_queue ? s->parse_queue : s->packet_buffer; - if(st->first_dts != AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE || st->cur_dts == AV_NOPTS_VALUE) + if(st->first_dts != AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE || st->cur_dts == AV_NOPTS_VALUE || is_relative(dts)) return; - st->first_dts= dts - st->cur_dts; + st->first_dts= dts - (st->cur_dts - RELATIVE_TS_BASE); st->cur_dts= dts; + if (is_relative(pts)) + pts += st->first_dts - RELATIVE_TS_BASE; + for(; pktl; pktl= get_next_pkt(s, st, pktl)){ if(pktl->pkt.stream_index != stream_index) continue; - //FIXME think more about this check - if(pktl->pkt.pts != AV_NOPTS_VALUE && pktl->pkt.pts == pktl->pkt.dts) - pktl->pkt.pts += st->first_dts; + if(is_relative(pktl->pkt.pts)) + pktl->pkt.pts += st->first_dts - RELATIVE_TS_BASE; - if(pktl->pkt.dts != AV_NOPTS_VALUE) - pktl->pkt.dts += st->first_dts; + if(is_relative(pktl->pkt.dts)) + pktl->pkt.dts += st->first_dts - RELATIVE_TS_BASE; if(st->start_time == AV_NOPTS_VALUE && pktl->pkt.pts != AV_NOPTS_VALUE) st->start_time= pktl->pkt.pts; @@ -897,7 +905,7 @@ static void update_initial_durations(AVFormatContext *s, AVStream *st, int stream_index, int duration) { AVPacketList *pktl= s->parse_queue ? s->parse_queue : s->packet_buffer; - int64_t cur_dts= 0; + int64_t cur_dts= RELATIVE_TS_BASE; if(st->first_dts != AV_NOPTS_VALUE){ cur_dts= st->first_dts; @@ -910,7 +918,7 @@ static void update_initial_durations(AVFormatContext *s, AVStream *st, } pktl= s->parse_queue ? s->parse_queue : s->packet_buffer; st->first_dts = cur_dts; - }else if(st->cur_dts) + }else if(st->cur_dts != RELATIVE_TS_BASE) return; for(; pktl; pktl= get_next_pkt(s, st, pktl)){ @@ -1308,15 +1316,17 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) { const int genpts = s->flags & AVFMT_FLAG_GENPTS; int eof = 0; + int ret; - if (!genpts) - return s->packet_buffer ? read_from_packet_buffer(&s->packet_buffer, + if (!genpts) { + ret = s->packet_buffer ? read_from_packet_buffer(&s->packet_buffer, &s->packet_buffer_end, pkt) : read_frame_internal(s, pkt); + goto return_packet; + } for (;;) { - int ret; AVPacketList *pktl = s->packet_buffer; if (pktl) { @@ -1337,9 +1347,11 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) /* read packet from packet buffer, if there is data */ if (!(next_pkt->pts == AV_NOPTS_VALUE && - next_pkt->dts != AV_NOPTS_VALUE && !eof)) - return read_from_packet_buffer(&s->packet_buffer, + next_pkt->dts != AV_NOPTS_VALUE && !eof)) { + ret = read_from_packet_buffer(&s->packet_buffer, &s->packet_buffer_end, pkt); + goto return_packet; + } } ret = read_frame_internal(s, pkt); @@ -1355,6 +1367,13 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) &s->packet_buffer_end)) < 0) return AVERROR(ENOMEM); } + +return_packet: + if (is_relative(pkt->dts)) + pkt->dts -= RELATIVE_TS_BASE; + if (is_relative(pkt->pts)) + pkt->pts -= RELATIVE_TS_BASE; + return ret; } /* XXX: suppress the packet queue */ @@ -1408,7 +1427,7 @@ void ff_read_frame_flush(AVFormatContext *s) st->parser = NULL; } st->last_IP_pts = AV_NOPTS_VALUE; - if(st->first_dts == AV_NOPTS_VALUE) st->cur_dts = 0; + if(st->first_dts == AV_NOPTS_VALUE) st->cur_dts = RELATIVE_TS_BASE; else st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */ st->reference_dts = AV_NOPTS_VALUE; @@ -1456,6 +1475,9 @@ int ff_add_index_entry(AVIndexEntry **index_entries, if((unsigned)*nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) return -1; + if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known + timestamp -= RELATIVE_TS_BASE; + entries = av_fast_realloc(*index_entries, index_entries_allocated_size, (*nb_index_entries + 1) * @@ -2479,7 +2501,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int64_t last = st->info->last_dts; if(pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && pkt->dts > last){ - double dts= pkt->dts * av_q2d(st->time_base); + double dts= (is_relative(pkt->dts) ? pkt->dts - RELATIVE_TS_BASE : pkt->dts) * av_q2d(st->time_base); int64_t duration= pkt->dts - last; // if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) @@ -2883,7 +2905,7 @@ AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c) but durations get some timestamps, formats with some unknown timestamps have their first few packets buffered and the timestamps corrected before they are returned to the user */ - st->cur_dts = 0; + st->cur_dts = s->iformat ? RELATIVE_TS_BASE : 0; st->first_dts = AV_NOPTS_VALUE; st->probe_packets = MAX_PROBE_PACKETS; diff --git a/tests/ref/lavf/wtv b/tests/ref/lavf/wtv index c101a3e58f..f0668a7d72 100644 --- a/tests/ref/lavf/wtv +++ b/tests/ref/lavf/wtv @@ -1,3 +1,3 @@ 7bd312f32538a14f248c2dff85394118 *./tests/data/lavf/lavf.wtv 413696 ./tests/data/lavf/lavf.wtv -./tests/data/lavf/lavf.wtv CRC=0xebced481 +./tests/data/lavf/lavf.wtv CRC=0x133216c1 diff --git a/tests/ref/seek/lavf_wtv b/tests/ref/seek/lavf_wtv index 2d6b95ca7a..20c0bb32ab 100644 --- a/tests/ref/seek/lavf_wtv +++ b/tests/ref/seek/lavf_wtv @@ -1,4 +1,4 @@ -ret: 0 st: 0 flags:1 dts:-0.040000 pts:-0.040000 pos: 2144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 2144 size: 24801 ret: 0 st:-1 flags:0 ts:-1.000000 ret: 0 st: 0 flags:1 dts: NOPTS pts: 0.000000 pos: 2144 size: 24801 ret:-1 st:-1 flags:1 ts: 1.894167