]> granicus.if.org Git - libvpx/commitdiff
Implement error tracking in the decoder
authorHenrik Lundin <hlundin@google.com>
Thu, 16 Dec 2010 15:46:31 +0000 (16:46 +0100)
committerHenrik Lundin <hlundin@google.com>
Wed, 19 Jan 2011 08:53:21 +0000 (09:53 +0100)
A new vpx_codec_control called VP8D_GET_FRAME_CORRUPTED. The output
from the function is non-zero if the last decoded frame contains
corruption due to packet losses.

The decoder is also modified to accept encoded frames of zero length.
A zero length frame indicates to the decoder that one or more frames
have been completely lost. This will mark the last decoded reference
buffer as corrupted. The data pointer can be NULL if the length is
zero.

Change-Id: Ic5902c785a281c6e05329deea958554b7a6c75ce

vp8/common/blockd.h
vp8/decoder/dboolhuff.h
vp8/decoder/decodframe.c
vp8/decoder/onyxd_if.c
vp8/decoder/threading.c
vp8/vp8_dx_iface.c
vpx/src/vpx_decoder.c
vpx/vp8dx.h
vpx_scale/generic/yv12config.c
vpx_scale/yv12config.h

index a38f0b72b391c559e42845a305c8f0cd7aa558c6..5a8991e65b86d83982f5802b0ab4c144ec1cce4c 100644 (file)
@@ -282,6 +282,8 @@ typedef struct
 
     void *current_bc;
 
+    int corrupted;
+
 #if CONFIG_RUNTIME_CPU_DETECT
     struct VP8_COMMON_RTCD  *rtcd;
 #endif
index c851aa7e57f39f3ffab2d68b855b70decc35ca39..d14f4dcebc86508bb1782a5840d5f0013044d6fa 100644 (file)
@@ -206,4 +206,29 @@ static int vp8_decode_value(BOOL_DECODER *br, int bits)
 
     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
index 4702faeedc48a853b312baf7c6da80c7d2ee75c5..2ce1b86b9ba74cf5f1be3006feecb35e9abbe894 100644 (file)
@@ -381,6 +381,12 @@ void vp8_decode_mb_row(VP8D_COMP *pbi,
         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 @@ void vp8_decode_mb_row(VP8D_COMP *pbi,
         */
         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;
@@ -556,6 +564,7 @@ static void init_frame(VP8D_COMP *pbi)
     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)
@@ -571,6 +580,10 @@ int vp8_decode_frame(VP8D_COMP *pbi)
     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");
@@ -892,6 +905,14 @@ int vp8_decode_frame(VP8D_COMP *pbi)
 
     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); */
 
     /* If this was a kf or Gf note the Q used */
index aa2709f5b3a7e4d54b25305eee105fe569a072df..d32b8cd651ac2ba07ac56324e8ae768b1a807ad1 100644 (file)
@@ -334,6 +334,23 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
 
     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)
@@ -356,6 +373,13 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
         }
 #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;
index fea4e1cc1ad19579b4540f7818efe089f66c9916..2e10c10599ee4add02bd0b72d30a00f255cfa630 100644 (file)
@@ -893,9 +893,18 @@ void vp8mt_decode_mb_rows( VP8D_COMP *pbi, MACROBLOCKD *xd)
                 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)
                 {
                     /* Save decoded MB last row data for next-row decoding */
index cf32d1f38bbfcd4ee1bd3653645b73010c519434..7d4d7f65b8aaeccdfc5867cfaed0f93bbbf21679 100644 (file)
@@ -708,6 +708,25 @@ static vpx_codec_err_t vp8_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
 }
 
 
+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},
@@ -718,6 +737,7 @@ vpx_codec_ctrl_fn_map_t vp8_ctf_maps[] =
     {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},
 };
 
index b52470b5119d1c292ad54e69e55c81c701529456..27049a51e0b86d885c21cf280b5f4a3c38d9e484 100644 (file)
@@ -118,7 +118,9 @@ vpx_codec_err_t vpx_codec_decode(vpx_codec_ctx_t    *ctx,
 {
     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;
index 9feab7cc262aad799c83b907c212a10c9957e278..16bc07c608c7d67aed15e6718ff57942cd9c4df9 100644 (file)
@@ -45,6 +45,7 @@ enum vp8d_dec_control_id
     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 @@ enum vp8d_dec_control_id
 
 
 VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES,   int *)
+VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED,    int *)
 
 
 /*! @} - end defgroup vp8_decoder */
index d9d228551bec8d337967e0df0b3bc6972e0498a4..e7c5b189c07ec9b9026de058b25c1078e86edd1a 100644 (file)
@@ -81,6 +81,8 @@ vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int
 
         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
     {
index 5dcee818a1d2b7cdb744ee2db1180c2c071fe314..0b08db3efa5decc36d41ad5301aaa9fba3608844 100644 (file)
@@ -57,6 +57,8 @@ extern "C"
         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);