lavf/mov.c: Guess video codec delay based on PTS while parsing MOV header.
authorSasi Inguva <isasi-at-google.com@ffmpeg.org>
Mon, 18 Dec 2017 23:31:16 +0000 (15:31 -0800)
committerMichael Niedermayer <michael@niedermayer.cc>
Wed, 20 Dec 2017 21:27:06 +0000 (22:27 +0100)
Signed-off-by: Sasi Inguva <isasi@google.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
libavformat/mov.c
tests/fate/mov.mak
tests/ref/fate/mov-guess-delay-1 [new file with mode: 0644]
tests/ref/fate/mov-guess-delay-2 [new file with mode: 0644]
tests/ref/fate/mov-guess-delay-3 [new file with mode: 0644]

index 28d6028..480e506 100644 (file)
@@ -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) {
index 19b0130..907dfa0 100644 (file)
@@ -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 (file)
index 0000000..96cb67b
--- /dev/null
@@ -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 (file)
index 0000000..248de1c
--- /dev/null
@@ -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 (file)
index 0000000..248de1c
--- /dev/null
@@ -0,0 +1,3 @@
+[STREAM]
+has_b_frames=2
+[/STREAM]