ref: 3d1f3fc6c9f20c9c42b51d3838a2ab10f2c362b5
parent: 939f64f68efc837a98a5c80913a4bde50b79854f
parent: 4645c89889aba53a1665934a42f082a23832f493
author: John Koleszar <jkoleszar@google.com>
date: Fri Aug 12 20:05:10 EDT 2011
Merge remote branch 'origin/master' into experimental Change-Id: Ie6bc53eb61dc772f308abce9bf93bcc67b38f670
--- a/vp8/decoder/decodemv.c
+++ b/vp8/decoder/decodemv.c
@@ -400,7 +400,7 @@
/* Clip "next_nearest" so that it does not extend to far out of image */
vp8_clamp_mv(mv, mb_to_left_edge, mb_to_right_edge,
mb_to_top_edge, mb_to_bottom_edge);
- break;
+ goto propagate_mv;
case NEARESTMV:
mv->as_int = nearest.as_int;
@@ -407,11 +407,11 @@
/* Clip "next_nearest" so that it does not extend to far out of image */
vp8_clamp_mv(mv, mb_to_left_edge, mb_to_right_edge,
mb_to_top_edge, mb_to_bottom_edge);
- break;
+ goto propagate_mv;
case ZEROMV:
mv->as_int = 0;
- break;
+ goto propagate_mv;
case NEWMV:
read_mv(bc, &mv->as_mv, (const MV_CONTEXT *) mvc);
@@ -428,8 +428,30 @@
mb_to_right_edge,
mb_to_top_edge,
mb_to_bottom_edge);
- break;
+ propagate_mv: /* same MV throughout */
+#if CONFIG_ERROR_CONCEALMENT
+ if(pbi->ec_enabled)
+ {
+ mi->bmi[ 0].mv.as_int =
+ mi->bmi[ 1].mv.as_int =
+ mi->bmi[ 2].mv.as_int =
+ mi->bmi[ 3].mv.as_int =
+ mi->bmi[ 4].mv.as_int =
+ mi->bmi[ 5].mv.as_int =
+ mi->bmi[ 6].mv.as_int =
+ mi->bmi[ 7].mv.as_int =
+ mi->bmi[ 8].mv.as_int =
+ mi->bmi[ 9].mv.as_int =
+ mi->bmi[10].mv.as_int =
+ mi->bmi[11].mv.as_int =
+ mi->bmi[12].mv.as_int =
+ mi->bmi[13].mv.as_int =
+ mi->bmi[14].mv.as_int =
+ mi->bmi[15].mv.as_int = mv->as_int;
+ }
+#endif
+ break;
default:;
#if CONFIG_DEBUG
assert(0);
--- a/vp8/decoder/decodframe.c
+++ b/vp8/decoder/decodframe.c
@@ -183,6 +183,7 @@
unsigned int mb_idx)
{
int eobtotal = 0;
+ int throw_residual = 0;
MB_PREDICTION_MODE mode;
int i;
@@ -203,7 +204,8 @@
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 @@
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 @@
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
@@ -495,6 +510,15 @@
#endif
}
+
+static int read_is_valid(const unsigned char *start,
+ size_t len,
+ const unsigned char *end)
+{
+ return (start + len > start && start + len <= end);
+}
+
+
static void setup_token_decoder(VP8D_COMP *pbi,
const unsigned char *cx_data)
{
@@ -510,7 +534,7 @@
(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;
@@ -529,26 +553,42 @@
for (i = 0; i < num_part; i++)
{
const unsigned char *partition_size_ptr = cx_data + i * 3;
- ptrdiff_t partition_size;
+ ptrdiff_t partition_size, bytes_left;
+ bytes_left = user_data_end - partition;
+
/* Calculate the length of this partition. The last partition
- * size is implicit.
+ * size is implicit. If the partition size can't be read, then
+ * either use the remaining data in the buffer (for EC mode)
+ * or throw an error.
*/
if (i < num_part - 1)
{
- partition_size = read_partition_size(partition_size_ptr);
+ if (read_is_valid(partition_size_ptr, 3, user_data_end))
+ partition_size = read_partition_size(partition_size_ptr);
+ else if (pbi->ec_active)
+ partition_size = bytes_left;
+ else
+ vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
+ "Truncated partition size data");
}
else
+ partition_size = bytes_left;
+
+ /* Validate the calculated partition length. If the buffer
+ * described by the partition can't be fully read, then restrict
+ * it to the portion that can be (for EC mode) or throw an error.
+ */
+ if (!read_is_valid(partition, partition_size, user_data_end))
{
- partition_size = user_data_end - partition;
+ if (pbi->ec_active)
+ partition_size = bytes_left;
+ else
+ vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
+ "Truncated packet or corrupt partition "
+ "%d length", i + 1);
}
- if (!pbi->ec_enabled && (partition + partition_size > user_data_end
- || partition + partition_size < partition))
- vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
- "Truncated packet or corrupt partition "
- "%d length", i + 1);
-
if (vp8dx_start_decode(bool_decoder, partition, partition_size))
vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate bool decoder %d", i + 1);
@@ -634,6 +674,9 @@
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;
@@ -656,6 +699,8 @@
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)
{
@@ -669,7 +714,7 @@
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
@@ -694,7 +739,7 @@
(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");
@@ -709,7 +754,7 @@
/* 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,
@@ -720,7 +765,7 @@
* 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;
@@ -919,7 +964,7 @@
#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
@@ -927,7 +972,7 @@
#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
@@ -957,7 +1002,7 @@
#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
@@ -975,6 +1020,8 @@
}
{
+ pbi->independent_partitions = 1;
+
/* read coef probability tree */
for (i = 0; i < BLOCK_TYPES; i++)
for (j = 0; j < COEF_BANDS; j++)
@@ -989,6 +1036,9 @@
*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;
+
}
}
@@ -1015,7 +1065,7 @@
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
@@ -1029,8 +1079,12 @@
#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
@@ -1037,6 +1091,7 @@
{
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++)
@@ -1053,6 +1108,7 @@
decode_mb_row(pbi, pc, mb_row, xd);
}
+ corrupt_tokens |= xd->corrupted;
}
stop_token_decoder(pbi);
@@ -1059,12 +1115,20 @@
/* 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); */
/* If this was a kf or Gf note the Q used */
@@ -1077,6 +1141,7 @@
if (pc->refresh_entropy_probs == 0)
{
vpx_memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc));
+ pbi->independent_partitions = prev_independent_partitions;
}
#ifdef PACKET_TESTING
--- a/vp8/decoder/onyxd_if.c
+++ b/vp8/decoder/onyxd_if.c
@@ -101,9 +101,21 @@
#else
pbi->ec_enabled = 0;
#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;
+ /* 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;
}
@@ -346,11 +358,15 @@
/* If error concealment is disabled we won't signal missing frames to
* the decoder.
*/
- if (!pbi->ec_enabled)
+ if (!pbi->ec_active)
{
/* Signal that we have no frame to show. */
cm->show_frame = 0;
+ pbi->num_partitions = 0;
+ if (pbi->input_partition)
+ pbi->common.multi_token_partition = 0;
+
/* Nothing more to do. */
return 0;
}
@@ -378,6 +394,10 @@
}
#endif
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
* any of the reference buffers, but we act conservative and
--- a/vp8/decoder/onyxd_int.h
+++ b/vp8/decoder/onyxd_int.h
@@ -132,7 +132,11 @@
unsigned int mvs_corrupt_from_mb;
#endif
int ec_enabled;
+ int ec_active;
int input_partition;
+ int decoded_key_frame;
+ int independent_partitions;
+ int frame_corrupt_residual;
} VP8D_COMP;
--- a/vp8/decoder/threading.c
+++ b/vp8/decoder/threading.c
@@ -93,6 +93,7 @@
static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, int mb_row, int mb_col)
{
int eobtotal = 0;
+ int throw_residual = 0;
int i, do_clamp = xd->mode_info_context->mbmi.need_to_clamp_mvs;
if (xd->mode_info_context->mbmi.mb_skip_coeff)
@@ -112,7 +113,7 @@
eobtotal |= (xd->mode_info_context->mbmi.mode == B_PRED ||
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
* mb_skip_coeff are zero.
@@ -154,14 +155,22 @@
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 &&
+ if (pbi->ec_active &&
(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.
* 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;
@@ -314,25 +323,32 @@
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
@@ -355,9 +371,19 @@
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);
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)
{
int skip_lf = (xd->mode_info_context->mbmi.mode != B_PRED &&
@@ -803,23 +829,28 @@
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