Merge "Disable error concealment until first key frame is decoded"

This commit is contained in:
John Koleszar 2011-08-12 11:45:26 -07:00 committed by Code Review
commit 4645c89889
4 changed files with 167 additions and 72 deletions

View File

@ -183,6 +183,7 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd,
unsigned int mb_idx) unsigned int mb_idx)
{ {
int eobtotal = 0; int eobtotal = 0;
int throw_residual = 0;
MB_PREDICTION_MODE mode; MB_PREDICTION_MODE mode;
int i; int i;
@ -203,7 +204,8 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd,
mode = xd->mode_info_context->mbmi.mode; mode = xd->mode_info_context->mbmi.mode;
if (eobtotal == 0 && mode != B_PRED && mode != SPLITMV) if (eobtotal == 0 && mode != B_PRED && mode != SPLITMV &&
!vp8dx_bool_error(xd->current_bc))
{ {
/* Special case: Force the loopfilter to skip when eobtotal and /* Special case: Force the loopfilter to skip when eobtotal and
* mb_skip_coeff are zero. * mb_skip_coeff are zero.
@ -235,14 +237,21 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd,
vp8_build_inter_predictors_mb(xd); vp8_build_inter_predictors_mb(xd);
} }
/* When we have independent partitions we can apply residual even
* though other partitions within the frame are corrupt.
*/
throw_residual = (!pbi->independent_partitions &&
pbi->frame_corrupt_residual);
throw_residual = (throw_residual || vp8dx_bool_error(xd->current_bc));
#if CONFIG_ERROR_CONCEALMENT #if CONFIG_ERROR_CONCEALMENT
if (pbi->ec_enabled && if (pbi->ec_active &&
(mb_idx >= pbi->mvs_corrupt_from_mb || (mb_idx >= pbi->mvs_corrupt_from_mb || throw_residual))
vp8dx_bool_error(xd->current_bc)))
{ {
/* MB with corrupt residuals or corrupt mode/motion vectors. /* MB with corrupt residuals or corrupt mode/motion vectors.
* Better to use the predictor as reconstruction. * Better to use the predictor as reconstruction.
*/ */
pbi->frame_corrupt_residual = 1;
vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff)); vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff));
vp8_conceal_corrupt_mb(xd); vp8_conceal_corrupt_mb(xd);
return; return;
@ -376,22 +385,28 @@ decode_mb_row(VP8D_COMP *pbi, VP8_COMMON *pc, int mb_row, MACROBLOCKD *xd)
xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
#if CONFIG_ERROR_CONCEALMENT #if CONFIG_ERROR_CONCEALMENT
if (pbi->ec_enabled &&
xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME &&
vp8dx_bool_error(xd->current_bc))
{ {
/* We have an intra block with corrupt coefficients, better to int corrupt_residual = (!pbi->independent_partitions &&
* conceal with an inter block. Interpolate MVs from neighboring MBs pbi->frame_corrupt_residual) ||
* vp8dx_bool_error(xd->current_bc);
* Note that for the first mb with corrupt residual in a frame, if (pbi->ec_active &&
* we might not discover that before decoding the residual. That xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME &&
* happens after this check, and therefore no inter concealment will corrupt_residual)
* be done. {
*/ /* We have an intra block with corrupt coefficients, better to
vp8_interpolate_motion(xd, * conceal with an inter block. Interpolate MVs from neighboring
mb_row, mb_col, * MBs.
pc->mb_rows, pc->mb_cols, *
pc->mode_info_stride); * Note that for the first mb with corrupt residual in a frame,
* we might not discover that before decoding the residual. That
* happens after this check, and therefore no inter concealment
* will be done.
*/
vp8_interpolate_motion(xd,
mb_row, mb_col,
pc->mb_rows, pc->mb_cols,
pc->mode_info_stride);
}
} }
#endif #endif
@ -519,7 +534,7 @@ static void setup_token_decoder(VP8D_COMP *pbi,
(TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2); (TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2);
/* Only update the multi_token_partition field if we are sure the value /* Only update the multi_token_partition field if we are sure the value
* is correct. */ * is correct. */
if (!pbi->ec_enabled || !vp8dx_bool_error(&pbi->bc)) if (!pbi->ec_active || !vp8dx_bool_error(&pbi->bc))
pc->multi_token_partition = multi_token_partition; pc->multi_token_partition = multi_token_partition;
num_part = 1 << pc->multi_token_partition; num_part = 1 << pc->multi_token_partition;
@ -551,7 +566,7 @@ static void setup_token_decoder(VP8D_COMP *pbi,
{ {
if (read_is_valid(partition_size_ptr, 3, user_data_end)) if (read_is_valid(partition_size_ptr, 3, user_data_end))
partition_size = read_partition_size(partition_size_ptr); partition_size = read_partition_size(partition_size_ptr);
else if(pbi->ec_enabled) else if (pbi->ec_active)
partition_size = bytes_left; partition_size = bytes_left;
else else
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
@ -566,7 +581,7 @@ static void setup_token_decoder(VP8D_COMP *pbi,
*/ */
if (!read_is_valid(partition, partition_size, user_data_end)) if (!read_is_valid(partition, partition_size, user_data_end))
{ {
if(pbi->ec_enabled) if (pbi->ec_active)
partition_size = bytes_left; partition_size = bytes_left;
else else
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
@ -659,6 +674,9 @@ static void init_frame(VP8D_COMP *pbi)
xd->subpixel_predict8x8 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear8x8); xd->subpixel_predict8x8 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear8x8);
xd->subpixel_predict16x16 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear16x16); xd->subpixel_predict16x16 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear16x16);
} }
if (pbi->decoded_key_frame && pbi->ec_enabled && !pbi->ec_active)
pbi->ec_active = 1;
} }
xd->left_context = &pc->left_context; xd->left_context = &pc->left_context;
@ -681,6 +699,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
int mb_row; int mb_row;
int i, j, k, l; int i, j, k, l;
const int *const mb_feature_data_bits = vp8_mb_feature_data_bits; const int *const mb_feature_data_bits = vp8_mb_feature_data_bits;
int corrupt_tokens = 0;
int prev_independent_partitions = pbi->independent_partitions;
if (pbi->input_partition) if (pbi->input_partition)
{ {
@ -694,7 +714,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
if (data_end - data < 3) if (data_end - data < 3)
{ {
if (pbi->ec_enabled) if (pbi->ec_active)
{ {
/* Declare the missing frame as an inter frame since it will /* Declare the missing frame as an inter frame since it will
be handled as an inter frame when we have estimated its be handled as an inter frame when we have estimated its
@ -719,7 +739,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
(data[0] | (data[1] << 8) | (data[2] << 16)) >> 5; (data[0] | (data[1] << 8) | (data[2] << 16)) >> 5;
data += 3; data += 3;
if (!pbi->ec_enabled && (data + first_partition_length_in_bytes > data_end if (!pbi->ec_active && (data + first_partition_length_in_bytes > data_end
|| data + first_partition_length_in_bytes < data)) || data + first_partition_length_in_bytes < data))
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
"Truncated packet or corrupt partition 0 length"); "Truncated packet or corrupt partition 0 length");
@ -734,7 +754,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
/* When error concealment is enabled we should only check the sync /* When error concealment is enabled we should only check the sync
* code if we have enough bits available * code if we have enough bits available
*/ */
if (!pbi->ec_enabled || data + 3 < data_end) if (!pbi->ec_active || data + 3 < data_end)
{ {
if (data[0] != 0x9d || data[1] != 0x01 || data[2] != 0x2a) if (data[0] != 0x9d || data[1] != 0x01 || data[2] != 0x2a)
vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM, vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM,
@ -745,7 +765,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
* if we have enough data. Otherwise we will end up with the wrong * if we have enough data. Otherwise we will end up with the wrong
* size. * size.
*/ */
if (!pbi->ec_enabled || data + 6 < data_end) if (!pbi->ec_active || data + 6 < data_end)
{ {
pc->Width = (data[3] | (data[4] << 8)) & 0x3fff; pc->Width = (data[3] | (data[4] << 8)) & 0x3fff;
pc->horiz_scale = data[4] >> 6; pc->horiz_scale = data[4] >> 6;
@ -944,7 +964,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
#if CONFIG_ERROR_CONCEALMENT #if CONFIG_ERROR_CONCEALMENT
/* Assume we shouldn't refresh golden if the bit is missing */ /* Assume we shouldn't refresh golden if the bit is missing */
xd->corrupted |= vp8dx_bool_error(bc); xd->corrupted |= vp8dx_bool_error(bc);
if (pbi->ec_enabled && xd->corrupted) if (pbi->ec_active && xd->corrupted)
pc->refresh_golden_frame = 0; pc->refresh_golden_frame = 0;
#endif #endif
@ -952,7 +972,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
#if CONFIG_ERROR_CONCEALMENT #if CONFIG_ERROR_CONCEALMENT
/* Assume we shouldn't refresh altref if the bit is missing */ /* Assume we shouldn't refresh altref if the bit is missing */
xd->corrupted |= vp8dx_bool_error(bc); xd->corrupted |= vp8dx_bool_error(bc);
if (pbi->ec_enabled && xd->corrupted) if (pbi->ec_active && xd->corrupted)
pc->refresh_alt_ref_frame = 0; pc->refresh_alt_ref_frame = 0;
#endif #endif
@ -982,7 +1002,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
#if CONFIG_ERROR_CONCEALMENT #if CONFIG_ERROR_CONCEALMENT
/* Assume we should refresh the last frame if the bit is missing */ /* Assume we should refresh the last frame if the bit is missing */
xd->corrupted |= vp8dx_bool_error(bc); xd->corrupted |= vp8dx_bool_error(bc);
if (pbi->ec_enabled && xd->corrupted) if (pbi->ec_active && xd->corrupted)
pc->refresh_last_frame = 1; pc->refresh_last_frame = 1;
#endif #endif
@ -1000,6 +1020,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
} }
{ {
pbi->independent_partitions = 1;
/* read coef probability tree */ /* read coef probability tree */
for (i = 0; i < BLOCK_TYPES; i++) for (i = 0; i < BLOCK_TYPES; i++)
for (j = 0; j < COEF_BANDS; j++) for (j = 0; j < COEF_BANDS; j++)
@ -1014,6 +1036,9 @@ int vp8_decode_frame(VP8D_COMP *pbi)
*p = (vp8_prob)vp8_read_literal(bc, 8); *p = (vp8_prob)vp8_read_literal(bc, 8);
} }
if (k > 0 && *p != pc->fc.coef_probs[i][j][k-1][l])
pbi->independent_partitions = 0;
} }
} }
@ -1040,7 +1065,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
vp8_decode_mode_mvs(pbi); vp8_decode_mode_mvs(pbi);
#if CONFIG_ERROR_CONCEALMENT #if CONFIG_ERROR_CONCEALMENT
if (pbi->ec_enabled && if (pbi->ec_active &&
pbi->mvs_corrupt_from_mb < (unsigned int)pc->mb_cols * pc->mb_rows) pbi->mvs_corrupt_from_mb < (unsigned int)pc->mb_cols * pc->mb_rows)
{ {
/* Motion vectors are missing in this frame. We will try to estimate /* Motion vectors are missing in this frame. We will try to estimate
@ -1054,14 +1079,19 @@ int vp8_decode_frame(VP8D_COMP *pbi)
#if CONFIG_MULTITHREAD #if CONFIG_MULTITHREAD
if (pbi->b_multithreaded_rd && pc->multi_token_partition != ONE_PARTITION) if (pbi->b_multithreaded_rd && pc->multi_token_partition != ONE_PARTITION)
{ {
int i;
pbi->frame_corrupt_residual = 0;
vp8mt_decode_mb_rows(pbi, xd); vp8mt_decode_mb_rows(pbi, xd);
vp8_yv12_extend_frame_borders_ptr(&pc->yv12_fb[pc->new_fb_idx]); /*cm->frame_to_show);*/ vp8_yv12_extend_frame_borders_ptr(&pc->yv12_fb[pc->new_fb_idx]); /*cm->frame_to_show);*/
for (i = 0; i < pbi->decoding_thread_count; ++i)
corrupt_tokens |= pbi->mb_row_di[i].mbd.corrupted;
} }
else else
#endif #endif
{ {
int ibc = 0; int ibc = 0;
int num_part = 1 << pc->multi_token_partition; int num_part = 1 << pc->multi_token_partition;
pbi->frame_corrupt_residual = 0;
/* Decode the individual macro block */ /* Decode the individual macro block */
for (mb_row = 0; mb_row < pc->mb_rows; mb_row++) for (mb_row = 0; mb_row < pc->mb_rows; mb_row++)
@ -1078,17 +1108,26 @@ int vp8_decode_frame(VP8D_COMP *pbi)
decode_mb_row(pbi, pc, mb_row, xd); decode_mb_row(pbi, pc, mb_row, xd);
} }
corrupt_tokens |= xd->corrupted;
} }
stop_token_decoder(pbi); stop_token_decoder(pbi);
/* Collect information about decoder corruption. */ /* Collect information about decoder corruption. */
/* 1. Check first boolean decoder for errors. */ /* 1. Check first boolean decoder for errors. */
pc->yv12_fb[pc->new_fb_idx].corrupted = pc->yv12_fb[pc->new_fb_idx].corrupted = vp8dx_bool_error(bc);
vp8dx_bool_error(bc);
/* 2. Check the macroblock information */ /* 2. Check the macroblock information */
pc->yv12_fb[pc->new_fb_idx].corrupted |= pc->yv12_fb[pc->new_fb_idx].corrupted |= corrupt_tokens;
xd->corrupted;
if (!pbi->decoded_key_frame)
{
if (pc->frame_type == KEY_FRAME &&
!pc->yv12_fb[pc->new_fb_idx].corrupted)
pbi->decoded_key_frame = 1;
else
vpx_internal_error(&pbi->common.error, VPX_CODEC_CORRUPT_FRAME,
"A stream must start with a complete key frame");
}
/* vpx_log("Decoder: Frame Decoded, Size Roughly:%d bytes \n",bc->pos+pbi->bc2.pos); */ /* vpx_log("Decoder: Frame Decoded, Size Roughly:%d bytes \n",bc->pos+pbi->bc2.pos); */
@ -1102,6 +1141,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
if (pc->refresh_entropy_probs == 0) if (pc->refresh_entropy_probs == 0)
{ {
vpx_memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc)); vpx_memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc));
pbi->independent_partitions = prev_independent_partitions;
} }
#ifdef PACKET_TESTING #ifdef PACKET_TESTING

View File

@ -101,9 +101,21 @@ VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf)
#else #else
pbi->ec_enabled = 0; pbi->ec_enabled = 0;
#endif #endif
/* Error concealment is activated after a key frame has been
* decoded without errors when error concealment is enabled.
*/
pbi->ec_active = 0;
pbi->decoded_key_frame = 0;
pbi->input_partition = oxcf->input_partition; pbi->input_partition = oxcf->input_partition;
/* Independent partitions is activated when a frame updates the
* token probability table to have equal probabilities over the
* PREV_COEF context.
*/
pbi->independent_partitions = 0;
return (VP8D_PTR) pbi; return (VP8D_PTR) pbi;
} }
@ -346,11 +358,15 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
/* If error concealment is disabled we won't signal missing frames to /* If error concealment is disabled we won't signal missing frames to
* the decoder. * the decoder.
*/ */
if (!pbi->ec_enabled) if (!pbi->ec_active)
{ {
/* Signal that we have no frame to show. */ /* Signal that we have no frame to show. */
cm->show_frame = 0; cm->show_frame = 0;
pbi->num_partitions = 0;
if (pbi->input_partition)
pbi->common.multi_token_partition = 0;
/* Nothing more to do. */ /* Nothing more to do. */
return 0; return 0;
} }
@ -379,6 +395,10 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
#endif #endif
pbi->common.error.setjmp = 0; pbi->common.error.setjmp = 0;
pbi->num_partitions = 0;
if (pbi->input_partition)
pbi->common.multi_token_partition = 0;
/* We do not know if the missing frame(s) was supposed to update /* We do not know if the missing frame(s) was supposed to update
* any of the reference buffers, but we act conservative and * any of the reference buffers, but we act conservative and
* mark only the last buffer as corrupted. * mark only the last buffer as corrupted.

View File

@ -132,7 +132,11 @@ typedef struct VP8Decompressor
unsigned int mvs_corrupt_from_mb; unsigned int mvs_corrupt_from_mb;
#endif #endif
int ec_enabled; int ec_enabled;
int ec_active;
int input_partition; int input_partition;
int decoded_key_frame;
int independent_partitions;
int frame_corrupt_residual;
} VP8D_COMP; } VP8D_COMP;

View File

@ -93,6 +93,7 @@ static void setup_decoding_thread_data(VP8D_COMP *pbi, MACROBLOCKD *xd, MB_ROW_D
static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, int mb_row, int mb_col) static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, int mb_row, int mb_col)
{ {
int eobtotal = 0; int eobtotal = 0;
int throw_residual = 0;
int i, do_clamp = xd->mode_info_context->mbmi.need_to_clamp_mvs; int i, do_clamp = xd->mode_info_context->mbmi.need_to_clamp_mvs;
if (xd->mode_info_context->mbmi.mb_skip_coeff) if (xd->mode_info_context->mbmi.mb_skip_coeff)
@ -112,7 +113,7 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, int mb_row, int m
eobtotal |= (xd->mode_info_context->mbmi.mode == B_PRED || eobtotal |= (xd->mode_info_context->mbmi.mode == B_PRED ||
xd->mode_info_context->mbmi.mode == SPLITMV); xd->mode_info_context->mbmi.mode == SPLITMV);
if (!eobtotal) if (!eobtotal && !vp8dx_bool_error(xd->current_bc))
{ {
/* Special case: Force the loopfilter to skip when eobtotal and /* Special case: Force the loopfilter to skip when eobtotal and
* mb_skip_coeff are zero. * mb_skip_coeff are zero.
@ -154,14 +155,22 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, int mb_row, int m
vp8_build_inter_predictors_mb(xd); vp8_build_inter_predictors_mb(xd);
} }
/* When we have independent partitions we can apply residual even
* though other partitions within the frame are corrupt.
*/
throw_residual = (!pbi->independent_partitions &&
pbi->frame_corrupt_residual);
throw_residual = (throw_residual || vp8dx_bool_error(xd->current_bc));
#if CONFIG_ERROR_CONCEALMENT #if CONFIG_ERROR_CONCEALMENT
if (pbi->ec_enabled && if (pbi->ec_active &&
(mb_row * pbi->common.mb_cols + mb_col >= pbi->mvs_corrupt_from_mb || (mb_row * pbi->common.mb_cols + mb_col >= pbi->mvs_corrupt_from_mb ||
vp8dx_bool_error(xd->current_bc))) throw_residual))
{ {
/* MB with corrupt residuals or corrupt mode/motion vectors. /* MB with corrupt residuals or corrupt mode/motion vectors.
* Better to use the predictor as reconstruction. * Better to use the predictor as reconstruction.
*/ */
pbi->frame_corrupt_residual = 1;
vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff)); vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff));
vp8_conceal_corrupt_mb(xd); vp8_conceal_corrupt_mb(xd);
return; return;
@ -314,25 +323,32 @@ static THREAD_FUNCTION thread_decoding_proc(void *p_data)
xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
#if CONFIG_ERROR_CONCEALMENT #if CONFIG_ERROR_CONCEALMENT
if (pbi->ec_enabled &&
(xd->mode_info_context->mbmi.ref_frame ==
INTRA_FRAME) &&
vp8dx_bool_error(xd->current_bc))
{ {
/* We have an intra block with corrupt coefficients, int corrupt_residual =
* better to conceal with an inter block. (!pbi->independent_partitions &&
* Interpolate MVs from neighboring MBs pbi->frame_corrupt_residual) ||
* vp8dx_bool_error(xd->current_bc);
* Note that for the first mb with corrupt residual if (pbi->ec_active &&
* in a frame, we might not discover that before (xd->mode_info_context->mbmi.ref_frame ==
* decoding the residual. That happens after this INTRA_FRAME) &&
* check, and therefore no inter concealment will be corrupt_residual)
* done. {
*/ /* We have an intra block with corrupt
vp8_interpolate_motion(xd, * coefficients, better to conceal with an inter
mb_row, mb_col, * block.
pc->mb_rows, pc->mb_cols, * Interpolate MVs from neighboring MBs
pc->mode_info_stride); *
* Note that for the first mb with corrupt
* residual in a frame, we might not discover
* that before decoding the residual. That
* happens after this check, and therefore no
* inter concealment will be done.
*/
vp8_interpolate_motion(xd,
mb_row, mb_col,
pc->mb_rows, pc->mb_cols,
pc->mode_info_stride);
}
} }
#endif #endif
@ -355,9 +371,19 @@ static THREAD_FUNCTION thread_decoding_proc(void *p_data)
xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset; 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; 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); vp8_build_uvmvs(xd, pc->full_pixel);
decode_macroblock(pbi, xd, mb_row, mb_col); 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) if (pbi->common.filter_level)
{ {
int skip_lf = (xd->mode_info_context->mbmi.mode != B_PRED && int skip_lf = (xd->mode_info_context->mbmi.mode != B_PRED &&
@ -803,23 +829,28 @@ void vp8mt_decode_mb_rows( VP8D_COMP *pbi, MACROBLOCKD *xd)
xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
#if CONFIG_ERROR_CONCEALMENT #if CONFIG_ERROR_CONCEALMENT
if (pbi->ec_enabled &&
(xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) &&
vp8dx_bool_error(xd->current_bc))
{ {
/* We have an intra block with corrupt coefficients, better int corrupt_residual = (!pbi->independent_partitions &&
* to conceal with an inter block. Interpolate MVs from pbi->frame_corrupt_residual) ||
* neighboring MBs vp8dx_bool_error(xd->current_bc);
* if (pbi->ec_active &&
* Note that for the first mb with corrupt residual in a (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) &&
* frame, we might not discover that before decoding the corrupt_residual)
* residual. That happens after this check, and therefore no {
* inter concealment will be done. /* We have an intra block with corrupt coefficients,
*/ * better to conceal with an inter block. Interpolate
vp8_interpolate_motion(xd, * MVs from neighboring MBs
mb_row, mb_col, *
pc->mb_rows, pc->mb_cols, * Note that for the first mb with corrupt residual in a
pc->mode_info_stride); * frame, we might not discover that before decoding the
* residual. That happens after this check, and
* therefore no inter concealment will be done.
*/
vp8_interpolate_motion(xd,
mb_row, mb_col,
pc->mb_rows, pc->mb_cols,
pc->mode_info_stride);
}
} }
#endif #endif