Bug fix: Handle input data ptr = NULL and size = 0 correctly
authorScott LaVarnway <slavarnway@google.com>
Tue, 22 Jan 2013 18:52:29 +0000 (10:52 -0800)
committerScott LaVarnway <slavarnway@google.com>
Tue, 22 Jan 2013 18:52:29 +0000 (10:52 -0800)
Issue 517: Issues decoding VPX_CODEC_USE_INPUT_FRAGMENTS
http://code.google.com/p/webm/issues/detail?id=517

Change-Id: I030c4cf15b1e1b993433571b6ee77c959a368ff2

vp8/common/onyxd.h
vp8/decoder/onyxd_if.c
vp8/decoder/onyxd_int.h
vp8/vp8_dx_iface.c

index fd7e051..c67910e 100644 (file)
@@ -34,7 +34,6 @@ extern "C"
         int     postprocess;
         int     max_threads;
         int     error_concealment;
-        int     input_fragments;
     } VP8D_CONFIG;
 
     typedef enum
index 8d6871b..f05c8c8 100644 (file)
@@ -91,9 +91,6 @@ struct VP8D_COMP * vp8dx_create_decompressor(VP8D_CONFIG *oxcf)
 
     pbi->decoded_key_frame = 0;
 
-    pbi->input_fragments = oxcf->input_fragments;
-    pbi->num_fragments = 0;
-
     /* Independent partitions is activated when a frame updates the
      * token probability table to have equal probabilities over the
      * PREV_COEF context.
@@ -281,60 +278,13 @@ static int swap_frame_buffers (VP8_COMMON *cm)
     return err;
 }
 
-int vp8dx_receive_compressed_data(VP8D_COMP *pbi, size_t size,
-                                  const uint8_t *source,
-                                  int64_t time_stamp)
+int check_fragments_for_errors(VP8D_COMP *pbi)
 {
-#if HAVE_NEON
-    int64_t dx_store_reg[8];
-#endif
-    VP8_COMMON *cm = &pbi->common;
-    int retcode = -1;
-
-    pbi->common.error.error_code = VPX_CODEC_OK;
-
-    if (pbi->num_fragments == 0)
-    {
-        /* New frame, reset fragment pointers and sizes */
-        vpx_memset((void*)pbi->fragments, 0, sizeof(pbi->fragments));
-        vpx_memset(pbi->fragment_sizes, 0, sizeof(pbi->fragment_sizes));
-    }
-    if (pbi->input_fragments && !(source == NULL && size == 0))
-    {
-        /* Store a pointer to this fragment and return. We haven't
-         * received the complete frame yet, so we will wait with decoding.
-         */
-        assert(pbi->num_fragments < MAX_PARTITIONS);
-        pbi->fragments[pbi->num_fragments] = source;
-        pbi->fragment_sizes[pbi->num_fragments] = size;
-        pbi->num_fragments++;
-        if (pbi->num_fragments > (1 << EIGHT_PARTITION) + 1)
-        {
-            pbi->common.error.error_code = VPX_CODEC_UNSUP_BITSTREAM;
-            pbi->common.error.setjmp = 0;
-            pbi->num_fragments = 0;
-            return -1;
-        }
-        return 0;
-    }
-
-    if (!pbi->input_fragments)
-    {
-        pbi->fragments[0] = source;
-        pbi->fragment_sizes[0] = size;
-        pbi->num_fragments = 1;
-    }
-    assert(pbi->common.multi_token_partition <= EIGHT_PARTITION);
-    if (pbi->num_fragments == 0)
-    {
-        pbi->num_fragments = 1;
-        pbi->fragments[0] = NULL;
-        pbi->fragment_sizes[0] = 0;
-    }
-
     if (!pbi->ec_active &&
         pbi->num_fragments <= 1 && pbi->fragment_sizes[0] == 0)
     {
+        VP8_COMMON *cm = &pbi->common;
+
         /* If error concealment is disabled we won't signal missing frames
          * to the decoder.
          */
@@ -360,12 +310,29 @@ int vp8dx_receive_compressed_data(VP8D_COMP *pbi, size_t size,
         /* Signal that we have no frame to show. */
         cm->show_frame = 0;
 
-        pbi->num_fragments = 0;
-
         /* Nothing more to do. */
         return 0;
     }
 
+    return 1;
+}
+int vp8dx_receive_compressed_data(VP8D_COMP *pbi, size_t size,
+                                  const uint8_t *source,
+                                  int64_t time_stamp)
+{
+#if HAVE_NEON
+    int64_t dx_store_reg[8];
+#endif
+    VP8_COMMON *cm = &pbi->common;
+    int retcode = -1;
+
+    pbi->common.error.error_code = VPX_CODEC_OK;
+
+    retcode = check_fragments_for_errors(pbi);
+    if(retcode <= 0)
+        return retcode;
+
 #if HAVE_NEON
 #if CONFIG_RUNTIME_CPU_DETECT
     if (cm->cpu_caps & HAS_NEON)
@@ -457,7 +424,6 @@ decode_exit:
 #endif
 
     pbi->common.error.setjmp = 0;
-    pbi->num_fragments = 0;
     return retcode;
 }
 int vp8dx_get_raw_frame(VP8D_COMP *pbi, YV12_BUFFER_CONFIG *sd, int64_t *time_stamp, int64_t *time_end_stamp, vp8_ppflags_t *flags)
index 0063beb..ff9ef0e 100644 (file)
@@ -33,6 +33,14 @@ typedef struct
     MACROBLOCKD  mbd;
 } MB_ROW_DEC;
 
+typedef struct
+{
+    int enabled;
+    unsigned int count;
+    const unsigned char *ptrs[MAX_PARTITIONS];
+    unsigned int sizes[MAX_PARTITIONS];
+} FRAGMENT_DATA;
+
 typedef struct VP8D_COMP
 {
     DECLARE_ALIGNED(16, MACROBLOCKD, mb);
index c13d697..ca2245a 100644 (file)
@@ -77,6 +77,7 @@ struct vpx_codec_alg_priv
     vpx_image_t             img;
     int                     img_setup;
     void                    *user_priv;
+    FRAGMENT_DATA           fragments;
 };
 
 static unsigned long vp8_priv_sz(const vpx_codec_dec_cfg_t *si, vpx_codec_flags_t flags)
@@ -215,6 +216,13 @@ static vpx_codec_err_t vp8_init(vpx_codec_ctx_t *ctx,
         {
             vp8_init_ctx(ctx, &mmap);
 
+            /* initialize number of fragments to zero */
+            ctx->priv->alg_priv->fragments.count = 0;
+            /* is input fragments enabled? */
+            ctx->priv->alg_priv->fragments.enabled =
+                    (ctx->priv->alg_priv->base.init_flags &
+                        VPX_CODEC_USE_INPUT_FRAGMENTS);
+
             ctx->priv->alg_priv->defer_alloc = 1;
             /*post processing level initialized to do nothing */
         }
@@ -343,6 +351,47 @@ static void yuvconfig2image(vpx_image_t               *img,
     img->self_allocd = 0;
 }
 
+static int
+update_fragments(vpx_codec_alg_priv_t  *ctx,
+                 const uint8_t         *data,
+                 unsigned int           data_sz,
+                 vpx_codec_err_t       *res)
+{
+    *res = VPX_CODEC_OK;
+
+    if (ctx->fragments.count == 0)
+    {
+        /* New frame, reset fragment pointers and sizes */
+        vpx_memset((void*)ctx->fragments.ptrs, 0, sizeof(ctx->fragments.ptrs));
+        vpx_memset(ctx->fragments.sizes, 0, sizeof(ctx->fragments.sizes));
+    }
+    if (ctx->fragments.enabled && !(data == NULL && data_sz == 0))
+    {
+        /* Store a pointer to this fragment and return. We haven't
+         * received the complete frame yet, so we will wait with decoding.
+         */
+        ctx->fragments.ptrs[ctx->fragments.count] = data;
+        ctx->fragments.sizes[ctx->fragments.count] = data_sz;
+        ctx->fragments.count++;
+        if (ctx->fragments.count > (1 << EIGHT_PARTITION) + 1)
+        {
+            ctx->fragments.count = 0;
+            *res = VPX_CODEC_INVALID_PARAM;
+            return -1;
+        }
+        return 0;
+    }
+
+    if (!ctx->fragments.enabled)
+    {
+        ctx->fragments.ptrs[0] = data;
+        ctx->fragments.sizes[0] = data_sz;
+        ctx->fragments.count = 1;
+    }
+
+    return 1;
+}
+
 static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t  *ctx,
                                   const uint8_t         *data,
                                   unsigned int            data_sz,
@@ -353,6 +402,11 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t  *ctx,
     unsigned int resolution_change = 0;
     unsigned int w, h;
 
+
+    /* Update the input fragment data */
+    if(update_fragments(ctx, data, data_sz, &res) <= 0)
+        return res;
+
     /* Determine the stream parameters. Note that we rely on peek_si to
      * validate that we have a buffer that does not wrap around the top
      * of the heap.
@@ -360,7 +414,8 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t  *ctx,
     w = ctx->si.w;
     h = ctx->si.h;
 
-    res = ctx->base.iface->dec.peek_si(data, data_sz, &ctx->si);
+    res = ctx->base.iface->dec.peek_si(ctx->fragments.ptrs[0],
+                                       ctx->fragments.sizes[0], &ctx->si);
 
     if((res == VPX_CODEC_UNSUP_BITSTREAM) && !ctx->si.is_kf)
     {
@@ -421,8 +476,6 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t  *ctx,
             oxcf.max_threads = ctx->cfg.threads;
             oxcf.error_concealment =
                     (ctx->base.init_flags & VPX_CODEC_USE_ERROR_CONCEALMENT);
-            oxcf.input_fragments =
-                    (ctx->base.init_flags & VPX_CODEC_USE_INPUT_FRAGMENTS);
 
             optr = vp8dx_create_decompressor(&oxcf);
 
@@ -544,12 +597,24 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t  *ctx,
             ctx->pbi->common.fb_idx_ref_cnt[0] = 0;
         }
 
+        /* update the pbi fragment data */
+        ctx->pbi->num_fragments = ctx->fragments.count;
+        ctx->pbi->input_fragments = ctx->fragments.enabled;
+        vpx_memcpy(ctx->pbi->fragments, ctx->fragments.ptrs,
+                   sizeof(ctx->fragments.ptrs));
+        vpx_memcpy(ctx->pbi->fragment_sizes, ctx->fragments.sizes,
+                   sizeof(ctx->fragments.sizes));
+
+
         ctx->user_priv = user_priv;
         if (vp8dx_receive_compressed_data(ctx->pbi, data_sz, data, deadline))
         {
             VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi;
             res = update_error_state(ctx, &pbi->common.error);
         }
+
+        /* get ready for the next series of fragments */
+        ctx->fragments.count = 0;
     }
 
     return res;