From 58a25aeb8e69532aae6ed1762fe7e0b260990010 Mon Sep 17 00:00:00 2001 From: Sasi Inguva Date: Mon, 18 Dec 2017 15:31:16 -0800 Subject: [PATCH] lavf/mov.c: Guess video codec delay based on PTS while parsing MOV header. Signed-off-by: Sasi Inguva Signed-off-by: Michael Niedermayer --- libavformat/mov.c | 56 ++++++++++++++++++++++++++++++++ tests/fate/mov.mak | 7 ++++ tests/ref/fate/mov-guess-delay-1 | 3 ++ tests/ref/fate/mov-guess-delay-2 | 3 ++ tests/ref/fate/mov-guess-delay-3 | 3 ++ 5 files changed, 72 insertions(+) create mode 100644 tests/ref/fate/mov-guess-delay-1 create mode 100644 tests/ref/fate/mov-guess-delay-2 create mode 100644 tests/ref/fate/mov-guess-delay-3 diff --git a/libavformat/mov.c b/libavformat/mov.c index 28d60289aa..480e506370 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -3241,6 +3241,60 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns return *ctts_count; } +#define MAX_REORDER_DELAY 16 +static void mov_estimate_video_delay(MOVContext *c, AVStream* st) { + MOVStreamContext *msc = st->priv_data; + int ind; + int ctts_ind = 0; + int ctts_sample = 0; + int64_t pts_buf[MAX_REORDER_DELAY + 1]; // Circular buffer to sort pts. + int buf_start = 0; + int buf_size = 0; + int j, r, num_swaps; + + if (st->codecpar->video_delay <= 0 && msc->ctts_data && + st->codecpar->codec_id == AV_CODEC_ID_H264) { + st->codecpar->video_delay = 0; + for(ind = 0; ind < st->nb_index_entries && ctts_ind < msc->ctts_count; ++ind) { + if (buf_size == (MAX_REORDER_DELAY + 1)) { + // If circular buffer is full, then move the first element forward. + buf_start = (buf_start + 1) % buf_size; + } else { + ++buf_size; + } + + // Point j to the last elem of the buffer and insert the current pts there. + j = (buf_start + buf_size - 1) % buf_size; + pts_buf[j] = st->index_entries[ind].timestamp + msc->ctts_data[ctts_ind].duration; + + // The timestamps that are already in the sorted buffer, and are greater than the + // current pts, are exactly the timestamps that need to be buffered to output PTS + // in correct sorted order. + // Hence the video delay (which is the buffer size used to sort DTS and output PTS), + // can be computed as the maximum no. of swaps any particular timestamp needs to + // go through, to keep this buffer in sorted order. + num_swaps = 0; + while (j != buf_start) { + r = (j - 1 + buf_size) % buf_size; + if (pts_buf[j] < pts_buf[r]) { + FFSWAP(int64_t, pts_buf[j], pts_buf[r]); + ++num_swaps; + } + j = r; + } + st->codecpar->video_delay = FFMAX(st->codecpar->video_delay, num_swaps); + + ctts_sample++; + if (ctts_sample == msc->ctts_data[ctts_ind].count) { + ctts_ind++; + ctts_sample = 0; + } + } + av_log(c->fc, AV_LOG_DEBUG, "Setting codecpar->delay to %d for stream st: %d\n", + st->codecpar->video_delay, st->index); + } +} + static void mov_current_sample_inc(MOVStreamContext *sc) { sc->current_sample++; @@ -3897,6 +3951,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) // Fix index according to edit lists. mov_fix_index(mov, st); } + + mov_estimate_video_delay(mov, st); } static int test_same_origin(const char *src, const char *ref) { diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak index 19b01304fb..907dfa0b69 100644 --- a/tests/fate/mov.mak +++ b/tests/fate/mov.mak @@ -13,6 +13,9 @@ FATE_MOV = fate-mov-3elist \ fate-mov-elst-ends-betn-b-and-i \ fate-mov-frag-overlap \ fate-mov-bbi-elst-starts-b \ + fate-mov-guess-delay-1 \ + fate-mov-guess-delay-2 \ + fate-mov-guess-delay-3 \ FATE_MOV_FFPROBE = fate-mov-aac-2048-priming \ fate-mov-zombie \ @@ -82,3 +85,7 @@ fate-mov-spherical-mono: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries str fate-mov-gpmf-remux: CMD = md5 -i $(TARGET_SAMPLES)/mov/fake-gp-media-with-real-gpmf.mp4 -map 0 -c copy -fflags +bitexact -f mp4 fate-mov-gpmf-remux: CMP = oneline fate-mov-gpmf-remux: REF = 8f48e435ee1f6b7e173ea756141eabf3 + +fate-mov-guess-delay-1: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_3bf_nopyramid_nobsrestriction.mp4 +fate-mov-guess-delay-2: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_3bf_pyramid_nobsrestriction.mp4 +fate-mov-guess-delay-3: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_4bf_pyramid_nobsrestriction.mp4 diff --git a/tests/ref/fate/mov-guess-delay-1 b/tests/ref/fate/mov-guess-delay-1 new file mode 100644 index 0000000000..96cb67be0c --- /dev/null +++ b/tests/ref/fate/mov-guess-delay-1 @@ -0,0 +1,3 @@ +[STREAM] +has_b_frames=1 +[/STREAM] diff --git a/tests/ref/fate/mov-guess-delay-2 b/tests/ref/fate/mov-guess-delay-2 new file mode 100644 index 0000000000..248de1c3ea --- /dev/null +++ b/tests/ref/fate/mov-guess-delay-2 @@ -0,0 +1,3 @@ +[STREAM] +has_b_frames=2 +[/STREAM] diff --git a/tests/ref/fate/mov-guess-delay-3 b/tests/ref/fate/mov-guess-delay-3 new file mode 100644 index 0000000000..248de1c3ea --- /dev/null +++ b/tests/ref/fate/mov-guess-delay-3 @@ -0,0 +1,3 @@ +[STREAM] +has_b_frames=2 +[/STREAM]