Added a first simple version of error-concealment

Added a first very simple version of error-concealment which simply
repeats the last decoded motion vector for corrupt MBs.

Change-Id: Ia83e111649afe11870c3c66065977bd0610c4fa1
This commit is contained in:
Stefan Holmer
2011-02-01 17:30:51 +01:00
parent 1422ce5cff
commit 83a2b4e114
7 changed files with 198 additions and 56 deletions

View File

@@ -251,6 +251,7 @@ void vp8_mb_mode_mv_init(VP8D_COMP *pbi)
vp8_reader *const bc = & pbi->bc;
MV_CONTEXT *const mvc = pbi->common.fc.mvc;
pbi->mvs_corrupt_from_mb = -1;
pbi->prob_skip_false = 0;
if (pbi->common.mb_no_coeff_skip)
pbi->prob_skip_false = (vp8_prob)vp8_read_literal(bc, 8);
@@ -543,12 +544,18 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
while (++mb_col < pbi->common.mb_cols)
{
int mb_num = mb_row * pbi->common.mb_cols + mb_col;
/*vp8_read_mb_modes_mv(pbi, xd->mode_info_context, &xd->mode_info_context->mbmi, mb_row, mb_col);*/
if(pbi->common.frame_type == KEY_FRAME)
vp8_kfread_modes(pbi, mi, mb_row, mb_col);
else
vp8_read_mb_modes_mv(pbi, mi, &mi->mbmi, mb_row, mb_col);
/* look for corruption */
if (vp8dx_bool_error(&pbi->bc) && mb_num < pbi->mvs_corrupt_from_mb)
pbi->mvs_corrupt_from_mb = mb_num;
mi++; /* next macroblock */
}

View File

@@ -27,6 +27,7 @@
#include "decodemv.h"
#include "extend.h"
#include "error_concealment.h"
#include "vpx_mem/vpx_mem.h"
#include "idct.h"
#include "dequantize.h"
@@ -176,7 +177,7 @@ void clamp_mvs(MACROBLOCKD *xd)
}
void vp8_decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd)
void vp8_decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, unsigned int mb_idx)
{
int eobtotal = 0;
int i, do_clamp = xd->mode_info_context->mbmi.need_to_clamp_mvs;
@@ -225,6 +226,14 @@ void vp8_decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd)
vp8_build_inter_predictors_mb(xd);
}
/* TODO(holmer): change when we have MB level error tracking */
if (xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME &&
(xd->corrupted || mb_idx >= pbi->mvs_corrupt_from_mb))
{
vp8_conceal_corrupt_block(xd);
return;
}
/* dequantization and idct */
if (xd->mode_info_context->mbmi.mode != B_PRED && xd->mode_info_context->mbmi.mode != SPLITMV)
{
@@ -395,7 +404,7 @@ void vp8_decode_mb_row(VP8D_COMP *pbi,
else
pbi->debugoutput =0;
*/
vp8_decode_macroblock(pbi, xd);
vp8_decode_macroblock(pbi, xd, mb_row * pc->mb_cols + mb_col);
/* check if the boolean decoder has suffered an error */
xd->corrupted |= vp8dx_bool_error(xd->current_bc);
@@ -469,8 +478,8 @@ static void setup_token_decoder(VP8D_COMP *pbi,
partition_size = user_data_end - partition;
}
if (partition + partition_size > user_data_end
|| partition + partition_size < partition)
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);
@@ -584,8 +593,25 @@ int vp8_decode_frame(VP8D_COMP *pbi)
pc->yv12_fb[pc->new_fb_idx].corrupted = 0;
if (data_end - data < 3)
{
if (pbi->ec_enabled)
{
/* Declare the missing frame as an inter frame since it will
be handled as an inter frame when we have estimated its
motion vectors. */
pc->frame_type = INTER_FRAME;
pc->version = 0;
pc->show_frame = 1;
first_partition_length_in_bytes = 0;
}
else
{
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
"Truncated packet");
}
}
else
{
pc->frame_type = (FRAME_TYPE)(data[0] & 1);
pc->version = (data[0] >> 1) & 7;
pc->show_frame = (data[0] >> 4) & 1;
@@ -593,8 +619,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
(data[0] | (data[1] << 8) | (data[2] << 16)) >> 5;
data += 3;
if (data + first_partition_length_in_bytes > data_end
|| data + first_partition_length_in_bytes < data)
if (!pbi->ec_enabled && (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");
vp8_setup_version(pc);
@@ -605,7 +631,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
const int Height = pc->Height;
/* vet via sync code */
if (data[0] != 0x9d || data[1] != 0x01 || data[2] != 0x2a)
if (!pbi->ec_enabled &&
(data[0] != 0x9d || data[1] != 0x01 || data[2] != 0x2a))
vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM,
"Invalid frame sync code");
@@ -643,6 +670,7 @@ int vp8_decode_frame(VP8D_COMP *pbi)
#endif
}
}
}
if (pc->Width == 0 || pc->Height == 0)
{
@@ -862,6 +890,11 @@ int vp8_decode_frame(VP8D_COMP *pbi)
vp8_decode_mode_mvs(pbi);
if (pbi->ec_enabled && pbi->mvs_corrupt_from_mb < (unsigned int)pc->mb_cols * pc->mb_rows)
{
vp8_estimate_missing_mvs(pbi);
}
vpx_memset(pc->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES) * pc->mb_cols);
vpx_memcpy(&xd->block[0].bmi, &xd->mode_info_context->bmi[0], sizeof(B_MODE_INFO));

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2011 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "error_concealment.h"
#include "onyxd_int.h"
#include "vpx_mem/vpx_mem.h"
void vp8_estimate_missing_mvs(VP8D_COMP *pbi)
{
VP8_COMMON *const pc = &pbi->common;
unsigned int first_corrupt = pbi->mvs_corrupt_from_mb;
const unsigned int num_mbs = pc->mb_rows * pc->mb_cols;
if (first_corrupt < num_mbs)
{
MODE_INFO *mi = pc->mi;
MODE_INFO *correct_mi;
const int num_corrupt = num_mbs - first_corrupt;
int i;
int mb_row, mb_col;
if (first_corrupt == 0)
{
/* if the first MB is corrupt we just copy from it
the previous frame */
mi[0].mbmi.mv.as_int = 0;
mi[0].mbmi.mode = ZEROMV;
mi[0].mbmi.uv_mode = ZEROMV;
mi[0].mbmi.ref_frame = LAST_FRAME;
first_corrupt = 1;
correct_mi = mi + 1;
}
for (mb_row = 0; mb_row < pc->mb_rows; ++mb_row)
{
for (mb_col = 0; mb_col < pc->mb_cols; ++mb_col)
{
int mb_idx = mb_row * pc->mb_cols + mb_col;
if (mb_idx >= first_corrupt)
{
*mi = *correct_mi;
}
else if (mb_idx == first_corrupt - 1)
{
correct_mi = mi;
}
++mi;
}
++mi;
}
}
}
void vp8_conceal_corrupt_block(MACROBLOCKD *xd)
{
/* this macroblock has corrupt residual, use the motion compensated
image for concealment */
int i;
for (i=0; i < 16; i++)
vpx_memcpy(xd->dst.y_buffer + i*xd->dst.y_stride,
xd->predictor + i*16, 16);
for (i=0; i < 8; i++)
vpx_memcpy(xd->dst.u_buffer + i*xd->dst.uv_stride,
xd->predictor + 256 + i*8, 8);
for (i=0; i < 8; i++)
vpx_memcpy(xd->dst.v_buffer + i*xd->dst.uv_stride,
xd->predictor + 320 + i*8, 8);
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2011 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef ERROR_CONCEALMENT_H
#define ERROR_CONCEALMENT_H
#include "onyxd_int.h"
void vp8_estimate_missing_mvs(VP8D_COMP *);
void vp8_conceal_corrupt_block(MACROBLOCKD *);
#endif

View File

@@ -319,6 +319,8 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
int retcode = 0;
struct vpx_usec_timer timer;
pbi->ec_enabled = 1;
/*if(pbi->ready_for_new_data == 0)
return -1;*/
@@ -338,12 +340,15 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
*/
cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
if (!pbi->ec_enabled)
{
/* Signal that we have no frame to show. */
cm->show_frame = 0;
/* Nothing more to do. */
return 0;
}
}
#if HAVE_ARMV7

View File

@@ -134,6 +134,9 @@ typedef struct VP8Decompressor
vp8_prob prob_gf;
vp8_prob prob_skip_false;
unsigned int mvs_corrupt_from_mb;
int ec_enabled;
} VP8D_COMP;
int vp8_decode_frame(VP8D_COMP *cpi);

View File

@@ -56,12 +56,14 @@ VP8_DX_SRCS-yes += decoder/decodemv.c
VP8_DX_SRCS-yes += decoder/decodframe.c
VP8_DX_SRCS-yes += decoder/dequantize.c
VP8_DX_SRCS-yes += decoder/detokenize.c
VP8_DX_SRCS-yes += decoder/error_concealment.c
VP8_DX_SRCS-yes += decoder/generic/dsystemdependent.c
VP8_DX_SRCS-yes += decoder/dboolhuff.h
VP8_DX_SRCS-yes += decoder/decodemv.h
VP8_DX_SRCS-yes += decoder/decoderthreading.h
VP8_DX_SRCS-yes += decoder/dequantize.h
VP8_DX_SRCS-yes += decoder/detokenize.h
VP8_DX_SRCS-yes += decoder/error_concealment.h
VP8_DX_SRCS-yes += decoder/onyxd_int.h
VP8_DX_SRCS-yes += decoder/treereader.h
VP8_DX_SRCS-yes += decoder/onyxd_if.c