[FFmpeg-devel] avformat/mov: fix hang while seek on a kind of fragmented mp4.

Submitted by Charles Liu on Feb. 3, 2019, 3:09 p.m.

Details

Message ID 20190203150906.6632-1-liuchh83@gmail.com
State Accepted
Commit aa25198f1b925a464bdfa83a98476f08d26c9209
Headers show

Commit Message

Charles Liu Feb. 3, 2019, 3:09 p.m.
Binary searching would hang if the fragment items do NOT have timestamp for the specified stream.

For example, a fmp4 consists of separated 'moof' boxes for each track, and separated 'sidx' for each segment, but no 'mfra' box.
Then every fragment item only have the timestamp for one of its tracks.

Signed-off-by: Charles Liu <liuchh83@gmail.com>
---
 libavformat/mov.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

Comments

Marton Balint Feb. 10, 2019, 10:04 p.m.
On Sun, 3 Feb 2019, Charles Liu wrote:

> Binary searching would hang if the fragment items do NOT have timestamp for the specified stream.
>
> For example, a fmp4 consists of separated 'moof' boxes for each track, and separated 'sidx' for each segment, but no 'mfra' box.
> Then every fragment item only have the timestamp for one of its tracks.
>
> Signed-off-by: Charles Liu <liuchh83@gmail.com>
> ---
> libavformat/mov.c | 21 ++++++++++++---------
> 1 file changed, 12 insertions(+), 9 deletions(-)
>
> diff --git a/libavformat/mov.c b/libavformat/mov.c
> index 9b9739f788..35cb619e9f 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -1266,7 +1266,7 @@ static int64_t get_frag_time(MOVFragmentIndex *frag_index,
> static int search_frag_timestamp(MOVFragmentIndex *frag_index,
>                                  AVStream *st, int64_t timestamp)
> {
> -    int a, b, m;
> +    int a, b, m, m0;
>     int64_t frag_time;
>     int id = -1;
> 
> @@ -1282,15 +1282,18 @@ static int search_frag_timestamp(MOVFragmentIndex *frag_index,
>     b = frag_index->nb_items;
>
>     while (b - a > 1) {
> -        m = (a + b) >> 1;
> -        frag_time = get_frag_time(frag_index, m, id);
> -        if (frag_time != AV_NOPTS_VALUE) {
> -            if (frag_time >= timestamp)
> -                b = m;
> -            if (frag_time <= timestamp)
> -                a = m;
> -        }
> +        m0 = m = (a + b) >> 1;
> +
> +        while (m < b &&
> +               (frag_time = get_frag_time(frag_index, m, id)) == AV_NOPTS_VALUE)
> +            m++;
> +
> +        if (m < b && frag_time <= timestamp)
> +            a = m;
> +        else
> +            b = m0;
>     }
> +
>     return a;
> }
>

As this fixes a hang, I will push this version soon. Can be optimized 
later to pure binary search, if anybody is still interested.

Regards,
Marton
Carl Eugen Hoyos Feb. 10, 2019, 10:24 p.m.
2019-02-10 23:04 GMT+01:00, Marton Balint <cus@passwd.hu>:
>
>
> On Sun, 3 Feb 2019, Charles Liu wrote:
>
>> Binary searching would hang if the fragment items do NOT have timestamp
>> for the specified stream.
>>
>> For example, a fmp4 consists of separated 'moof' boxes for each track, and
>> separated 'sidx' for each segment, but no 'mfra' box.
>> Then every fragment item only have the timestamp for one of its tracks.
>>
>> Signed-off-by: Charles Liu <liuchh83@gmail.com>
>> ---
>> libavformat/mov.c | 21 ++++++++++++---------
>> 1 file changed, 12 insertions(+), 9 deletions(-)
>>
>> diff --git a/libavformat/mov.c b/libavformat/mov.c
>> index 9b9739f788..35cb619e9f 100644
>> --- a/libavformat/mov.c
>> +++ b/libavformat/mov.c
>> @@ -1266,7 +1266,7 @@ static int64_t get_frag_time(MOVFragmentIndex
>> *frag_index,
>> static int search_frag_timestamp(MOVFragmentIndex *frag_index,
>>                                  AVStream *st, int64_t timestamp)
>> {
>> -    int a, b, m;
>> +    int a, b, m, m0;
>>     int64_t frag_time;
>>     int id = -1;
>>
>> @@ -1282,15 +1282,18 @@ static int search_frag_timestamp(MOVFragmentIndex
>> *frag_index,
>>     b = frag_index->nb_items;
>>
>>     while (b - a > 1) {
>> -        m = (a + b) >> 1;
>> -        frag_time = get_frag_time(frag_index, m, id);
>> -        if (frag_time != AV_NOPTS_VALUE) {
>> -            if (frag_time >= timestamp)
>> -                b = m;
>> -            if (frag_time <= timestamp)
>> -                a = m;
>> -        }
>> +        m0 = m = (a + b) >> 1;
>> +
>> +        while (m < b &&
>> +               (frag_time = get_frag_time(frag_index, m, id)) ==
>> AV_NOPTS_VALUE)
>> +            m++;
>> +
>> +        if (m < b && frag_time <= timestamp)
>> +            a = m;
>> +        else
>> +            b = m0;
>>     }
>> +
>>     return a;
>> }
>>
>
> As this fixes a hang, I will push this version soon.

Please mention ticket #7572 in the commit message.

Thank you, Carl Eugen
Charles Liu Feb. 11, 2019, 11:51 a.m.
It is lucky that my patch works to ticket 7572. However, #7572 has a deeper
reason.

Mov demuxer consider that fragmented index is completed if a ‘sidx’ point
to the end of the file. But there may be other ‘sidx’ for other tracks. If
we skip the tail from there, we will missing the last ‘sidx’ and ‘moof’.
Then AV_NOPTS_VALUE occurs.

I tried to avoid skipping the tail simply. However, fate-test run failed on
mov-frag-encrypted.mp4.


BTW, I just got back from vacation. I am willing to follow an optimized
solution.


Thanks and Regards,

Chenhui



Carl Eugen Hoyos <ceffmpeg@gmail.com> 于2019年2月11日周一 上午6:24写道:

> 2019-02-10 23:04 GMT+01:00, Marton Balint <cus@passwd.hu>:
> >
> >
> > On Sun, 3 Feb 2019, Charles Liu wrote:
> >
> >> Binary searching would hang if the fragment items do NOT have timestamp
> >> for the specified stream.
> >>
> >> For example, a fmp4 consists of separated 'moof' boxes for each track,
> and
> >> separated 'sidx' for each segment, but no 'mfra' box.
> >> Then every fragment item only have the timestamp for one of its tracks.
> >>
> >> Signed-off-by: Charles Liu <liuchh83@gmail.com>
> >> ---
> >> libavformat/mov.c | 21 ++++++++++++---------
> >> 1 file changed, 12 insertions(+), 9 deletions(-)
> >>
> >> diff --git a/libavformat/mov.c b/libavformat/mov.c
> >> index 9b9739f788..35cb619e9f 100644
> >> --- a/libavformat/mov.c
> >> +++ b/libavformat/mov.c
> >> @@ -1266,7 +1266,7 @@ static int64_t get_frag_time(MOVFragmentIndex
> >> *frag_index,
> >> static int search_frag_timestamp(MOVFragmentIndex *frag_index,
> >>                                  AVStream *st, int64_t timestamp)
> >> {
> >> -    int a, b, m;
> >> +    int a, b, m, m0;
> >>     int64_t frag_time;
> >>     int id = -1;
> >>
> >> @@ -1282,15 +1282,18 @@ static int
> search_frag_timestamp(MOVFragmentIndex
> >> *frag_index,
> >>     b = frag_index->nb_items;
> >>
> >>     while (b - a > 1) {
> >> -        m = (a + b) >> 1;
> >> -        frag_time = get_frag_time(frag_index, m, id);
> >> -        if (frag_time != AV_NOPTS_VALUE) {
> >> -            if (frag_time >= timestamp)
> >> -                b = m;
> >> -            if (frag_time <= timestamp)
> >> -                a = m;
> >> -        }
> >> +        m0 = m = (a + b) >> 1;
> >> +
> >> +        while (m < b &&
> >> +               (frag_time = get_frag_time(frag_index, m, id)) ==
> >> AV_NOPTS_VALUE)
> >> +            m++;
> >> +
> >> +        if (m < b && frag_time <= timestamp)
> >> +            a = m;
> >> +        else
> >> +            b = m0;
> >>     }
> >> +
> >>     return a;
> >> }
> >>
> >
> > As this fixes a hang, I will push this version soon.
>
> Please mention ticket #7572 in the commit message.
>
> Thank you, Carl Eugen
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Marton Balint Feb. 11, 2019, 9:10 p.m.
On Sun, 10 Feb 2019, Carl Eugen Hoyos wrote:

> 2019-02-10 23:04 GMT+01:00, Marton Balint <cus@passwd.hu>:
>>
>>
>> On Sun, 3 Feb 2019, Charles Liu wrote:
>>
>>> Binary searching would hang if the fragment items do NOT have timestamp
>>> for the specified stream.
>>>
>>> For example, a fmp4 consists of separated 'moof' boxes for each track, and
>>> separated 'sidx' for each segment, but no 'mfra' box.
>>> Then every fragment item only have the timestamp for one of its tracks.
>>>
>>> Signed-off-by: Charles Liu <liuchh83@gmail.com>
>>> ---
>>> libavformat/mov.c | 21 ++++++++++++---------
>>> 1 file changed, 12 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/libavformat/mov.c b/libavformat/mov.c
>>> index 9b9739f788..35cb619e9f 100644
>>> --- a/libavformat/mov.c
>>> +++ b/libavformat/mov.c
>>> @@ -1266,7 +1266,7 @@ static int64_t get_frag_time(MOVFragmentIndex
>>> *frag_index,
>>> static int search_frag_timestamp(MOVFragmentIndex *frag_index,
>>>                                  AVStream *st, int64_t timestamp)
>>> {
>>> -    int a, b, m;
>>> +    int a, b, m, m0;
>>>     int64_t frag_time;
>>>     int id = -1;
>>>
>>> @@ -1282,15 +1282,18 @@ static int search_frag_timestamp(MOVFragmentIndex
>>> *frag_index,
>>>     b = frag_index->nb_items;
>>>
>>>     while (b - a > 1) {
>>> -        m = (a + b) >> 1;
>>> -        frag_time = get_frag_time(frag_index, m, id);
>>> -        if (frag_time != AV_NOPTS_VALUE) {
>>> -            if (frag_time >= timestamp)
>>> -                b = m;
>>> -            if (frag_time <= timestamp)
>>> -                a = m;
>>> -        }
>>> +        m0 = m = (a + b) >> 1;
>>> +
>>> +        while (m < b &&
>>> +               (frag_time = get_frag_time(frag_index, m, id)) ==
>>> AV_NOPTS_VALUE)
>>> +            m++;
>>> +
>>> +        if (m < b && frag_time <= timestamp)
>>> +            a = m;
>>> +        else
>>> +            b = m0;
>>>     }
>>> +
>>>     return a;
>>> }
>>>
>>
>> As this fixes a hang, I will push this version soon.
>
> Please mention ticket #7572 in the commit message.

Sure. Pushed.

Regards,
Marton

Patch hide | download patch | download mbox

diff --git a/libavformat/mov.c b/libavformat/mov.c
index 9b9739f788..35cb619e9f 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1266,7 +1266,7 @@  static int64_t get_frag_time(MOVFragmentIndex *frag_index,
 static int search_frag_timestamp(MOVFragmentIndex *frag_index,
                                  AVStream *st, int64_t timestamp)
 {
-    int a, b, m;
+    int a, b, m, m0;
     int64_t frag_time;
     int id = -1;
 
@@ -1282,15 +1282,18 @@  static int search_frag_timestamp(MOVFragmentIndex *frag_index,
     b = frag_index->nb_items;
 
     while (b - a > 1) {
-        m = (a + b) >> 1;
-        frag_time = get_frag_time(frag_index, m, id);
-        if (frag_time != AV_NOPTS_VALUE) {
-            if (frag_time >= timestamp)
-                b = m;
-            if (frag_time <= timestamp)
-                a = m;
-        }
+        m0 = m = (a + b) >> 1;
+
+        while (m < b &&
+               (frag_time = get_frag_time(frag_index, m, id)) == AV_NOPTS_VALUE)
+            m++;
+
+        if (m < b && frag_time <= timestamp)
+            a = m;
+        else
+            b = m0;
     }
+
     return a;
 }