diff mbox

[FFmpeg-devel] lavf/mov.c: Guess video codec delay based on PTS while parsing MOV header.

Message ID 20171121042705.7021-1-isasi@google.com
State Superseded
Headers show

Commit Message

Sasi Inguva Nov. 21, 2017, 4:27 a.m. UTC
Signed-off-by: Sasi Inguva <isasi@google.com>
---
 libavformat/mov.c                | 50 ++++++++++++++++++++++++++++++++++++++++
 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, 66 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

Comments

Michael Niedermayer Nov. 22, 2017, 2:59 a.m. UTC | #1
On Mon, Nov 20, 2017 at 08:27:05PM -0800, Sasi Inguva wrote:
> Signed-off-by: Sasi Inguva <isasi@google.com>
> ---
>  libavformat/mov.c                | 50 ++++++++++++++++++++++++++++++++++++++++
>  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, 66 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 fd170baa57..afb0d4ca5c 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -3213,6 +3213,54 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns
>      return *ctts_count;
>  }
>  
> +static void mov_guess_video_delay(MOVContext *c, AVStream* st) {
> +    MOVStreamContext *msc = st->priv_data;
> +    int ind;
> +    int ctts_ind = 0;
> +    int ctts_sample = 0;
> +    int64_t curr_pts = AV_NOPTS_VALUE;
> +    int64_t min_prev_pts = AV_NOPTS_VALUE;
> +    int64_t prev_max_pts = AV_NOPTS_VALUE;
> +    int num_steps = 0;
> +
> +    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) {
> +            curr_pts = st->index_entries[ind].timestamp + msc->ctts_data[ctts_ind].duration;
> +
> +            // Everytime we encounter a new max_pts we reset num_steps and compute again.
> +            if (curr_pts > prev_max_pts) {
> +                st->codecpar->video_delay = FFMIN(FFMAX(st->codecpar->video_delay, num_steps), 16);
> +                num_steps = 0;
> +                prev_max_pts = curr_pts;
> +                min_prev_pts = curr_pts;
> +            } else {
> +                // Compute delay as the length of the path from max PTS to min PTS.
> +                // Frames: I0 I1 B0 B1 B2
> +                // PTS:     0  4  1  2  3 -> num_steps = delay = 1 (4->1)
> +                //
> +                // Frames: I0 I1 B1 B0 B2
> +                // PTS:     0  4  2  1  3 -> num_steps = delay = 2 (4->2, 2->1)
> +                if (min_prev_pts != AV_NOPTS_VALUE) {
> +                    if (curr_pts < min_prev_pts) {
> +                        ++num_steps;
> +                        min_prev_pts = curr_pts;
> +                    }
> +                }
> +            }

Can you explain why this algorithm is correct ?
(iam asking as i suspect it is not correct, but i may be wrong)

What this should do is find the minimum buffer size to sort the stream
of frame timestamps.


[...]
Sasi Inguva Nov. 22, 2017, 7:51 a.m. UTC | #2
I was just shooting for a heuristic which works for most of the cases.
Most GOP structures are like this in decoding order
PTS:              Pmin ,  Pmax , (Pmin + k) , (Pmin + k -1) ... (Pmin + 1)
,  (Pmin + 2k) , (Pmin + 2k -1) ... (Pmin + k + 1) .... (Pmax + 1)
PICT_TYPE:     I0         I1               Bk               Bk-1
    B0                  B2k                 B2k-1                  Bk+1
                   I2

The min. buffer size is actually the number of frames that came in between
Pmin and Pmin + 1 ,since the buffer should be able to hold all those frames
(and sort them) , before Pmin + 1 comes along and is output. So here, the
buffer size is "k".

The algo computes the number of decreasing steps from Pmax ->  (Pmin + 1)
=  k . Hence the algo works for this case.

However I realize now that my algo will break,
when Pmin and Pmax are not adjacent
Pmin , *(Pmin + k -1)* , Pmax , (Pmin + k) ,  ... (Pmin + 1) , ...   - The
buffer size is still k but the algo will compute as (k - 1) . e.g.  0, 2,
4, 1, 3

or the path from Pmax -> (Pmin + 1) not strictly decreasing .
Pmin ,  Pmax , (Pmin + k) , (Pmin + k -1), *(Pmin + k +1)*   ... (Pmin +
1)  - The buffer size is now (k + 1) but the algo will still compute as  k
e.g. 0, 4, 2, 3, 1

I can build a better heuristic by finding the  frame with next min. PTS
after Pmin and computing the distance between that frame and Pmin.  However
that will still fail for this example,
 0, 3, 5, 1, 4, 2 . The delay computed will be 2 (because 2 frames between
0 and 1 ) but we need a buffer size of 3 .

On Wed, Nov 22, 2017 at 8:29 AM, Michael Niedermayer <michael@niedermayer.cc
> wrote:

> On Mon, Nov 20, 2017 at 08:27:05PM -0800, Sasi Inguva wrote:
> > Signed-off-by: Sasi Inguva <isasi@google.com>
> > ---
> >  libavformat/mov.c                | 50 ++++++++++++++++++++++++++++++
> ++++++++++
> >  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, 66 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 fd170baa57..afb0d4ca5c 100644
> > --- a/libavformat/mov.c
> > +++ b/libavformat/mov.c
> > @@ -3213,6 +3213,54 @@ static int64_t add_ctts_entry(MOVStts**
> ctts_data, unsigned int* ctts_count, uns
> >      return *ctts_count;
> >  }
> >
> > +static void mov_guess_video_delay(MOVContext *c, AVStream* st) {
> > +    MOVStreamContext *msc = st->priv_data;
> > +    int ind;
> > +    int ctts_ind = 0;
> > +    int ctts_sample = 0;
> > +    int64_t curr_pts = AV_NOPTS_VALUE;
> > +    int64_t min_prev_pts = AV_NOPTS_VALUE;
> > +    int64_t prev_max_pts = AV_NOPTS_VALUE;
> > +    int num_steps = 0;
> > +
> > +    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) {
> > +            curr_pts = st->index_entries[ind].timestamp +
> msc->ctts_data[ctts_ind].duration;
> > +
> > +            // Everytime we encounter a new max_pts we reset num_steps
> and compute again.
> > +            if (curr_pts > prev_max_pts) {
> > +                st->codecpar->video_delay = FFMIN(FFMAX(st->codecpar->video_delay,
> num_steps), 16);
> > +                num_steps = 0;
> > +                prev_max_pts = curr_pts;
> > +                min_prev_pts = curr_pts;
> > +            } else {
> > +                // Compute delay as the length of the path from max PTS
> to min PTS.
> > +                // Frames: I0 I1 B0 B1 B2
> > +                // PTS:     0  4  1  2  3 -> num_steps = delay = 1
> (4->1)
> > +                //
> > +                // Frames: I0 I1 B1 B0 B2
> > +                // PTS:     0  4  2  1  3 -> num_steps = delay = 2
> (4->2, 2->1)
> > +                if (min_prev_pts != AV_NOPTS_VALUE) {
> > +                    if (curr_pts < min_prev_pts) {
> > +                        ++num_steps;
> > +                        min_prev_pts = curr_pts;
> > +                    }
> > +                }
> > +            }
>
> Can you explain why this algorithm is correct ?
> (iam asking as i suspect it is not correct, but i may be wrong)
>
> What this should do is find the minimum buffer size to sort the stream
> of frame timestamps.
>
>
> [...]
> --
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> Its not that you shouldnt use gotos but rather that you should write
> readable code and code with gotos often but not always is less readable
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
>
Michael Niedermayer Nov. 22, 2017, 12:43 p.m. UTC | #3
On Wed, Nov 22, 2017 at 01:21:45PM +0530, Sasi Inguva wrote:
> I was just shooting for a heuristic which works for most of the cases.

I do not think a heuristic is a good idea. Its not very hard to
compute this exactly. You just reorder using a 16 entry buffer and
keep track of what the largest size was that was actually needed.

Or a buffer that is increased in size whenever it would lead to
out of order output



[...]

> I can build a better heuristic by finding the  frame with next min. PTS
> after Pmin and computing the distance between that frame and Pmin.  However
> that will still fail for this example,
>  0, 3, 5, 1, 4, 2 . The delay computed will be 2 (because 2 frames between
> 0 and 1 ) but we need a buffer size of 3 .
> 
> On Wed, Nov 22, 2017 at 8:29 AM, Michael Niedermayer <michael@niedermayer.cc
> > wrote:
> 
> > On Mon, Nov 20, 2017 at 08:27:05PM -0800, Sasi Inguva wrote:
> > > Signed-off-by: Sasi Inguva <isasi@google.com>
> > > ---
> > >  libavformat/mov.c                | 50 ++++++++++++++++++++++++++++++
> > ++++++++++
> > >  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, 66 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 fd170baa57..afb0d4ca5c 100644
> > > --- a/libavformat/mov.c
> > > +++ b/libavformat/mov.c
> > > @@ -3213,6 +3213,54 @@ static int64_t add_ctts_entry(MOVStts**
> > ctts_data, unsigned int* ctts_count, uns
> > >      return *ctts_count;
> > >  }
> > >
> > > +static void mov_guess_video_delay(MOVContext *c, AVStream* st) {
> > > +    MOVStreamContext *msc = st->priv_data;
> > > +    int ind;
> > > +    int ctts_ind = 0;
> > > +    int ctts_sample = 0;
> > > +    int64_t curr_pts = AV_NOPTS_VALUE;
> > > +    int64_t min_prev_pts = AV_NOPTS_VALUE;
> > > +    int64_t prev_max_pts = AV_NOPTS_VALUE;
> > > +    int num_steps = 0;
> > > +
> > > +    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) {
> > > +            curr_pts = st->index_entries[ind].timestamp +
> > msc->ctts_data[ctts_ind].duration;
> > > +
> > > +            // Everytime we encounter a new max_pts we reset num_steps
> > and compute again.
> > > +            if (curr_pts > prev_max_pts) {
> > > +                st->codecpar->video_delay = FFMIN(FFMAX(st->codecpar->video_delay,
> > num_steps), 16);
> > > +                num_steps = 0;
> > > +                prev_max_pts = curr_pts;
> > > +                min_prev_pts = curr_pts;
> > > +            } else {
> > > +                // Compute delay as the length of the path from max PTS
> > to min PTS.
> > > +                // Frames: I0 I1 B0 B1 B2
> > > +                // PTS:     0  4  1  2  3 -> num_steps = delay = 1
> > (4->1)
> > > +                //
> > > +                // Frames: I0 I1 B1 B0 B2
> > > +                // PTS:     0  4  2  1  3 -> num_steps = delay = 2
> > (4->2, 2->1)
> > > +                if (min_prev_pts != AV_NOPTS_VALUE) {
> > > +                    if (curr_pts < min_prev_pts) {
> > > +                        ++num_steps;
> > > +                        min_prev_pts = curr_pts;
> > > +                    }
> > > +                }
> > > +            }
> >
> > Can you explain why this algorithm is correct ?
> > (iam asking as i suspect it is not correct, but i may be wrong)
> >
> > What this should do is find the minimum buffer size to sort the stream
> > of frame timestamps.
> >
> >
> > [...]
> > --
> > Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
> >
> > Its not that you shouldnt use gotos but rather that you should write
> > readable code and code with gotos often but not always is less readable
> >
> > _______________________________________________
> > ffmpeg-devel mailing list
> > ffmpeg-devel@ffmpeg.org
> > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> >
> >
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Sasi Inguva Dec. 18, 2017, 11:30 p.m. UTC | #4
Sorry for getting back so late as I was on vacation. Submitting the patch
again. This time I compute the delay exactly using a 17 element circular
buffer to sort the timestamps. PTAL.

On Wed, Nov 22, 2017 at 4:43 AM, Michael Niedermayer <michael@niedermayer.cc
> wrote:

> On Wed, Nov 22, 2017 at 01:21:45PM +0530, Sasi Inguva wrote:
> > I was just shooting for a heuristic which works for most of the cases.
>
> I do not think a heuristic is a good idea. Its not very hard to
> compute this exactly. You just reorder using a 16 entry buffer and
> keep track of what the largest size was that was actually needed.
>
> Or a buffer that is increased in size whenever it would lead to
> out of order output
>
>
>
> [...]
>
> > I can build a better heuristic by finding the  frame with next min. PTS
> > after Pmin and computing the distance between that frame and Pmin.
> However
> > that will still fail for this example,
> >  0, 3, 5, 1, 4, 2 . The delay computed will be 2 (because 2 frames
> between
> > 0 and 1 ) but we need a buffer size of 3 .
> >
> > On Wed, Nov 22, 2017 at 8:29 AM, Michael Niedermayer
> <michael@niedermayer.cc
> > > wrote:
> >
> > > On Mon, Nov 20, 2017 at 08:27:05PM -0800, Sasi Inguva wrote:
> > > > Signed-off-by: Sasi Inguva <isasi@google.com>
> > > > ---
> > > >  libavformat/mov.c                | 50 ++++++++++++++++++++++++++++++
> > > ++++++++++
> > > >  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, 66 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 fd170baa57..afb0d4ca5c 100644
> > > > --- a/libavformat/mov.c
> > > > +++ b/libavformat/mov.c
> > > > @@ -3213,6 +3213,54 @@ static int64_t add_ctts_entry(MOVStts**
> > > ctts_data, unsigned int* ctts_count, uns
> > > >      return *ctts_count;
> > > >  }
> > > >
> > > > +static void mov_guess_video_delay(MOVContext *c, AVStream* st) {
> > > > +    MOVStreamContext *msc = st->priv_data;
> > > > +    int ind;
> > > > +    int ctts_ind = 0;
> > > > +    int ctts_sample = 0;
> > > > +    int64_t curr_pts = AV_NOPTS_VALUE;
> > > > +    int64_t min_prev_pts = AV_NOPTS_VALUE;
> > > > +    int64_t prev_max_pts = AV_NOPTS_VALUE;
> > > > +    int num_steps = 0;
> > > > +
> > > > +    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) {
> > > > +            curr_pts = st->index_entries[ind].timestamp +
> > > msc->ctts_data[ctts_ind].duration;
> > > > +
> > > > +            // Everytime we encounter a new max_pts we reset
> num_steps
> > > and compute again.
> > > > +            if (curr_pts > prev_max_pts) {
> > > > +                st->codecpar->video_delay =
> FFMIN(FFMAX(st->codecpar->video_delay,
> > > num_steps), 16);
> > > > +                num_steps = 0;
> > > > +                prev_max_pts = curr_pts;
> > > > +                min_prev_pts = curr_pts;
> > > > +            } else {
> > > > +                // Compute delay as the length of the path from max
> PTS
> > > to min PTS.
> > > > +                // Frames: I0 I1 B0 B1 B2
> > > > +                // PTS:     0  4  1  2  3 -> num_steps = delay = 1
> > > (4->1)
> > > > +                //
> > > > +                // Frames: I0 I1 B1 B0 B2
> > > > +                // PTS:     0  4  2  1  3 -> num_steps = delay = 2
> > > (4->2, 2->1)
> > > > +                if (min_prev_pts != AV_NOPTS_VALUE) {
> > > > +                    if (curr_pts < min_prev_pts) {
> > > > +                        ++num_steps;
> > > > +                        min_prev_pts = curr_pts;
> > > > +                    }
> > > > +                }
> > > > +            }
> > >
> > > Can you explain why this algorithm is correct ?
> > > (iam asking as i suspect it is not correct, but i may be wrong)
> > >
> > > What this should do is find the minimum buffer size to sort the stream
> > > of frame timestamps.
> > >
> > >
> > > [...]
> > > --
> > > Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC7
> 87040B0FAB
> > >
> > > Its not that you shouldnt use gotos but rather that you should write
> > > readable code and code with gotos often but not always is less readable
> > >
> > > _______________________________________________
> > > ffmpeg-devel mailing list
> > > ffmpeg-devel@ffmpeg.org
> > > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> > >
> > >
> > _______________________________________________
> > ffmpeg-devel mailing list
> > ffmpeg-devel@ffmpeg.org
> > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> --
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> Take away the freedom of one citizen and you will be jailed, take away
> the freedom of all citizens and you will be congratulated by your peers
> in Parliament.
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
>
diff mbox

Patch

diff --git a/libavformat/mov.c b/libavformat/mov.c
index fd170baa57..afb0d4ca5c 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -3213,6 +3213,54 @@  static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns
     return *ctts_count;
 }
 
+static void mov_guess_video_delay(MOVContext *c, AVStream* st) {
+    MOVStreamContext *msc = st->priv_data;
+    int ind;
+    int ctts_ind = 0;
+    int ctts_sample = 0;
+    int64_t curr_pts = AV_NOPTS_VALUE;
+    int64_t min_prev_pts = AV_NOPTS_VALUE;
+    int64_t prev_max_pts = AV_NOPTS_VALUE;
+    int num_steps = 0;
+
+    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) {
+            curr_pts = st->index_entries[ind].timestamp + msc->ctts_data[ctts_ind].duration;
+
+            // Everytime we encounter a new max_pts we reset num_steps and compute again.
+            if (curr_pts > prev_max_pts) {
+                st->codecpar->video_delay = FFMIN(FFMAX(st->codecpar->video_delay, num_steps), 16);
+                num_steps = 0;
+                prev_max_pts = curr_pts;
+                min_prev_pts = curr_pts;
+            } else {
+                // Compute delay as the length of the path from max PTS to min PTS.
+                // Frames: I0 I1 B0 B1 B2
+                // PTS:     0  4  1  2  3 -> num_steps = delay = 1 (4->1)
+                //
+                // Frames: I0 I1 B1 B0 B2
+                // PTS:     0  4  2  1  3 -> num_steps = delay = 2 (4->2, 2->1)
+                if (min_prev_pts != AV_NOPTS_VALUE) {
+                    if (curr_pts < min_prev_pts) {
+                        ++num_steps;
+                        min_prev_pts = curr_pts;
+                    }
+                }
+            }
+
+            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++;
@@ -3846,6 +3894,8 @@  static void mov_build_index(MOVContext *mov, AVStream *st)
         // Fix index according to edit lists.
         mov_fix_index(mov, st);
     }
+
+    mov_guess_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 76f66ff498..6e79f0aba8 100644
--- a/tests/fate/mov.mak
+++ b/tests/fate/mov.mak
@@ -11,6 +11,9 @@  FATE_MOV = fate-mov-3elist \
            fate-mov-440hz-10ms \
            fate-mov-ibi-elst-starts-b \
            fate-mov-elst-ends-betn-b-and-i \
+           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 \
@@ -72,3 +75,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
\ No newline at end of file
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]