avidec: handle broken AVI index better

Message ID 20170227192234.21485-1-stebbins@jetheaddev.com
State New
Headers show

Commit Message

John Stebbins Feb. 27, 2017, 7:22 p.m.
A broken index that causes non-interleaved access and has a packet size
of 0 causes an infinite loop reading 0 bytes.  Switch to assuming file
is interleaved if a broken index is detected.
---
 libavformat/avidec.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

Comments

Luca Barbato Feb. 27, 2017, 7:35 p.m. | #1
On 27/02/2017 20:22, John Stebbins wrote:
> A broken index that causes non-interleaved access and has a packet size
> of 0 causes an infinite loop reading 0 bytes.  Switch to assuming file
> is interleaved if a broken index is detected.
> ---
>  libavformat/avidec.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 

Probably it should go to stable as well.

lu
Luca Barbato Feb. 27, 2017, 7:36 p.m. | #2
On 27/02/2017 20:22, John Stebbins wrote:
> -        avio_seek(s->pb, pos + 8, SEEK_SET);

Is that intended?
John Stebbins Feb. 27, 2017, 7:40 p.m. | #3
On 02/27/2017 12:36 PM, Luca Barbato wrote:
> On 27/02/2017 20:22, John Stebbins wrote:
>> -        avio_seek(s->pb, pos + 8, SEEK_SET);
> Is that intended?
> _______________________________________________
>

Yes, I moved it to the "else" clause of the code I added.  I.e. it does not do the seek if a broken index is detected
and continues from the end of the last successful read point.

Patch

diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index 870066e..31e9a31 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -1146,7 +1146,6 @@  static int ni_prepare_read(AVFormatContext *s)
     if (i >= 0) {
         int64_t pos = best_st->index_entries[i].pos;
         pos += best_ast->packet_size - best_ast->remaining;
-        avio_seek(s->pb, pos + 8, SEEK_SET);
 
         assert(best_ast->remaining <= best_ast->packet_size);
 
@@ -1154,6 +1153,14 @@  static int ni_prepare_read(AVFormatContext *s)
         if (!best_ast->remaining)
             best_ast->packet_size =
             best_ast->remaining   = best_st->index_entries[i].size;
+        if (!best_ast->remaining) {
+            /* broken index, assume interleaved and attempt to continue */
+            av_log(s, AV_LOG_ERROR, "Broken AVI index.\n");
+            avi->stream_index = -1;
+            avi->non_interleaved = 0;
+        } else {
+            avio_seek(s->pb, pos + 8, SEEK_SET);
+        }
     }
 
     return 0;