From: Michael Niedermayer <[email protected]> Additional fixes by Nigel Touati-Evans <[email protected]>. The method guess_ni_flag needs to divide timestamps in the index by sample_size, if it is set in order to compare different streams correctly.
Bug-Id: 666 CC: [email protected] Sample-Id: yet-another-broken-interleaved-avi.avi Signed-off-by: Vittorio Giovara <[email protected]> --- No better bug number for the issue at hand. This fixes desync for badly interleaved files, such as the one provided, in mpv and possibly other players. Thanks to wm4 for testing this patch and confirming it fixes the bug. Vittorio libavformat/avidec.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/libavformat/avidec.c b/libavformat/avidec.c index f48c441..55ef9d5 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -1313,6 +1313,8 @@ static int guess_ni_flag(AVFormatContext *s) int64_t last_start = 0; int64_t first_end = INT64_MAX; int64_t oldpos = avio_tell(s->pb); + int *idx; + int64_t min_pos, pos; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; @@ -1336,7 +1338,58 @@ static int guess_ni_flag(AVFormatContext *s) first_end = st->index_entries[n - 1].pos; } avio_seek(s->pb, oldpos, SEEK_SET); - return last_start > first_end; + + if (last_start > first_end) + return 1; + + idx = av_mallocz_array(s->nb_streams, sizeof(*idx)); + if (!idx) + return 0; + + for (min_pos = pos = 0; min_pos != INT64_MAX; pos = min_pos + 1LU) { + int64_t max_dts = INT64_MIN / 2, min_dts= INT64_MAX / 2; + int64_t max_buffer = 0; + min_pos = INT64_MAX; + + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + AVIStream *ast = st->priv_data; + int n = st->nb_index_entries; + while (idx[i] < n && st->index_entries[idx[i]].pos < pos) + idx[i]++; + if (idx[i] < n) { + min_dts = FFMIN(min_dts, + av_rescale_q(st->index_entries[idx[i]].timestamp / + FFMAX(ast->sample_size, 1), + st->time_base, AV_TIME_BASE_Q)); + min_pos = FFMIN(min_pos, st->index_entries[idx[i]].pos); + } + } + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + AVIStream *ast = st->priv_data; + + if (idx[i] && min_dts != INT64_MAX / 2) { + int64_t dts; + dts = av_rescale_q(st->index_entries[idx[i] - 1].timestamp / + FFMAX(ast->sample_size, 1), + st->time_base, AV_TIME_BASE_Q); + max_dts = FFMAX(max_dts, dts); + max_buffer = FFMAX(max_buffer, + av_rescale(dts - min_dts, + st->codec->bit_rate, + AV_TIME_BASE)); + } + } + if (max_dts - min_dts > 2 * AV_TIME_BASE || + max_buffer > 1024 * 1024 * 8 * 8) { + av_free(idx); + return 1; + } + } + av_free(idx); + return 0; + } static int avi_load_index(AVFormatContext *s) -- 1.8.3.4 (Apple Git-47) _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
