diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h index a38f0b72b..5a8991e65 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 c851aa7e5..d14f4dceb 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 9305a0556..d3972b324 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; @@ -555,6 +563,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) @@ -570,6 +579,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"); @@ -891,6 +904,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 adc9f8ec8..adbb1f336 100644 --- a/vp8/decoder/onyxd_if.c +++ b/vp8/decoder/onyxd_if.c @@ -329,6 +329,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) @@ -351,6 +368,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 dac990a26..fc8406eae 100644 --- a/vp8/decoder/threading.c +++ b/vp8/decoder/threading.c @@ -890,9 +890,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/encoder/firstpass.c b/vp8/encoder/firstpass.c index a78048153..1554f3d30 100644 --- a/vp8/encoder/firstpass.c +++ b/vp8/encoder/firstpass.c @@ -1487,7 +1487,7 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) // Break out conditions. if ( /* i>4 || */ // Break at cpi->max_gf_interval unless almost totally static - (i >= cpi->max_gf_interval && (loop_decay_rate < 0.99)) || + (i >= cpi->max_gf_interval && (decay_accumulator < 0.99)) || ( // Dont break out with a very short interval (i > MIN_GF_INTERVAL) && diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c index a2ad59662..1b1cf3b94 100644 --- a/vp8/vp8_dx_iface.c +++ b/vp8/vp8_dx_iface.c @@ -709,6 +709,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}, @@ -719,6 +738,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 b52470b51..27049a51e 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 9feab7cc2..16bc07c60 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 d9d228551..e7c5b189c 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 5dcee818a..0b08db3ef 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);