shithub: libvpx

Download patch

ref: 2f0331c90cdf1eaa19f48c9dd4d31b6f05947e11
parent: f97f2b1bb6c08661b88324ef15354505dad4a041
parent: 67fb3a5155bd7dcb6aacbc7e3bb05be308040367
author: John Koleszar <jkoleszar@google.com>
date: Wed Jan 19 00:51:00 EST 2011

Merge "Implement error tracking in the decoder"

--- a/vp8/common/blockd.h
+++ b/vp8/common/blockd.h
@@ -282,6 +282,8 @@
 
     void *current_bc;
 
+    int corrupted;
+
 #if CONFIG_RUNTIME_CPU_DETECT
     struct VP8_COMMON_RTCD  *rtcd;
 #endif
--- a/vp8/decoder/dboolhuff.h
+++ b/vp8/decoder/dboolhuff.h
@@ -206,4 +206,29 @@
 
     return z;
 }
+
+static int vp8dx_bool_error(BOOL_DECODER *br)
+{
+  /* Check if we have reached the end of the buffer.
+   *
+   * Variable 'count' stores the number of bits in the 'value' buffer,
+   * minus 8. So if count == 8, there are 16 bits available to be read.
+   * Normally, count is filled with 8 and one byte is filled into the
+   * value buffer. When we reach the end of the buffer, count is instead
+   * filled with VP8_LOTS_OF_BITS, 8 of which represent the last 8 real
+   * bits from the bitstream. So the last bit in the bitstream will be
+   * represented by count == VP8_LOTS_OF_BITS - 16.
+   */
+    if ((br->count > VP8_BD_VALUE_SIZE)
+        && (br->count <= VP8_LOTS_OF_BITS - 16))
+    {
+       /* We have tried to decode bits after the end of
+        * stream was encountered.
+        */
+        return 1;
+    }
+
+    /* No error. */
+    return 0;
+}
 #endif
--- a/vp8/decoder/decodframe.c
+++ b/vp8/decoder/decodframe.c
@@ -381,6 +381,12 @@
         xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset;
         xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset;
 
+        if (xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME)
+        {
+            /* propagate errors from reference frames */
+            xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted;
+        }
+
         vp8_build_uvmvs(xd, pc->full_pixel);
 
         /*
@@ -391,6 +397,8 @@
         */
         vp8_decode_macroblock(pbi, xd);
 
+        /* check if the boolean decoder has suffered an error */
+        xd->corrupted |= vp8dx_bool_error(xd->current_bc);
 
         recon_yoffset += 16;
         recon_uvoffset += 8;
@@ -555,6 +563,7 @@
     xd->frame_type = pc->frame_type;
     xd->mode_info_context->mbmi.mode = DC_PRED;
     xd->mode_info_stride = pc->mode_info_stride;
+    xd->corrupted = 0; /* init without corruption */
 }
 
 int vp8_decode_frame(VP8D_COMP *pbi)
@@ -570,6 +579,10 @@
     int i, j, k, l;
     const int *const mb_feature_data_bits = vp8_mb_feature_data_bits;
 
+    /* start with no corruption of current frame */
+    xd->corrupted = 0;
+    pc->yv12_fb[pc->new_fb_idx].corrupted = 0;
+
     if (data_end - data < 3)
         vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
                            "Truncated packet");
@@ -890,6 +903,14 @@
 
 
     stop_token_decoder(pbi);
+
+    /* Collect information about decoder corruption. */
+    /* 1. Check first boolean decoder for errors. */
+    pc->yv12_fb[pc->new_fb_idx].corrupted =
+        vp8dx_bool_error(bc);
+    /* 2. Check the macroblock information */
+    pc->yv12_fb[pc->new_fb_idx].corrupted |=
+        xd->corrupted;
 
     /* vpx_log("Decoder: Frame Decoded, Size Roughly:%d bytes  \n",bc->pos+pbi->bc2.pos); */
 
--- a/vp8/decoder/onyxd_if.c
+++ b/vp8/decoder/onyxd_if.c
@@ -329,6 +329,23 @@
 
     pbi->common.error.error_code = VPX_CODEC_OK;
 
+    if (size == 0)
+    {
+       /* This is used to signal that we are missing frames.
+        * We do not know if the missing frame(s) was supposed to update
+        * any of the reference buffers, but we act conservative and
+        * mark only the last buffer as corrupted.
+        */
+        cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
+
+        /* Signal that we have no frame to show. */
+        cm->show_frame = 0;
+
+        /* Nothing more to do. */
+        return 0;
+    }
+
+
 #if HAVE_ARMV7
 #if CONFIG_RUNTIME_CPU_DETECT
     if (cm->rtcd.flags & HAS_NEON)
@@ -351,6 +368,13 @@
         }
 #endif
         pbi->common.error.setjmp = 0;
+
+       /* We do not know if the missing frame(s) was supposed to update
+        * any of the reference buffers, but we act conservative and
+        * mark only the last buffer as corrupted.
+        */
+        cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
+
         if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
           cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
         return -1;
--- a/vp8/decoder/threading.c
+++ b/vp8/decoder/threading.c
@@ -890,8 +890,17 @@
                 xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset;
                 xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset;
 
+                if (xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME)
+                {
+                    /* propagate errors from reference frames */
+                    xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted;
+                }
+
                 vp8_build_uvmvs(xd, pc->full_pixel);
                 vp8mt_decode_macroblock(pbi, xd, mb_row, mb_col);
+
+                /* check if the boolean decoder has suffered an error */
+                xd->corrupted |= vp8dx_bool_error(xd->current_bc);
 
                 if (pbi->common.filter_level)
                 {
--- a/vp8/vp8_dx_iface.c
+++ b/vp8/vp8_dx_iface.c
@@ -709,6 +709,25 @@
 }
 
 
+static vpx_codec_err_t vp8_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
+                                               int ctrl_id,
+                                               va_list args)
+{
+
+    int *corrupted = va_arg(args, int *);
+
+    if (corrupted)
+    {
+        VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi;
+        *corrupted = pbi->common.frame_to_show->corrupted;
+
+        return VPX_CODEC_OK;
+    }
+    else
+        return VPX_CODEC_INVALID_PARAM;
+
+}
+
 vpx_codec_ctrl_fn_map_t vp8_ctf_maps[] =
 {
     {VP8_SET_REFERENCE,             vp8_set_reference},
@@ -719,6 +738,7 @@
     {VP8_SET_DBG_COLOR_B_MODES,     vp8_set_dbg_options},
     {VP8_SET_DBG_DISPLAY_MV,        vp8_set_dbg_options},
     {VP8D_GET_LAST_REF_UPDATES,     vp8_get_last_ref_updates},
+    {VP8D_GET_FRAME_CORRUPTED,      vp8_get_frame_corrupted},
     { -1, NULL},
 };
 
--- a/vpx/src/vpx_decoder.c
+++ b/vpx/src/vpx_decoder.c
@@ -118,7 +118,9 @@
 {
     vpx_codec_err_t res;
 
-    if (!ctx || !data || !data_sz)
+    /* Sanity checks */
+    /* NULL data ptr allowed if data_sz is 0 too */
+    if (!ctx || (!data && data_sz))
         res = VPX_CODEC_INVALID_PARAM;
     else if (!ctx->iface || !ctx->priv)
         res = VPX_CODEC_ERROR;
--- a/vpx/vp8dx.h
+++ b/vpx/vp8dx.h
@@ -45,6 +45,7 @@
     VP8_DECODER_CTRL_ID_START   = 256,
     VP8D_GET_LAST_REF_UPDATES,              /**< control function to get info on which reference frames were updated
                                             by the last decode */
+    VP8D_GET_FRAME_CORRUPTED,               /**< check if the indicated frame is corrupted */
     VP8_DECODER_CTRL_ID_MAX
 } ;
 
@@ -58,6 +59,7 @@
 
 
 VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES,   int *)
+VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED,    int *)
 
 
 /*! @} - end defgroup vp8_decoder */
--- a/vpx_scale/generic/yv12config.c
+++ b/vpx_scale/generic/yv12config.c
@@ -81,6 +81,8 @@
 
         ybf->u_buffer = ybf->buffer_alloc + yplane_size + (border / 2  * ybf->uv_stride) + border / 2;
         ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + (border / 2  * ybf->uv_stride) + border / 2;
+
+        ybf->corrupted = 0; /* assume not currupted by errors */
     }
     else
     {
--- a/vpx_scale/yv12config.h
+++ b/vpx_scale/yv12config.h
@@ -57,6 +57,8 @@
         int border;
         int frame_size;
         YUV_TYPE clrtype;
+
+        int corrupted;
     } YV12_BUFFER_CONFIG;
 
     int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int border);