diff mbox series

[FFmpeg-devel,v3,1/4] avformat/movenc: fix assert failure in get_cluster_duration()

Message ID tencent_9373ABED4E3F70552D699AF7400F9A699F08@qq.com
State New
Headers show
Series [FFmpeg-devel,v3,1/4] avformat/movenc: fix assert failure in get_cluster_duration() | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/make_ppc success Make finished
andriy/make_fate_ppc fail Make fate failed

Commit Message

zhilizhao(赵志立) Dec. 31, 2021, 11:36 a.m. UTC
When editlist is disabled, the workaournd method of shift dts to
zero and increase the first sample duration doesn't work if the
timestamp is larger than mp4 spec restriction (e.g., sample_delta
in stts entry). Further more, it triggers get_cluster_duration()
assert failure. This patch will drop large offsets between
multiple tracks.
---
 libavformat/movenc.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

Comments

zhilizhao(赵志立) Feb. 27, 2022, 6:34 a.m. UTC | #1
Ping.

> On Dec 31, 2021, at 7:36 PM, Zhao Zhili <quinkblack@foxmail.com> wrote:
> 
> When editlist is disabled, the workaournd method of shift dts to
> zero and increase the first sample duration doesn't work if the
> timestamp is larger than mp4 spec restriction (e.g., sample_delta
> in stts entry). Further more, it triggers get_cluster_duration()
> assert failure. This patch will drop large offsets between
> multiple tracks.
> ---
> libavformat/movenc.c | 13 ++++++++++++-
> 1 file changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index 0f912dd012..f5bb785b01 100644
> --- a/libavformat/movenc.c
> +++ b/libavformat/movenc.c
> @@ -5917,7 +5917,18 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
>          * to signal the difference in starting time without an edit list.
>          * Thus move the timestamp for this first sample to 0, increasing
>          * its duration instead. */
> -        trk->cluster[trk->entry].dts = trk->start_dts = 0;
> +        if (pkt->dts + pkt->duration <= INT32_MAX) {
> +            trk->cluster[trk->entry].dts = trk->start_dts = 0;
> +        } else {
> +            /* Impossible to write a sample duration >= UINT32_MAX.
> +             * Use INT32_MAX as a tight restriction.
> +             */
> +            trk->start_dts = pkt->dts;
> +            av_log(s, AV_LOG_WARNING,
> +                   "Track %d starts with a nonzero dts %" PRId64
> +                   " which will be shifted to zero\n",
> +                   pkt->stream_index, pkt->dts);
> +        }
>     }
>     if (trk->start_dts == AV_NOPTS_VALUE) {
>         trk->start_dts = pkt->dts;
> -- 
> 2.31.1
> 
> _______________________________________________
> 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".
Gyan Doshi Feb. 27, 2022, 6:49 a.m. UTC | #2
On 2022-02-27 12:04 pm, "zhilizhao(赵志立)" wrote:
> Ping.
>
>> On Dec 31, 2021, at 7:36 PM, Zhao Zhili <quinkblack@foxmail.com> wrote:
>>
>> When editlist is disabled, the workaournd method of shift dts to
>> zero and increase the first sample duration doesn't work if the
>> timestamp is larger than mp4 spec restriction (e.g., sample_delta
>> in stts entry). Further more, it triggers get_cluster_duration()
>> assert failure. This patch will drop large offsets between
>> multiple tracks.
>> ---
>> libavformat/movenc.c | 13 ++++++++++++-
>> 1 file changed, 12 insertions(+), 1 deletion(-)
>>
>> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
>> index 0f912dd012..f5bb785b01 100644
>> --- a/libavformat/movenc.c
>> +++ b/libavformat/movenc.c
>> @@ -5917,7 +5917,18 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
>>           * to signal the difference in starting time without an edit list.
>>           * Thus move the timestamp for this first sample to 0, increasing
>>           * its duration instead. */
>> -        trk->cluster[trk->entry].dts = trk->start_dts = 0;
>> +        if (pkt->dts + pkt->duration <= INT32_MAX) {
>> +            trk->cluster[trk->entry].dts = trk->start_dts = 0;
>> +        } else {
>> +            /* Impossible to write a sample duration >= UINT32_MAX.

As per 14496-12 (2005), sample_delta is stored as

unsigned int(32) sample_delta;

The only restriction is that no delta shall be zero except the last 
sample, which means UINT32_MAX  is allowed.
INT32_MAX had been set as max allowed delta in mov.c since inception. 
See my recent changes in mov.c correcting that.

Will this patch break remuxing of files with large deltas?
Let's not clamp if the spec does not call for it.

Regards,
Gyan
Paul B Mahol Feb. 27, 2022, 12:42 p.m. UTC | #3
On Sun, Feb 27, 2022 at 7:49 AM Gyan Doshi <ffmpeg@gyani.pro> wrote:

>
>
> On 2022-02-27 12:04 pm, "zhilizhao(赵志立)" wrote:
> > Ping.
> >
> >> On Dec 31, 2021, at 7:36 PM, Zhao Zhili <quinkblack@foxmail.com> wrote:
> >>
> >> When editlist is disabled, the workaournd method of shift dts to
> >> zero and increase the first sample duration doesn't work if the
> >> timestamp is larger than mp4 spec restriction (e.g., sample_delta
> >> in stts entry). Further more, it triggers get_cluster_duration()
> >> assert failure. This patch will drop large offsets between
> >> multiple tracks.
> >> ---
> >> libavformat/movenc.c | 13 ++++++++++++-
> >> 1 file changed, 12 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> >> index 0f912dd012..f5bb785b01 100644
> >> --- a/libavformat/movenc.c
> >> +++ b/libavformat/movenc.c
> >> @@ -5917,7 +5917,18 @@ int ff_mov_write_packet(AVFormatContext *s,
> AVPacket *pkt)
> >>           * to signal the difference in starting time without an edit
> list.
> >>           * Thus move the timestamp for this first sample to 0,
> increasing
> >>           * its duration instead. */
> >> -        trk->cluster[trk->entry].dts = trk->start_dts = 0;
> >> +        if (pkt->dts + pkt->duration <= INT32_MAX) {
> >> +            trk->cluster[trk->entry].dts = trk->start_dts = 0;
> >> +        } else {
> >> +            /* Impossible to write a sample duration >= UINT32_MAX.
>
> As per 14496-12 (2005), sample_delta is stored as
>
> unsigned int(32) sample_delta;
>
> The only restriction is that no delta shall be zero except the last
> sample, which means UINT32_MAX  is allowed.
> INT32_MAX had been set as max allowed delta in mov.c since inception.
> See my recent changes in mov.c correcting that.
>
> Will this patch break remuxing of files with large deltas?
> Let's not clamp if the spec does not call for it.
>

Yes, I agree 100% this is not proper fix for assert.


> Regards,
> 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".
>
zhilizhao(赵志立) March 1, 2022, 1:32 p.m. UTC | #4
> On Feb 27, 2022, at 2:49 PM, Gyan Doshi <ffmpeg@gyani.pro> wrote:
> 
> 
> 
> On 2022-02-27 12:04 pm, "zhilizhao(赵志立)" wrote:
>> Ping.
>> 
>>> On Dec 31, 2021, at 7:36 PM, Zhao Zhili <quinkblack@foxmail.com> wrote:
>>> 
>>> When editlist is disabled, the workaournd method of shift dts to
>>> zero and increase the first sample duration doesn't work if the
>>> timestamp is larger than mp4 spec restriction (e.g., sample_delta
>>> in stts entry). Further more, it triggers get_cluster_duration()
>>> assert failure. This patch will drop large offsets between
>>> multiple tracks.
>>> ---
>>> libavformat/movenc.c | 13 ++++++++++++-
>>> 1 file changed, 12 insertions(+), 1 deletion(-)
>>> 
>>> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
>>> index 0f912dd012..f5bb785b01 100644
>>> --- a/libavformat/movenc.c
>>> +++ b/libavformat/movenc.c
>>> @@ -5917,7 +5917,18 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
>>>          * to signal the difference in starting time without an edit list.
>>>          * Thus move the timestamp for this first sample to 0, increasing
>>>          * its duration instead. */
>>> -        trk->cluster[trk->entry].dts = trk->start_dts = 0;
>>> +        if (pkt->dts + pkt->duration <= INT32_MAX) {
>>> +            trk->cluster[trk->entry].dts = trk->start_dts = 0;
>>> +        } else {
>>> +            /* Impossible to write a sample duration >= UINT32_MAX.
> 
> As per 14496-12 (2005), sample_delta is stored as
> 
> unsigned int(32) sample_delta;
> 
> The only restriction is that no delta shall be zero except the last sample, which means UINT32_MAX  is allowed.
> INT32_MAX had been set as max allowed delta in mov.c since inception. See my recent changes in mov.c correcting that.
> 
> Will this patch break remuxing of files with large deltas?
> Let's not clamp if the spec does not call for it.

Since get_cluster_duration() checks dts against INT_MAX, remove
the clamp at here can still trigger abort() after.

```
    av_assert0(next_dts <= INT_MAX);

```

The prototype of get_cluster_duration() which returns int needs
to be fixed, and a bunch of places.

And then we can get regression issues: movenc.c output files with
delta larger than INT32_MAX can be dangerous, which is not the
case of mov.c demuxer.

It’s a clever trick here, by using a large sample duration to
handle start time difference between multiple tracks. Since it’s
not a standard method like editlist, I think we can turn off the
strategy safely (FFmpeg abort before the patch, so it’s already
turned off in a hard way).

What do you think?

> 
> Regards,
> 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".
zhilizhao(赵志立) March 29, 2022, 4:59 a.m. UTC | #5
> On Mar 1, 2022, at 9:32 PM, zhilizhao(赵志立) <quinkblack@foxmail.com> wrote:
> 
> 
>> On Feb 27, 2022, at 2:49 PM, Gyan Doshi <ffmpeg@gyani.pro> wrote:
>> 
>> 
>> 
>> On 2022-02-27 12:04 pm, "zhilizhao(赵志立)" wrote:
>>> Ping.
>>> 
>>>> On Dec 31, 2021, at 7:36 PM, Zhao Zhili <quinkblack@foxmail.com> wrote:
>>>> 
>>>> When editlist is disabled, the workaournd method of shift dts to
>>>> zero and increase the first sample duration doesn't work if the
>>>> timestamp is larger than mp4 spec restriction (e.g., sample_delta
>>>> in stts entry). Further more, it triggers get_cluster_duration()
>>>> assert failure. This patch will drop large offsets between
>>>> multiple tracks.
>>>> ---
>>>> libavformat/movenc.c | 13 ++++++++++++-
>>>> 1 file changed, 12 insertions(+), 1 deletion(-)
>>>> 
>>>> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
>>>> index 0f912dd012..f5bb785b01 100644
>>>> --- a/libavformat/movenc.c
>>>> +++ b/libavformat/movenc.c
>>>> @@ -5917,7 +5917,18 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
>>>>         * to signal the difference in starting time without an edit list.
>>>>         * Thus move the timestamp for this first sample to 0, increasing
>>>>         * its duration instead. */
>>>> -        trk->cluster[trk->entry].dts = trk->start_dts = 0;
>>>> +        if (pkt->dts + pkt->duration <= INT32_MAX) {
>>>> +            trk->cluster[trk->entry].dts = trk->start_dts = 0;
>>>> +        } else {
>>>> +            /* Impossible to write a sample duration >= UINT32_MAX.
>> 
>> As per 14496-12 (2005), sample_delta is stored as
>> 
>> unsigned int(32) sample_delta;
>> 
>> The only restriction is that no delta shall be zero except the last sample, which means UINT32_MAX  is allowed.
>> INT32_MAX had been set as max allowed delta in mov.c since inception. See my recent changes in mov.c correcting that.
>> 
>> Will this patch break remuxing of files with large deltas?
>> Let's not clamp if the spec does not call for it.
> 
> Since get_cluster_duration() checks dts against INT_MAX, remove
> the clamp at here can still trigger abort() after.
> 
> ```
>    av_assert0(next_dts <= INT_MAX);
> 
> ```
> 
> The prototype of get_cluster_duration() which returns int needs
> to be fixed, and a bunch of places.
> 
> And then we can get regression issues: movenc.c output files with
> delta larger than INT32_MAX can be dangerous, which is not the
> case of mov.c demuxer.
> 
> It’s a clever trick here, by using a large sample duration to
> handle start time difference between multiple tracks. Since it’s
> not a standard method like editlist, I think we can turn off the
> strategy safely (FFmpeg abort before the patch, so it’s already
> turned off in a hard way).
> 
> What do you think?

Ping. Another idea is return error instead of abort().

> 
>> 
>> Regards,
>> 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".
>
diff mbox series

Patch

diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 0f912dd012..f5bb785b01 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -5917,7 +5917,18 @@  int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
          * to signal the difference in starting time without an edit list.
          * Thus move the timestamp for this first sample to 0, increasing
          * its duration instead. */
-        trk->cluster[trk->entry].dts = trk->start_dts = 0;
+        if (pkt->dts + pkt->duration <= INT32_MAX) {
+            trk->cluster[trk->entry].dts = trk->start_dts = 0;
+        } else {
+            /* Impossible to write a sample duration >= UINT32_MAX.
+             * Use INT32_MAX as a tight restriction.
+             */
+            trk->start_dts = pkt->dts;
+            av_log(s, AV_LOG_WARNING,
+                   "Track %d starts with a nonzero dts %" PRId64
+                   " which will be shifted to zero\n",
+                   pkt->stream_index, pkt->dts);
+        }
     }
     if (trk->start_dts == AV_NOPTS_VALUE) {
         trk->start_dts = pkt->dts;