diff mbox

[FFmpeg-devel] ivfdec/ivfenc: Match behaviour of libvpx and chromium

Message ID 4efe528fe8a1c2221bd4f1e81ce5de80b866589e.camel@kepstin.ca
State New
Headers show

Commit Message

Calvin Walton Oct. 1, 2019, 5:56 p.m. UTC
The ffmpeg code read and wrote a 64bit duration field (in timebase units) in the ivf
header, where the libvpx and chromium code instead use a 32bit frame count field, and
then 32bits of unused (reserved?) space.

Switch ffmpeg to match the behaviour of libvpx & chromium.

Note that libvpx writes 0 to the frame count field when initially writing the header
then seeks back and overwrites it with the real frame count. ffmpeg used to write
0xFFFFFFFF - I've changed the behaviour to match libvpx.

References:
https://github.com/webmproject/libvpx/blob/v1.8.1/ivfenc.c#L16
Which is called from:
https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1191 (initial header)
https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1209 (rewrite with frame count)
And the chromium parser:
https://chromium.googlesource.com/chromium/src/media/+/1681b9abff73fe0e3d0932aefdab4f039a284d1a/filters/ivf_parser.h
---
 libavformat/ivfdec.c |  3 ++-
 libavformat/ivfenc.c | 11 ++++-------
 2 files changed, 6 insertions(+), 8 deletions(-)

Comments

Gyan Doshi Oct. 1, 2019, 6:11 p.m. UTC | #1
On 01-10-2019 11:26 PM, Calvin Walton wrote:
> The ffmpeg code read and wrote a 64bit duration field (in timebase units) in the ivf
> header, where the libvpx and chromium code instead use a 32bit frame count field, and
> then 32bits of unused (reserved?) space.
>
> Switch ffmpeg to match the behaviour of libvpx & chromium.
>
> Note that libvpx writes 0 to the frame count field when initially writing the header
> then seeks back and overwrites it with the real frame count. ffmpeg used to write
> 0xFFFFFFFF - I've changed the behaviour to match libvpx.
>
> References:
> https://github.com/webmproject/libvpx/blob/v1.8.1/ivfenc.c#L16
> Which is called from:
> https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1191 (initial header)
> https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1209 (rewrite with frame count)
> And the chromium parser:
> https://chromium.googlesource.com/chromium/src/media/+/1681b9abff73fe0e3d0932aefdab4f039a284d1a/filters/ivf_parser.h
> ---
>   libavformat/ivfdec.c |  3 ++-
>   libavformat/ivfenc.c | 11 ++++-------
>   2 files changed, 6 insertions(+), 8 deletions(-)
>
> diff --git a/libavformat/ivfdec.c b/libavformat/ivfdec.c
> index 40ae464b76..2eaa5164ff 100644
> --- a/libavformat/ivfdec.c
> +++ b/libavformat/ivfdec.c
> @@ -53,7 +53,8 @@ static int read_header(AVFormatContext *s)
>       st->codecpar->height     = avio_rl16(s->pb);
>       time_base.den         = avio_rl32(s->pb);
>       time_base.num         = avio_rl32(s->pb);
> -    st->duration          = avio_rl64(s->pb);
> +    st->nb_frames         = avio_rl32(s->pb);
> +    avio_skip(s->pb, 4); // 32 bits unused
>   
>       st->need_parsing      = AVSTREAM_PARSE_HEADERS;
>   
> diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c
> index adf72117e9..85ca6045ba 100644
> --- a/libavformat/ivfenc.c
> +++ b/libavformat/ivfenc.c
> @@ -22,8 +22,7 @@
>   #include "libavutil/intreadwrite.h"
>   
>   typedef struct IVFEncContext {
> -    unsigned frame_cnt;
> -    uint64_t last_pts, sum_delta_pts;
> +    uint32_t frame_cnt;
>   } IVFEncContext;
>   
>   static int ivf_write_header(AVFormatContext *s)
> @@ -53,7 +52,8 @@ static int ivf_write_header(AVFormatContext *s)
>       avio_wl16(pb, par->height);
>       avio_wl32(pb, s->streams[0]->time_base.den);
>       avio_wl32(pb, s->streams[0]->time_base.num);
> -    avio_wl64(pb, 0xFFFFFFFFFFFFFFFFULL);
> +    avio_wl32(pb, 0); // frame count
> +    avio_wl32(pb, 0); // unused
>   
>       return 0;
>   }
> @@ -66,10 +66,7 @@ static int ivf_write_packet(AVFormatContext *s, AVPacket *pkt)
>       avio_wl32(pb, pkt->size);
>       avio_wl64(pb, pkt->pts);
>       avio_write(pb, pkt->data, pkt->size);
> -    if (ctx->frame_cnt)
> -        ctx->sum_delta_pts += pkt->pts - ctx->last_pts;
>       ctx->frame_cnt++;
> -    ctx->last_pts = pkt->pts;
>   
>       return 0;
>   }
> @@ -83,7 +80,7 @@ static int ivf_write_trailer(AVFormatContext *s)
>           size_t end = avio_tell(pb);
>   
>           avio_seek(pb, 24, SEEK_SET);
> -        avio_wl64(pb, ctx->frame_cnt * ctx->sum_delta_pts / (ctx->frame_cnt - 1));
> +        avio_wl32(pb, ctx->frame_cnt);
>           avio_seek(pb, end, SEEK_SET);
>       }

See http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-October/250871.html

Gyan
James Almer Oct. 1, 2019, 6:23 p.m. UTC | #2
On 10/1/2019 3:11 PM, Gyan wrote:
> 
> 
> On 01-10-2019 11:26 PM, Calvin Walton wrote:
>> The ffmpeg code read and wrote a 64bit duration field (in timebase
>> units) in the ivf
>> header, where the libvpx and chromium code instead use a 32bit frame
>> count field, and
>> then 32bits of unused (reserved?) space.
>>
>> Switch ffmpeg to match the behaviour of libvpx & chromium.
>>
>> Note that libvpx writes 0 to the frame count field when initially
>> writing the header
>> then seeks back and overwrites it with the real frame count. ffmpeg
>> used to write
>> 0xFFFFFFFF - I've changed the behaviour to match libvpx.
>>
>> References:
>> https://github.com/webmproject/libvpx/blob/v1.8.1/ivfenc.c#L16
>> Which is called from:
>> https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1191
>> (initial header)
>> https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1209
>> (rewrite with frame count)
>> And the chromium parser:
>> https://chromium.googlesource.com/chromium/src/media/+/1681b9abff73fe0e3d0932aefdab4f039a284d1a/filters/ivf_parser.h
>>
>> ---
>>   libavformat/ivfdec.c |  3 ++-
>>   libavformat/ivfenc.c | 11 ++++-------
>>   2 files changed, 6 insertions(+), 8 deletions(-)
>>
>> diff --git a/libavformat/ivfdec.c b/libavformat/ivfdec.c
>> index 40ae464b76..2eaa5164ff 100644
>> --- a/libavformat/ivfdec.c
>> +++ b/libavformat/ivfdec.c
>> @@ -53,7 +53,8 @@ static int read_header(AVFormatContext *s)
>>       st->codecpar->height     = avio_rl16(s->pb);
>>       time_base.den         = avio_rl32(s->pb);
>>       time_base.num         = avio_rl32(s->pb);
>> -    st->duration          = avio_rl64(s->pb);
>> +    st->nb_frames         = avio_rl32(s->pb);
>> +    avio_skip(s->pb, 4); // 32 bits unused
>>         st->need_parsing      = AVSTREAM_PARSE_HEADERS;
>>   diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c
>> index adf72117e9..85ca6045ba 100644
>> --- a/libavformat/ivfenc.c
>> +++ b/libavformat/ivfenc.c
>> @@ -22,8 +22,7 @@
>>   #include "libavutil/intreadwrite.h"
>>     typedef struct IVFEncContext {
>> -    unsigned frame_cnt;
>> -    uint64_t last_pts, sum_delta_pts;
>> +    uint32_t frame_cnt;
>>   } IVFEncContext;
>>     static int ivf_write_header(AVFormatContext *s)
>> @@ -53,7 +52,8 @@ static int ivf_write_header(AVFormatContext *s)
>>       avio_wl16(pb, par->height);
>>       avio_wl32(pb, s->streams[0]->time_base.den);
>>       avio_wl32(pb, s->streams[0]->time_base.num);
>> -    avio_wl64(pb, 0xFFFFFFFFFFFFFFFFULL);
>> +    avio_wl32(pb, 0); // frame count
>> +    avio_wl32(pb, 0); // unused
>>         return 0;
>>   }
>> @@ -66,10 +66,7 @@ static int ivf_write_packet(AVFormatContext *s,
>> AVPacket *pkt)
>>       avio_wl32(pb, pkt->size);
>>       avio_wl64(pb, pkt->pts);
>>       avio_write(pb, pkt->data, pkt->size);
>> -    if (ctx->frame_cnt)
>> -        ctx->sum_delta_pts += pkt->pts - ctx->last_pts;
>>       ctx->frame_cnt++;
>> -    ctx->last_pts = pkt->pts;
>>         return 0;
>>   }
>> @@ -83,7 +80,7 @@ static int ivf_write_trailer(AVFormatContext *s)
>>           size_t end = avio_tell(pb);
>>             avio_seek(pb, 24, SEEK_SET);
>> -        avio_wl64(pb, ctx->frame_cnt * ctx->sum_delta_pts /
>> (ctx->frame_cnt - 1));
>> +        avio_wl32(pb, ctx->frame_cnt);
>>           avio_seek(pb, end, SEEK_SET);
>>       }
> 
> See http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-October/250871.html
> 
> Gyan

That patch was already NAKed, and a fixed version sent in replacement.
James Almer Oct. 1, 2019, 6:26 p.m. UTC | #3
On 10/1/2019 2:56 PM, Calvin Walton wrote:
> The ffmpeg code read and wrote a 64bit duration field (in timebase units) in the ivf
> header, where the libvpx and chromium code instead use a 32bit frame count field, and
> then 32bits of unused (reserved?) space.
> 
> Switch ffmpeg to match the behaviour of libvpx & chromium.
> 
> Note that libvpx writes 0 to the frame count field when initially writing the header
> then seeks back and overwrites it with the real frame count. ffmpeg used to write
> 0xFFFFFFFF - I've changed the behaviour to match libvpx.
> 
> References:
> https://github.com/webmproject/libvpx/blob/v1.8.1/ivfenc.c#L16
> Which is called from:
> https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1191 (initial header)
> https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1209 (rewrite with frame count)
> And the chromium parser:
> https://chromium.googlesource.com/chromium/src/media/+/1681b9abff73fe0e3d0932aefdab4f039a284d1a/filters/ivf_parser.h
> ---
>  libavformat/ivfdec.c |  3 ++-
>  libavformat/ivfenc.c | 11 ++++-------
>  2 files changed, 6 insertions(+), 8 deletions(-)
> 
> diff --git a/libavformat/ivfdec.c b/libavformat/ivfdec.c
> index 40ae464b76..2eaa5164ff 100644
> --- a/libavformat/ivfdec.c
> +++ b/libavformat/ivfdec.c
> @@ -53,7 +53,8 @@ static int read_header(AVFormatContext *s)
>      st->codecpar->height     = avio_rl16(s->pb);
>      time_base.den         = avio_rl32(s->pb);
>      time_base.num         = avio_rl32(s->pb);
> -    st->duration          = avio_rl64(s->pb);
> +    st->nb_frames         = avio_rl32(s->pb);

The demuxer will report N/A as duration after this.

> +    avio_skip(s->pb, 4); // 32 bits unused
>  
>      st->need_parsing      = AVSTREAM_PARSE_HEADERS;
>  
> diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c
> index adf72117e9..85ca6045ba 100644
> --- a/libavformat/ivfenc.c
> +++ b/libavformat/ivfenc.c
> @@ -22,8 +22,7 @@
>  #include "libavutil/intreadwrite.h"
>  
>  typedef struct IVFEncContext {
> -    unsigned frame_cnt;
> -    uint64_t last_pts, sum_delta_pts;
> +    uint32_t frame_cnt;
>  } IVFEncContext;
>  
>  static int ivf_write_header(AVFormatContext *s)
> @@ -53,7 +52,8 @@ static int ivf_write_header(AVFormatContext *s)
>      avio_wl16(pb, par->height);
>      avio_wl32(pb, s->streams[0]->time_base.den);
>      avio_wl32(pb, s->streams[0]->time_base.num);
> -    avio_wl64(pb, 0xFFFFFFFFFFFFFFFFULL);
> +    avio_wl32(pb, 0); // frame count
> +    avio_wl32(pb, 0); // unused
>  
>      return 0;
>  }
> @@ -66,10 +66,7 @@ static int ivf_write_packet(AVFormatContext *s, AVPacket *pkt)
>      avio_wl32(pb, pkt->size);
>      avio_wl64(pb, pkt->pts);
>      avio_write(pb, pkt->data, pkt->size);
> -    if (ctx->frame_cnt)
> -        ctx->sum_delta_pts += pkt->pts - ctx->last_pts;
>      ctx->frame_cnt++;
> -    ctx->last_pts = pkt->pts;
>  
>      return 0;
>  }
> @@ -83,7 +80,7 @@ static int ivf_write_trailer(AVFormatContext *s)
>          size_t end = avio_tell(pb);
>  
>          avio_seek(pb, 24, SEEK_SET);
> -        avio_wl64(pb, ctx->frame_cnt * ctx->sum_delta_pts / (ctx->frame_cnt - 1));
> +        avio_wl32(pb, ctx->frame_cnt);
>          avio_seek(pb, end, SEEK_SET);
>      }

Similarly, old versions of the ivf demuxer will read bogus duration
values after this change.
Gyan Doshi Oct. 1, 2019, 6:28 p.m. UTC | #4
On 01-10-2019 11:53 PM, James Almer wrote:
> On 10/1/2019 3:11 PM, Gyan wrote:
>>
>> On 01-10-2019 11:26 PM, Calvin Walton wrote:
>>> The ffmpeg code read and wrote a 64bit duration field (in timebase
>>> units) in the ivf
>>> header, where the libvpx and chromium code instead use a 32bit frame
>>> count field, and
>>> then 32bits of unused (reserved?) space.
>>>
>>> Switch ffmpeg to match the behaviour of libvpx & chromium.
>>>
>>> Note that libvpx writes 0 to the frame count field when initially
>>> writing the header
>>> then seeks back and overwrites it with the real frame count. ffmpeg
>>> used to write
>>> 0xFFFFFFFF - I've changed the behaviour to match libvpx.
>>>
>>> References:
>>> https://github.com/webmproject/libvpx/blob/v1.8.1/ivfenc.c#L16
>>> Which is called from:
>>> https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1191
>>> (initial header)
>>> https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1209
>>> (rewrite with frame count)
>>> And the chromium parser:
>>> https://chromium.googlesource.com/chromium/src/media/+/1681b9abff73fe0e3d0932aefdab4f039a284d1a/filters/ivf_parser.h
>>>
>>> ---
>>>    libavformat/ivfdec.c |  3 ++-
>>>    libavformat/ivfenc.c | 11 ++++-------
>>>    2 files changed, 6 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/libavformat/ivfdec.c b/libavformat/ivfdec.c
>>> index 40ae464b76..2eaa5164ff 100644
>>> --- a/libavformat/ivfdec.c
>>> +++ b/libavformat/ivfdec.c
>>> @@ -53,7 +53,8 @@ static int read_header(AVFormatContext *s)
>>>        st->codecpar->height     = avio_rl16(s->pb);
>>>        time_base.den         = avio_rl32(s->pb);
>>>        time_base.num         = avio_rl32(s->pb);
>>> -    st->duration          = avio_rl64(s->pb);
>>> +    st->nb_frames         = avio_rl32(s->pb);
>>> +    avio_skip(s->pb, 4); // 32 bits unused
>>>          st->need_parsing      = AVSTREAM_PARSE_HEADERS;
>>>    diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c
>>> index adf72117e9..85ca6045ba 100644
>>> --- a/libavformat/ivfenc.c
>>> +++ b/libavformat/ivfenc.c
>>> @@ -22,8 +22,7 @@
>>>    #include "libavutil/intreadwrite.h"
>>>      typedef struct IVFEncContext {
>>> -    unsigned frame_cnt;
>>> -    uint64_t last_pts, sum_delta_pts;
>>> +    uint32_t frame_cnt;
>>>    } IVFEncContext;
>>>      static int ivf_write_header(AVFormatContext *s)
>>> @@ -53,7 +52,8 @@ static int ivf_write_header(AVFormatContext *s)
>>>        avio_wl16(pb, par->height);
>>>        avio_wl32(pb, s->streams[0]->time_base.den);
>>>        avio_wl32(pb, s->streams[0]->time_base.num);
>>> -    avio_wl64(pb, 0xFFFFFFFFFFFFFFFFULL);
>>> +    avio_wl32(pb, 0); // frame count
>>> +    avio_wl32(pb, 0); // unused
>>>          return 0;
>>>    }
>>> @@ -66,10 +66,7 @@ static int ivf_write_packet(AVFormatContext *s,
>>> AVPacket *pkt)
>>>        avio_wl32(pb, pkt->size);
>>>        avio_wl64(pb, pkt->pts);
>>>        avio_write(pb, pkt->data, pkt->size);
>>> -    if (ctx->frame_cnt)
>>> -        ctx->sum_delta_pts += pkt->pts - ctx->last_pts;
>>>        ctx->frame_cnt++;
>>> -    ctx->last_pts = pkt->pts;
>>>          return 0;
>>>    }
>>> @@ -83,7 +80,7 @@ static int ivf_write_trailer(AVFormatContext *s)
>>>            size_t end = avio_tell(pb);
>>>              avio_seek(pb, 24, SEEK_SET);
>>> -        avio_wl64(pb, ctx->frame_cnt * ctx->sum_delta_pts /
>>> (ctx->frame_cnt - 1));
>>> +        avio_wl32(pb, ctx->frame_cnt);
>>>            avio_seek(pb, end, SEEK_SET);
>>>        }
>> See http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-October/250871.html
>>
>> Gyan
> That patch was already NAKed, and a fixed version sent in replacement.

I intended to link to the start of the thread, not the patch.

Gyan
rzumer@tebako.net Oct. 1, 2019, 6:33 p.m. UTC | #5
This is a superset of my patch(es). It should match the behavior of
libvpx more closely, but the validity of the change from duration to
number of frames depends on your interpretation of the reference
implementation, which comments the field as "length".

On Tue, 2019-10-01 at 23:41 +0530, Gyan wrote:
> 
> On 01-10-2019 11:26 PM, Calvin Walton wrote:
> > The ffmpeg code read and wrote a 64bit duration field (in timebase
> > units) in the ivf
> > header, where the libvpx and chromium code instead use a 32bit
> > frame count field, and
> > then 32bits of unused (reserved?) space.
> > 
> > Switch ffmpeg to match the behaviour of libvpx & chromium.
> > 
> > Note that libvpx writes 0 to the frame count field when initially
> > writing the header
> > then seeks back and overwrites it with the real frame count. ffmpeg
> > used to write
> > 0xFFFFFFFF - I've changed the behaviour to match libvpx.
> > 
> > References:
> > https://github.com/webmproject/libvpx/blob/v1.8.1/ivfenc.c#L16
> > Which is called from:
> > https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1191
> > (initial header)
> > https://github.com/webmproject/libvpx/blob/v1.8.1/vpxenc.c#L1209
> > (rewrite with frame count)
> > And the chromium parser:
> > https://chromium.googlesource.com/chromium/src/media/+/1681b9abff73fe0e3d0932aefdab4f039a284d1a/filters/ivf_parser.h
> > ---
> >   libavformat/ivfdec.c |  3 ++-
> >   libavformat/ivfenc.c | 11 ++++-------
> >   2 files changed, 6 insertions(+), 8 deletions(-)
> > 
> > diff --git a/libavformat/ivfdec.c b/libavformat/ivfdec.c
> > index 40ae464b76..2eaa5164ff 100644
> > --- a/libavformat/ivfdec.c
> > +++ b/libavformat/ivfdec.c
> > @@ -53,7 +53,8 @@ static int read_header(AVFormatContext *s)
> >       st->codecpar->height     = avio_rl16(s->pb);
> >       time_base.den         = avio_rl32(s->pb);
> >       time_base.num         = avio_rl32(s->pb);
> > -    st->duration          = avio_rl64(s->pb);
> > +    st->nb_frames         = avio_rl32(s->pb);
> > +    avio_skip(s->pb, 4); // 32 bits unused
> >   
> >       st->need_parsing      = AVSTREAM_PARSE_HEADERS;
> >   
> > diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c
> > index adf72117e9..85ca6045ba 100644
> > --- a/libavformat/ivfenc.c
> > +++ b/libavformat/ivfenc.c
> > @@ -22,8 +22,7 @@
> >   #include "libavutil/intreadwrite.h"
> >   
> >   typedef struct IVFEncContext {
> > -    unsigned frame_cnt;
> > -    uint64_t last_pts, sum_delta_pts;
> > +    uint32_t frame_cnt;
> >   } IVFEncContext;
> >   
> >   static int ivf_write_header(AVFormatContext *s)
> > @@ -53,7 +52,8 @@ static int ivf_write_header(AVFormatContext *s)
> >       avio_wl16(pb, par->height);
> >       avio_wl32(pb, s->streams[0]->time_base.den);
> >       avio_wl32(pb, s->streams[0]->time_base.num);
> > -    avio_wl64(pb, 0xFFFFFFFFFFFFFFFFULL);
> > +    avio_wl32(pb, 0); // frame count
> > +    avio_wl32(pb, 0); // unused
> >   
> >       return 0;
> >   }
> > @@ -66,10 +66,7 @@ static int ivf_write_packet(AVFormatContext *s,
> > AVPacket *pkt)
> >       avio_wl32(pb, pkt->size);
> >       avio_wl64(pb, pkt->pts);
> >       avio_write(pb, pkt->data, pkt->size);
> > -    if (ctx->frame_cnt)
> > -        ctx->sum_delta_pts += pkt->pts - ctx->last_pts;
> >       ctx->frame_cnt++;
> > -    ctx->last_pts = pkt->pts;
> >   
> >       return 0;
> >   }
> > @@ -83,7 +80,7 @@ static int ivf_write_trailer(AVFormatContext *s)
> >           size_t end = avio_tell(pb);
> >   
> >           avio_seek(pb, 24, SEEK_SET);
> > -        avio_wl64(pb, ctx->frame_cnt * ctx->sum_delta_pts / (ctx-
> > >frame_cnt - 1));
> > +        avio_wl32(pb, ctx->frame_cnt);
> >           avio_seek(pb, end, SEEK_SET);
> >       }
> 
> See 
> http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-October/250871.html
> 
> Gyan
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Calvin Walton Oct. 1, 2019, 6:43 p.m. UTC | #6
On Tue, 2019-10-01 at 15:26 -0300, James Almer wrote:
> On 10/1/2019 2:56 PM, Calvin Walton wrote:
> >  libavformat/ivfdec.c |  3 ++-
> >  libavformat/ivfenc.c | 11 ++++-------
> >  2 files changed, 6 insertions(+), 8 deletions(-)
> > 
> > diff --git a/libavformat/ivfdec.c b/libavformat/ivfdec.c
> > index 40ae464b76..2eaa5164ff 100644
> > --- a/libavformat/ivfdec.c
> > +++ b/libavformat/ivfdec.c
> > @@ -53,7 +53,8 @@ static int read_header(AVFormatContext *s)
> >      st->codecpar->height     = avio_rl16(s->pb);
> >      time_base.den         = avio_rl32(s->pb);
> >      time_base.num         = avio_rl32(s->pb);
> > -    st->duration          = avio_rl64(s->pb);
> > +    st->nb_frames         = avio_rl32(s->pb);
> 
> The demuxer will report N/A as duration after this.

This is intentional, as the container format doesn't have a duration
field, only a frame count. I suppose it might be possible to estimate a
duration by probing the file to guess the average framerate, and then
dividing the frame count by the framerate - but I'm not familiar with
how that could be done in the demuxer

> >          size_t end = avio_tell(pb);
> >  
> >          avio_seek(pb, 24, SEEK_SET);
> > -        avio_wl64(pb, ctx->frame_cnt * ctx->sum_delta_pts / (ctx-
> > >frame_cnt - 1));
> > +        avio_wl32(pb, ctx->frame_cnt);
> >          avio_seek(pb, end, SEEK_SET);
> >      }
> 
> Similarly, old versions of the ivf demuxer will read bogus duration
> values after this change.

Old versions of the ivf demuxer read bogus duration values for files
generated by vpxenc in the case where the timebase is something other
than 1/framerate (i think this can happen if a timebase is manually set
or if a fractional framerate is used) or if the file is vfr (I'm not
sure if vpxenc can generate vfr files).
Calvin Walton Oct. 1, 2019, 7:25 p.m. UTC | #7
On Tue, 2019-10-01 at 13:56 -0400, Calvin Walton wrote:
> The ffmpeg code read and wrote a 64bit duration field (in timebase
> units) in the ivf
> header, where the libvpx and chromium code instead use a 32bit frame
> count field, and
> then 32bits of unused (reserved?) space.
> 
> Switch ffmpeg to match the behaviour of libvpx & chromium.

Just to note (now that I've got fate working on my dev machine again),
if this patch is applied, a bunch of the test references will need
updates due to the ivf file output changing. I'll include those updates
if I do a second patch revision.
diff mbox

Patch

diff --git a/libavformat/ivfdec.c b/libavformat/ivfdec.c
index 40ae464b76..2eaa5164ff 100644
--- a/libavformat/ivfdec.c
+++ b/libavformat/ivfdec.c
@@ -53,7 +53,8 @@  static int read_header(AVFormatContext *s)
     st->codecpar->height     = avio_rl16(s->pb);
     time_base.den         = avio_rl32(s->pb);
     time_base.num         = avio_rl32(s->pb);
-    st->duration          = avio_rl64(s->pb);
+    st->nb_frames         = avio_rl32(s->pb);
+    avio_skip(s->pb, 4); // 32 bits unused
 
     st->need_parsing      = AVSTREAM_PARSE_HEADERS;
 
diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c
index adf72117e9..85ca6045ba 100644
--- a/libavformat/ivfenc.c
+++ b/libavformat/ivfenc.c
@@ -22,8 +22,7 @@ 
 #include "libavutil/intreadwrite.h"
 
 typedef struct IVFEncContext {
-    unsigned frame_cnt;
-    uint64_t last_pts, sum_delta_pts;
+    uint32_t frame_cnt;
 } IVFEncContext;
 
 static int ivf_write_header(AVFormatContext *s)
@@ -53,7 +52,8 @@  static int ivf_write_header(AVFormatContext *s)
     avio_wl16(pb, par->height);
     avio_wl32(pb, s->streams[0]->time_base.den);
     avio_wl32(pb, s->streams[0]->time_base.num);
-    avio_wl64(pb, 0xFFFFFFFFFFFFFFFFULL);
+    avio_wl32(pb, 0); // frame count
+    avio_wl32(pb, 0); // unused
 
     return 0;
 }
@@ -66,10 +66,7 @@  static int ivf_write_packet(AVFormatContext *s, AVPacket *pkt)
     avio_wl32(pb, pkt->size);
     avio_wl64(pb, pkt->pts);
     avio_write(pb, pkt->data, pkt->size);
-    if (ctx->frame_cnt)
-        ctx->sum_delta_pts += pkt->pts - ctx->last_pts;
     ctx->frame_cnt++;
-    ctx->last_pts = pkt->pts;
 
     return 0;
 }
@@ -83,7 +80,7 @@  static int ivf_write_trailer(AVFormatContext *s)
         size_t end = avio_tell(pb);
 
         avio_seek(pb, 24, SEEK_SET);
-        avio_wl64(pb, ctx->frame_cnt * ctx->sum_delta_pts / (ctx->frame_cnt - 1));
+        avio_wl32(pb, ctx->frame_cnt);
         avio_seek(pb, end, SEEK_SET);
     }