[FFmpeg-devel] [PATCH] Fix: VP9 superframe parsing when the superframe contains only one frame

Sebastien Alaiwan sebastien.alaiwan at allegrodvt.com
Fri Nov 6 17:10:40 CET 2015


Hi,

The attached patch fixes an issue with the superframe index parsing.
Please find attached a VP9 IVF stream showing the issue (if you try to remux it to webm).
The gist of the problem is that the vp9 superframe parser seems to expect at least two frames inside the superframe.

Cheers,
Sebastien Alaiwan

-------------- next part --------------
A non-text attachment was scrubbed...
Name: superframe.vp9
Type: application/octet-stream
Size: 80 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20151106/97277aec/attachment.obj>
-------------- next part --------------
From 2b9dccf27821f6de1e792bba3f340d2ba9a2753f Mon Sep 17 00:00:00 2001
From: Sebastien Alaiwan <sebastien.alaiwan at allegrodvt.com>
Date: Fri, 6 Nov 2015 14:29:12 +0100
Subject: [PATCH] Fix VP9 superframe parsing when there's only one nested frame
 in the superframe

Signed-off-by: Sebastien Alaiwan <sebastien.alaiwan at allegrodvt.com>
---
 libavcodec/vp9_parser.c | 92 ++++++++++++++++++++++---------------------------
 1 file changed, 41 insertions(+), 51 deletions(-)

diff --git a/libavcodec/vp9_parser.c b/libavcodec/vp9_parser.c
index 6713850..07c80da 100644
--- a/libavcodec/vp9_parser.c
+++ b/libavcodec/vp9_parser.c
@@ -88,65 +88,55 @@ static int parse(AVCodecParserContext *ctx,
         return 0;
     }
 
-    if (s->n_frames > 0) {
-        *out_data = data;
-        *out_size = s->size[--s->n_frames];
-        parse_frame(ctx, *out_data, *out_size);
+    if (s->n_frames <= 0) {
 
-        return s->n_frames > 0 ? *out_size : size /* i.e. include idx tail */;
-    }
+        // by default: exactly one nested frame, no index
+        s->n_frames = 1;
+        s->size[0] = full_size;
+
+        // try to read many nested frames
+        marker = data[size - 1];
+        if ((marker & 0xe0) == 0xc0) {
+            int nbytes = 1 + ((marker >> 3) & 0x3);
+            int n_frames = 1 + (marker & 0x7);
+            int idx_sz = 2 + n_frames * nbytes;
+
+            if (size >= idx_sz && data[size - idx_sz] == marker) {
+                const uint8_t *idx = data + size + 1 - idx_sz;
+
+                s->n_frames = n_frames;
 
-    marker = data[size - 1];
-    if ((marker & 0xe0) == 0xc0) {
-        int nbytes = 1 + ((marker >> 3) & 0x3);
-        int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes;
-
-        if (size >= idx_sz && data[size - idx_sz] == marker) {
-            const uint8_t *idx = data + size + 1 - idx_sz;
-            int first = 1;
-
-            switch (nbytes) {
-#define case_n(a, rd) \
-            case a: \
-                while (n_frames--) { \
-                    unsigned sz = rd; \
-                    idx += a; \
-                    if (sz == 0 || sz > size) { \
-                        s->n_frames = 0; \
-                        *out_size = size; \
-                        *out_data = data; \
-                        av_log(avctx, AV_LOG_ERROR, \
-                               "Invalid superframe packet size: %u frame size: %d\n", \
-                               sz, size); \
-                        return full_size; \
-                    } \
-                    if (first) { \
-                        first = 0; \
-                        *out_data = data; \
-                        *out_size = sz; \
-                        s->n_frames = n_frames; \
-                    } else { \
-                        s->size[n_frames] = sz; \
-                    } \
-                    data += sz; \
-                    size -= sz; \
-                } \
-                parse_frame(ctx, *out_data, *out_size); \
-                return *out_size
-
-                case_n(1, *idx);
-                case_n(2, AV_RL16(idx));
-                case_n(3, AV_RL24(idx));
-                case_n(4, AV_RL32(idx));
+                for(int k=0; k < n_frames; ++k) {
+                    unsigned sz = 0;
+
+                    for(int i=0; i < nbytes;++i)
+                        sz += idx[i] << (8*i);
+
+                    idx += nbytes;
+
+                    if (sz > size) {
+                        s->n_frames = 0;
+                        *out_size = size;
+                        *out_data = data;
+                        av_log(avctx, AV_LOG_ERROR,
+                                "Superframe packet size too big: %u > %d\n",
+                                sz, size);
+                        return full_size;
+                    }
+
+                    s->size[n_frames-1-k] = sz;
+                }
             }
         }
     }
 
+    assert(s->n_frames > 0);
+
     *out_data = data;
-    *out_size = size;
-    parse_frame(ctx, data, size);
+    *out_size = s->size[--s->n_frames];
+    parse_frame(ctx, *out_data, *out_size);
 
-    return size;
+    return s->n_frames > 0 ? *out_size : size /* i.e. include idx tail */;
 }
 
 AVCodecParser ff_vp9_parser = {
-- 
2.6.2



More information about the ffmpeg-devel mailing list