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:
@@ -251,6 +251,7 @@ void vp8_mb_mode_mv_init(VP8D_COMP *pbi)
|
|||||||
vp8_reader *const bc = & pbi->bc;
|
vp8_reader *const bc = & pbi->bc;
|
||||||
MV_CONTEXT *const mvc = pbi->common.fc.mvc;
|
MV_CONTEXT *const mvc = pbi->common.fc.mvc;
|
||||||
|
|
||||||
|
pbi->mvs_corrupt_from_mb = -1;
|
||||||
pbi->prob_skip_false = 0;
|
pbi->prob_skip_false = 0;
|
||||||
if (pbi->common.mb_no_coeff_skip)
|
if (pbi->common.mb_no_coeff_skip)
|
||||||
pbi->prob_skip_false = (vp8_prob)vp8_read_literal(bc, 8);
|
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)
|
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);*/
|
/*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)
|
if(pbi->common.frame_type == KEY_FRAME)
|
||||||
vp8_kfread_modes(pbi, mi, mb_row, mb_col);
|
vp8_kfread_modes(pbi, mi, mb_row, mb_col);
|
||||||
else
|
else
|
||||||
vp8_read_mb_modes_mv(pbi, mi, &mi->mbmi, mb_row, mb_col);
|
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 */
|
mi++; /* next macroblock */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "decodemv.h"
|
#include "decodemv.h"
|
||||||
#include "extend.h"
|
#include "extend.h"
|
||||||
|
#include "error_concealment.h"
|
||||||
#include "vpx_mem/vpx_mem.h"
|
#include "vpx_mem/vpx_mem.h"
|
||||||
#include "idct.h"
|
#include "idct.h"
|
||||||
#include "dequantize.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 eobtotal = 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;
|
||||||
@@ -225,6 +226,14 @@ void vp8_decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd)
|
|||||||
vp8_build_inter_predictors_mb(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 */
|
/* dequantization and idct */
|
||||||
if (xd->mode_info_context->mbmi.mode != B_PRED && xd->mode_info_context->mbmi.mode != SPLITMV)
|
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
|
else
|
||||||
pbi->debugoutput =0;
|
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 */
|
/* check if the boolean decoder has suffered an error */
|
||||||
xd->corrupted |= vp8dx_bool_error(xd->current_bc);
|
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;
|
partition_size = user_data_end - partition;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (partition + partition_size > user_data_end
|
if (!pbi->ec_enabled && (partition + partition_size > user_data_end
|
||||||
|| partition + partition_size < partition)
|
|| partition + partition_size < partition))
|
||||||
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
||||||
"Truncated packet or corrupt partition "
|
"Truncated packet or corrupt partition "
|
||||||
"%d length", i + 1);
|
"%d length", i + 1);
|
||||||
@@ -584,63 +593,82 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
|||||||
pc->yv12_fb[pc->new_fb_idx].corrupted = 0;
|
pc->yv12_fb[pc->new_fb_idx].corrupted = 0;
|
||||||
|
|
||||||
if (data_end - data < 3)
|
if (data_end - data < 3)
|
||||||
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
|
||||||
"Truncated packet");
|
|
||||||
pc->frame_type = (FRAME_TYPE)(data[0] & 1);
|
|
||||||
pc->version = (data[0] >> 1) & 7;
|
|
||||||
pc->show_frame = (data[0] >> 4) & 1;
|
|
||||||
first_partition_length_in_bytes =
|
|
||||||
(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)
|
|
||||||
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
|
||||||
"Truncated packet or corrupt partition 0 length");
|
|
||||||
vp8_setup_version(pc);
|
|
||||||
|
|
||||||
if (pc->frame_type == KEY_FRAME)
|
|
||||||
{
|
{
|
||||||
const int Width = pc->Width;
|
if (pbi->ec_enabled)
|
||||||
const int Height = pc->Height;
|
|
||||||
|
|
||||||
/* vet via sync code */
|
|
||||||
if (data[0] != 0x9d || data[1] != 0x01 || data[2] != 0x2a)
|
|
||||||
vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM,
|
|
||||||
"Invalid frame sync code");
|
|
||||||
|
|
||||||
pc->Width = (data[3] | (data[4] << 8)) & 0x3fff;
|
|
||||||
pc->horiz_scale = data[4] >> 6;
|
|
||||||
pc->Height = (data[5] | (data[6] << 8)) & 0x3fff;
|
|
||||||
pc->vert_scale = data[6] >> 6;
|
|
||||||
data += 7;
|
|
||||||
|
|
||||||
if (Width != pc->Width || Height != pc->Height)
|
|
||||||
{
|
{
|
||||||
int prev_mb_rows = pc->mb_rows;
|
/* 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;
|
||||||
|
first_partition_length_in_bytes =
|
||||||
|
(data[0] | (data[1] << 8) | (data[2] << 16)) >> 5;
|
||||||
|
data += 3;
|
||||||
|
|
||||||
if (pc->Width <= 0)
|
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);
|
||||||
|
|
||||||
|
if (pc->frame_type == KEY_FRAME)
|
||||||
|
{
|
||||||
|
const int Width = pc->Width;
|
||||||
|
const int Height = pc->Height;
|
||||||
|
|
||||||
|
/* vet via sync code */
|
||||||
|
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");
|
||||||
|
|
||||||
|
pc->Width = (data[3] | (data[4] << 8)) & 0x3fff;
|
||||||
|
pc->horiz_scale = data[4] >> 6;
|
||||||
|
pc->Height = (data[5] | (data[6] << 8)) & 0x3fff;
|
||||||
|
pc->vert_scale = data[6] >> 6;
|
||||||
|
data += 7;
|
||||||
|
|
||||||
|
if (Width != pc->Width || Height != pc->Height)
|
||||||
{
|
{
|
||||||
pc->Width = Width;
|
int prev_mb_rows = pc->mb_rows;
|
||||||
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
|
||||||
"Invalid frame width");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pc->Height <= 0)
|
if (pc->Width <= 0)
|
||||||
{
|
{
|
||||||
pc->Height = Height;
|
pc->Width = Width;
|
||||||
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
||||||
"Invalid frame height");
|
"Invalid frame width");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vp8_alloc_frame_buffers(pc, pc->Width, pc->Height))
|
if (pc->Height <= 0)
|
||||||
vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
|
{
|
||||||
"Failed to allocate frame buffers");
|
pc->Height = Height;
|
||||||
|
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
||||||
|
"Invalid frame height");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vp8_alloc_frame_buffers(pc, pc->Width, pc->Height))
|
||||||
|
vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
|
||||||
|
"Failed to allocate frame buffers");
|
||||||
|
|
||||||
#if CONFIG_MULTITHREAD
|
#if CONFIG_MULTITHREAD
|
||||||
if (pbi->b_multithreaded_rd)
|
if (pbi->b_multithreaded_rd)
|
||||||
vp8mt_alloc_temp_buffers(pbi, pc->Width, prev_mb_rows);
|
vp8mt_alloc_temp_buffers(pbi, pc->Width, prev_mb_rows);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -862,6 +890,11 @@ int vp8_decode_frame(VP8D_COMP *pbi)
|
|||||||
|
|
||||||
vp8_decode_mode_mvs(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_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));
|
vpx_memcpy(&xd->block[0].bmi, &xd->mode_info_context->bmi[0], sizeof(B_MODE_INFO));
|
||||||
|
72
vp8/decoder/error_concealment.c
Normal file
72
vp8/decoder/error_concealment.c
Normal 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);
|
||||||
|
}
|
20
vp8/decoder/error_concealment.h
Normal file
20
vp8/decoder/error_concealment.h
Normal 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
|
@@ -318,6 +318,8 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
|
|||||||
VP8_COMMON *cm = &pbi->common;
|
VP8_COMMON *cm = &pbi->common;
|
||||||
int retcode = 0;
|
int retcode = 0;
|
||||||
struct vpx_usec_timer timer;
|
struct vpx_usec_timer timer;
|
||||||
|
|
||||||
|
pbi->ec_enabled = 1;
|
||||||
|
|
||||||
/*if(pbi->ready_for_new_data == 0)
|
/*if(pbi->ready_for_new_data == 0)
|
||||||
return -1;*/
|
return -1;*/
|
||||||
@@ -338,11 +340,14 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
|
|||||||
*/
|
*/
|
||||||
cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
|
cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
|
||||||
|
|
||||||
/* Signal that we have no frame to show. */
|
if (!pbi->ec_enabled)
|
||||||
cm->show_frame = 0;
|
{
|
||||||
|
/* Signal that we have no frame to show. */
|
||||||
|
cm->show_frame = 0;
|
||||||
|
|
||||||
/* Nothing more to do. */
|
/* Nothing more to do. */
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -134,6 +134,9 @@ typedef struct VP8Decompressor
|
|||||||
vp8_prob prob_gf;
|
vp8_prob prob_gf;
|
||||||
vp8_prob prob_skip_false;
|
vp8_prob prob_skip_false;
|
||||||
|
|
||||||
|
unsigned int mvs_corrupt_from_mb;
|
||||||
|
int ec_enabled;
|
||||||
|
|
||||||
} VP8D_COMP;
|
} VP8D_COMP;
|
||||||
|
|
||||||
int vp8_decode_frame(VP8D_COMP *cpi);
|
int vp8_decode_frame(VP8D_COMP *cpi);
|
||||||
|
@@ -56,12 +56,14 @@ VP8_DX_SRCS-yes += decoder/decodemv.c
|
|||||||
VP8_DX_SRCS-yes += decoder/decodframe.c
|
VP8_DX_SRCS-yes += decoder/decodframe.c
|
||||||
VP8_DX_SRCS-yes += decoder/dequantize.c
|
VP8_DX_SRCS-yes += decoder/dequantize.c
|
||||||
VP8_DX_SRCS-yes += decoder/detokenize.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/generic/dsystemdependent.c
|
||||||
VP8_DX_SRCS-yes += decoder/dboolhuff.h
|
VP8_DX_SRCS-yes += decoder/dboolhuff.h
|
||||||
VP8_DX_SRCS-yes += decoder/decodemv.h
|
VP8_DX_SRCS-yes += decoder/decodemv.h
|
||||||
VP8_DX_SRCS-yes += decoder/decoderthreading.h
|
VP8_DX_SRCS-yes += decoder/decoderthreading.h
|
||||||
VP8_DX_SRCS-yes += decoder/dequantize.h
|
VP8_DX_SRCS-yes += decoder/dequantize.h
|
||||||
VP8_DX_SRCS-yes += decoder/detokenize.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/onyxd_int.h
|
||||||
VP8_DX_SRCS-yes += decoder/treereader.h
|
VP8_DX_SRCS-yes += decoder/treereader.h
|
||||||
VP8_DX_SRCS-yes += decoder/onyxd_if.c
|
VP8_DX_SRCS-yes += decoder/onyxd_if.c
|
||||||
|
Reference in New Issue
Block a user