Disable error concealment until first key frame is decoded
When error concealment is enabled the first key frame must be successfully received before error concealment is activated. Error concealment will be activated when the delta following delta frame is received. Also fixed a couple of bugs related to error tracking in multi-threading. And avoiding decoding corrupt residual when we have multiple non-resilient partitions. Change-Id: I45c4bb296e2f05f57624aef500a874faf431a60d
This commit is contained in:
@@ -183,6 +183,7 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd,
|
||||
unsigned int mb_idx)
|
||||
{
|
||||
int eobtotal = 0;
|
||||
int throw_residual = 0;
|
||||
MB_PREDICTION_MODE mode;
|
||||
int i;
|
||||
|
||||
@@ -203,7 +204,8 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd,
|
||||
|
||||
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
|
||||
* mb_skip_coeff are zero.
|
||||
@@ -235,14 +237,21 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *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 (pbi->ec_enabled &&
|
||||
(mb_idx >= pbi->mvs_corrupt_from_mb ||
|
||||
vp8dx_bool_error(xd->current_bc)))
|
||||
if (pbi->ec_active &&
|
||||
(mb_idx >= pbi->mvs_corrupt_from_mb || throw_residual))
|
||||
{
|
||||
/* MB with corrupt residuals or corrupt mode/motion vectors.
|
||||
* Better to use the predictor as reconstruction.
|
||||
*/
|
||||
pbi->frame_corrupt_residual = 1;
|
||||
vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff));
|
||||
vp8_conceal_corrupt_mb(xd);
|
||||
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;
|
||||
|
||||
#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
|
||||
* conceal with an inter block. Interpolate MVs from neighboring MBs
|
||||
*
|
||||
* 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);
|
||||
int corrupt_residual = (!pbi->independent_partitions &&
|
||||
pbi->frame_corrupt_residual) ||
|
||||
vp8dx_bool_error(xd->current_bc);
|
||||
if (pbi->ec_active &&
|
||||
xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME &&
|
||||
corrupt_residual)
|
||||
{
|
||||
/* We have an intra block with corrupt coefficients, better to
|
||||
* conceal with an inter block. Interpolate MVs from neighboring
|
||||
* MBs.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -519,7 +534,7 @@ static void setup_token_decoder(VP8D_COMP *pbi,
|
||||
(TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2);
|
||||
/* Only update the multi_token_partition field if we are sure the value
|
||||
* 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;
|
||||
|
||||
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))
|
||||
partition_size = read_partition_size(partition_size_ptr);
|
||||
else if(pbi->ec_enabled)
|
||||
else if (pbi->ec_active)
|
||||
partition_size = bytes_left;
|
||||
else
|
||||
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(pbi->ec_enabled)
|
||||
if (pbi->ec_active)
|
||||
partition_size = bytes_left;
|
||||
else
|
||||
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_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;
|
||||
@@ -681,6 +699,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
||||
int mb_row;
|
||||
int i, j, k, l;
|
||||
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)
|
||||
{
|
||||
@@ -694,7 +714,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
||||
|
||||
if (data_end - data < 3)
|
||||
{
|
||||
if (pbi->ec_enabled)
|
||||
if (pbi->ec_active)
|
||||
{
|
||||
/* Declare the missing frame as an inter frame since it will
|
||||
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 += 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))
|
||||
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
||||
"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
|
||||
* 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)
|
||||
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
|
||||
* 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->horiz_scale = data[4] >> 6;
|
||||
@@ -944,7 +964,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
||||
#if CONFIG_ERROR_CONCEALMENT
|
||||
/* Assume we shouldn't refresh golden if the bit is missing */
|
||||
xd->corrupted |= vp8dx_bool_error(bc);
|
||||
if (pbi->ec_enabled && xd->corrupted)
|
||||
if (pbi->ec_active && xd->corrupted)
|
||||
pc->refresh_golden_frame = 0;
|
||||
#endif
|
||||
|
||||
@@ -952,7 +972,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
||||
#if CONFIG_ERROR_CONCEALMENT
|
||||
/* Assume we shouldn't refresh altref if the bit is missing */
|
||||
xd->corrupted |= vp8dx_bool_error(bc);
|
||||
if (pbi->ec_enabled && xd->corrupted)
|
||||
if (pbi->ec_active && xd->corrupted)
|
||||
pc->refresh_alt_ref_frame = 0;
|
||||
#endif
|
||||
|
||||
@@ -982,7 +1002,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
||||
#if CONFIG_ERROR_CONCEALMENT
|
||||
/* Assume we should refresh the last frame if the bit is missing */
|
||||
xd->corrupted |= vp8dx_bool_error(bc);
|
||||
if (pbi->ec_enabled && xd->corrupted)
|
||||
if (pbi->ec_active && xd->corrupted)
|
||||
pc->refresh_last_frame = 1;
|
||||
#endif
|
||||
|
||||
@@ -1000,6 +1020,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
||||
}
|
||||
|
||||
{
|
||||
pbi->independent_partitions = 1;
|
||||
|
||||
/* read coef probability tree */
|
||||
for (i = 0; i < BLOCK_TYPES; i++)
|
||||
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);
|
||||
|
||||
}
|
||||
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);
|
||||
|
||||
#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)
|
||||
{
|
||||
/* 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 (pbi->b_multithreaded_rd && pc->multi_token_partition != ONE_PARTITION)
|
||||
{
|
||||
int i;
|
||||
pbi->frame_corrupt_residual = 0;
|
||||
vp8mt_decode_mb_rows(pbi, xd);
|
||||
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
|
||||
#endif
|
||||
{
|
||||
int ibc = 0;
|
||||
int num_part = 1 << pc->multi_token_partition;
|
||||
pbi->frame_corrupt_residual = 0;
|
||||
|
||||
/* Decode the individual macro block */
|
||||
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);
|
||||
}
|
||||
corrupt_tokens |= xd->corrupted;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
pc->yv12_fb[pc->new_fb_idx].corrupted |= corrupt_tokens;
|
||||
|
||||
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); */
|
||||
|
||||
@@ -1102,6 +1141,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
||||
if (pc->refresh_entropy_probs == 0)
|
||||
{
|
||||
vpx_memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc));
|
||||
pbi->independent_partitions = prev_independent_partitions;
|
||||
}
|
||||
|
||||
#ifdef PACKET_TESTING
|
||||
|
||||
Reference in New Issue
Block a user