diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h index a38f0b72b391c559e42845a305c8f0cd7aa558c6..5a8991e65b86d83982f5802b0ab4c144ec1cce4c 100644 --- a/vp8/common/blockd.h +++ b/vp8/common/blockd.h @@ -282,6 +282,8 @@ typedef struct void *current_bc; + int corrupted; + #if CONFIG_RUNTIME_CPU_DETECT struct VP8_COMMON_RTCD *rtcd; #endif diff --git a/vp8/decoder/dboolhuff.h b/vp8/decoder/dboolhuff.h index c851aa7e57f39f3ffab2d68b855b70decc35ca39..d14f4dcebc86508bb1782a5840d5f0013044d6fa 100644 --- a/vp8/decoder/dboolhuff.h +++ b/vp8/decoder/dboolhuff.h @@ -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 diff --git a/vp8/decoder/decodframe.c b/vp8/decoder/decodframe.c index 4702faeedc48a853b312baf7c6da80c7d2ee75c5..2ce1b86b9ba74cf5f1be3006feecb35e9abbe894 100644 --- a/vp8/decoder/decodframe.c +++ b/vp8/decoder/decodframe.c @@ -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 */ diff --git a/vp8/decoder/onyxd_if.c b/vp8/decoder/onyxd_if.c index aa2709f5b3a7e4d54b25305eee105fe569a072df..d32b8cd651ac2ba07ac56324e8ae768b1a807ad1 100644 --- a/vp8/decoder/onyxd_if.c +++ b/vp8/decoder/onyxd_if.c @@ -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; diff --git a/vp8/decoder/threading.c b/vp8/decoder/threading.c index fea4e1cc1ad19579b4540f7818efe089f66c9916..2e10c10599ee4add02bd0b72d30a00f255cfa630 100644 --- a/vp8/decoder/threading.c +++ b/vp8/decoder/threading.c @@ -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 */ diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c index cf32d1f38bbfcd4ee1bd3653645b73010c519434..7d4d7f65b8aaeccdfc5867cfaed0f93bbbf21679 100644 --- a/vp8/vp8_dx_iface.c +++ b/vp8/vp8_dx_iface.c @@ -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}, }; diff --git a/vpx/src/vpx_decoder.c b/vpx/src/vpx_decoder.c index b52470b5119d1c292ad54e69e55c81c701529456..27049a51e0b86d885c21cf280b5f4a3c38d9e484 100644 --- a/vpx/src/vpx_decoder.c +++ b/vpx/src/vpx_decoder.c @@ -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; diff --git a/vpx/vp8dx.h b/vpx/vp8dx.h index 9feab7cc262aad799c83b907c212a10c9957e278..16bc07c608c7d67aed15e6718ff57942cd9c4df9 100644 --- a/vpx/vp8dx.h +++ b/vpx/vp8dx.h @@ -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 */ diff --git a/vpx_scale/generic/yv12config.c b/vpx_scale/generic/yv12config.c index d9d228551bec8d337967e0df0b3bc6972e0498a4..e7c5b189c07ec9b9026de058b25c1078e86edd1a 100644 --- a/vpx_scale/generic/yv12config.c +++ b/vpx_scale/generic/yv12config.c @@ -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 { diff --git a/vpx_scale/yv12config.h b/vpx_scale/yv12config.h index 5dcee818a1d2b7cdb744ee2db1180c2c071fe314..0b08db3efa5decc36d41ad5301aaa9fba3608844 100644 --- a/vpx_scale/yv12config.h +++ b/vpx_scale/yv12config.h @@ -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);