[vlc-devel] [PATCH] Use avcodec's vp9 parser to packetize the superframes before decoding

Denis Charmet typx at dinauz.org
Thu Feb 5 20:54:32 CET 2015


Le jeudi 05 février 2015 à 05:38:27, Rémi Denis-Courmont a écrit :
> So what happens when FFmpeg gets fixed and someone tries to use VLC
> 2.2 with it, or vice versa? Also what of libav? *If* the bug is in
> FFmpeg, then FFmpeg needs to be fixed; is all.

It works with libav which doesn't have a vp9 parser so when FFmpeg get
fixed it will work the same way since it uses their code.
We can ask their opinion on that.

The only ways to get vp9 in 2.2 and before the end of the week are:
* Fixing FFmpeg, which I can't do in a so short time
* Upgrading libvpx' codec priority
* Pushing this patch maybe with version checks.

What I've come so far is this ugly POC:

And notice the //ff_thread_finish_setup(ctx);

diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index 2bb2432..cf98274 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -3741,10 +3741,11 @@ static av_cold int
vp9_decode_free(AVCodecContext *ctx)
 
 
 static int vp9_decode_frame(AVCodecContext *ctx, void *frame,
-                            int *got_frame, AVPacket *pkt)
+                            int *got_frame, const uint8_t * data, int size)
+//                            int *got_frame, AVPacket *pkt) {
-    const uint8_t *data = pkt->data;
-    int size = pkt->size;
+    //const uint8_t *data = pkt->data;
+    //int size = pkt->size;
     VP9Context *s = ctx->priv_data;
     int res, tile_row, tile_col, i, ref, row, col;
     ptrdiff_t yoff, uvoff, ls_y, ls_uv;
@@ -3838,9 +3839,9 @@ static int vp9_decode_frame(AVCodecContext *ctx,
void *frame,
                 break;
         }
         s->prob_ctx[s->framectxid].p = s->prob.p;
-        ff_thread_finish_setup(ctx);
+        //ff_thread_finish_setup(ctx);
     } else if (!s->refreshctx) {
-        ff_thread_finish_setup(ctx);
+        //ff_thread_finish_setup(ctx);
     }
 
     do {
@@ -3966,7 +3967,7 @@ static int vp9_decode_frame(AVCodecContext *ctx,
void *frame,
 
         if (s->pass < 2 && s->refreshctx && !s->parallelmode) {
             adapt_probs(s);
-            ff_thread_finish_setup(ctx);
+            //ff_thread_finish_setup(ctx);
         }
     } while (s->pass++ == 1);
     ff_thread_report_progress(&s->frames[CUR_FRAME].tf, INT_MAX, 0);
@@ -3987,6 +3988,68 @@ static int vp9_decode_frame(AVCodecContext *ctx,
void *frame,
     return 0;
 }
 
+static int vp9_decode_packet(AVCodecContext *avctx, void *frame,
+                             int *got_frame, AVPacket *avpkt)
+{
+    const uint8_t *data = avpkt->data;
+    int size            = avpkt->size;
+    int marker, ret;
+
+    /* Read superframe index - this is a collection of individual
frames
+     * that together lead to one visible frame */
+    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;
+
+            while (n_frames--) {
+                unsigned sz;
+                switch(nbytes)
+                {
+                case 1:
+                    sz = *idx;
+                    break;
+                case 2:
+                    sz = AV_RL16(idx);
+                    break;
+                case 3:
+                    sz = AV_RL24(idx);
+                    break;
+                case 4:
+                    sz = AV_RL32(idx);
+                    break;
+                }
+                idx += nbytes;
+
+                if (sz > size) {
+                    av_log(avctx, AV_LOG_ERROR,
+                           "Superframe packet size too big: %u > %d nbytes=%d\n",
+                           sz, size, nbytes);
+                    return AVERROR_INVALIDDATA;
+                }
+
+                ret = vp9_decode_frame(avctx, frame, got_frame, data, sz);
+                if (ret < 0)
+                    return ret;
+                data += sz;
+                size -= sz;
+            }
+            return size;
+        }
+    }
+
+    /* If we get here, there was no valid superframe index, i.e. this is just
+     * one whole single frame. Decode it as such from the complete input buf. */
+    if ((ret = vp9_decode_frame(avctx, frame, got_frame, data, size)) < 0)
+        return ret;
+    return size;
+}
+
+
 static void vp9_decode_flush(AVCodecContext *ctx)
 {
     VP9Context *s = ctx->priv_data;
@@ -4091,7 +4154,8 @@ AVCodec ff_vp9_decoder = {
     .priv_data_size        = sizeof(VP9Context),
     .init                  = vp9_decode_init,
     .close                 = vp9_decode_free,
-    .decode                = vp9_decode_frame,
+    //.decode                = vp9_decode_frame,
+    .decode                = vp9_decode_packet,
     .capabilities          = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
     .flush                 = vp9_decode_flush,
     .init_thread_copy      = ONLY_IF_THREADS_ENABLED(vp9_decode_init_thread_copy),



If someone has a good way to do it... feel free to contribute.

Regards,

-- 
Denis Charmet - TypX
Le mauvais esprit est un art de vivre



More information about the vlc-devel mailing list