Adding support for error concealment in multi-threaded decoding
Also includes a couple of error concealment bug fixes: - the segment_id wasn't properly initialized when missing - when interpolating and no neighbors are found, set to zero - clear the qcoef buffer when concealing an MB Change-Id: Id79c876b41d78b559a2241e9cd0fd2cae6198f49
This commit is contained in:
parent
deca8cfc44
commit
ba0822ba96
@ -110,7 +110,7 @@ void throw_packets(unsigned char* frame, int* size, int loss_rate,
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT
|
||||
/* Initialize codec */
|
||||
flags = VPX_CODEC_USE_ERROR_CONCEALMENT;
|
||||
res = vpx_codec_dec_init(&codec, interface, NULL, flags);
|
||||
res = vpx_codec_dec_init(&codec, interface, &dec_cfg, flags);
|
||||
if(res)
|
||||
die_codec(&codec, "Failed to initialize decoder");
|
||||
|
||||
@ -123,11 +123,15 @@ which specifies the range or pattern of frames to drop. The parameter is
|
||||
parsed as follows:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE
|
||||
if(argc!=4 && argc != 5)
|
||||
die("Usage: %s <infile> <outfile> <N-M|N/M|L,S>\n", argv[0]);
|
||||
if(argc < 4 || argc > 6)
|
||||
die("Usage: %s <infile> <outfile> [-t <num threads>] <N-M|N/M|L,S>\n",
|
||||
argv[0]);
|
||||
{
|
||||
char *nptr;
|
||||
n = strtol(argv[3], &nptr, 0);
|
||||
int arg_num = 3;
|
||||
if (argc == 6 && strncmp(argv[arg_num++], "-t", 2) == 0)
|
||||
dec_cfg.threads = strtol(argv[arg_num++], NULL, 0);
|
||||
n = strtol(argv[arg_num], &nptr, 0);
|
||||
mode = (*nptr == '\0' || *nptr == ',') ? 2 : (*nptr == '-') ? 1 : 0;
|
||||
|
||||
m = strtol(nptr+1, NULL, 0);
|
||||
@ -138,6 +142,7 @@ if(argc!=4 && argc != 5)
|
||||
seed = (m > 0) ? m : (unsigned int)time(NULL);
|
||||
srand(seed);thrown_frame = 0;
|
||||
printf("Seed: %u\n", seed);
|
||||
printf("Threads: %d\n", dec_cfg.threads);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE
|
||||
|
||||
|
||||
@ -181,6 +186,7 @@ int n, m, mode;
|
||||
unsigned int seed;
|
||||
int thrown=0, kept=0;
|
||||
int thrown_frame=0, kept_frame=0;
|
||||
vpx_codec_dec_cfg_t dec_cfg = {0};
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS
|
||||
|
||||
|
||||
|
@ -239,12 +239,13 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd,
|
||||
|
||||
#if CONFIG_ERROR_CONCEALMENT
|
||||
if (pbi->ec_enabled &&
|
||||
(mb_idx > pbi->mvs_corrupt_from_mb ||
|
||||
(mb_idx >= pbi->mvs_corrupt_from_mb ||
|
||||
vp8dx_bool_error(xd->current_bc)))
|
||||
{
|
||||
/* MB with corrupt residuals or corrupt mode/motion vectors.
|
||||
* Better to use the predictor as reconstruction.
|
||||
*/
|
||||
vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff));
|
||||
vp8_conceal_corrupt_mb(xd);
|
||||
return;
|
||||
}
|
||||
@ -474,7 +475,13 @@ static void setup_token_decoder(VP8D_COMP *pbi,
|
||||
const unsigned char *partition;
|
||||
|
||||
/* Parse number of token partitions to use */
|
||||
pc->multi_token_partition = (TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2);
|
||||
const TOKEN_PARTITION multi_token_partition =
|
||||
(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))
|
||||
pc->multi_token_partition = multi_token_partition;
|
||||
|
||||
num_part = 1 << pc->multi_token_partition;
|
||||
|
||||
/* Set up pointers to the first partition */
|
||||
|
@ -382,6 +382,7 @@ static void estimate_missing_mvs(MB_OVERLAP *overlaps,
|
||||
mi->mbmi.mode = SPLITMV;
|
||||
mi->mbmi.uv_mode = DC_PRED;
|
||||
mi->mbmi.partitioning = 3;
|
||||
mi->mbmi.segment_id = 0;
|
||||
estimate_mb_mvs(block_overlaps,
|
||||
mi,
|
||||
mb_to_left_edge,
|
||||
@ -563,6 +564,12 @@ static void interpolate_mvs(MACROBLOCKD *mb,
|
||||
mb->mb_to_top_edge,
|
||||
mb->mb_to_bottom_edge);
|
||||
}
|
||||
else
|
||||
{
|
||||
mv->as_int = 0;
|
||||
mi->bmi[row*4 + col].as_mode = NEW4X4;
|
||||
mi->mbmi.need_to_clamp_mvs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -597,6 +604,7 @@ void vp8_interpolate_motion(MACROBLOCKD *mb,
|
||||
mb->mode_info_context->mbmi.mode = SPLITMV;
|
||||
mb->mode_info_context->mbmi.uv_mode = DC_PRED;
|
||||
mb->mode_info_context->mbmi.partitioning = 3;
|
||||
mb->mode_info_context->mbmi.segment_id = 0;
|
||||
}
|
||||
|
||||
void vp8_conceal_corrupt_mb(MACROBLOCKD *xd)
|
||||
|
@ -22,6 +22,9 @@
|
||||
#include "detokenize.h"
|
||||
#include "vp8/common/reconinter.h"
|
||||
#include "reconintra_mt.h"
|
||||
#if CONFIG_ERROR_CONCEALMENT
|
||||
#include "error_concealment.h"
|
||||
#endif
|
||||
|
||||
extern void mb_init_dequantizer(VP8D_COMP *pbi, MACROBLOCKD *xd);
|
||||
extern void clamp_mvs(MACROBLOCKD *xd);
|
||||
@ -151,6 +154,20 @@ static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, int mb_row, int m
|
||||
vp8_build_inter_predictors_mb(xd);
|
||||
}
|
||||
|
||||
#if CONFIG_ERROR_CONCEALMENT
|
||||
if (pbi->ec_enabled &&
|
||||
(mb_row * pbi->common.mb_cols + mb_col >= pbi->mvs_corrupt_from_mb ||
|
||||
vp8dx_bool_error(xd->current_bc)))
|
||||
{
|
||||
/* MB with corrupt residuals or corrupt mode/motion vectors.
|
||||
* Better to use the predictor as reconstruction.
|
||||
*/
|
||||
vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff));
|
||||
vp8_conceal_corrupt_mb(xd);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* dequantization and idct */
|
||||
if (xd->mode_info_context->mbmi.mode != B_PRED && xd->mode_info_context->mbmi.mode != SPLITMV)
|
||||
{
|
||||
@ -291,12 +308,37 @@ static THREAD_FUNCTION thread_decoding_proc(void *p_data)
|
||||
|
||||
update_blockd_bmi(xd);
|
||||
|
||||
/* Distance of Mb to the various image edges.
|
||||
* These are specified to 8th pel as they are always compared to values that are in 1/8th pel units
|
||||
/* Distance of MB to the various image edges.
|
||||
* These are specified to 8th pel as they are always
|
||||
* compared to values that are in 1/8th pel units.
|
||||
*/
|
||||
xd->mb_to_left_edge = -((mb_col * 16) << 3);
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
xd->dst.y_buffer = pc->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset;
|
||||
xd->dst.u_buffer = pc->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset;
|
||||
xd->dst.v_buffer = pc->yv12_fb[dst_fb_idx].v_buffer + recon_uvoffset;
|
||||
@ -772,12 +814,35 @@ void vp8mt_decode_mb_rows( VP8D_COMP *pbi, MACROBLOCKD *xd)
|
||||
|
||||
update_blockd_bmi(xd);
|
||||
|
||||
/* Distance of Mb to the various image edges.
|
||||
* These are specified to 8th pel as they are always compared to values that are in 1/8th pel units
|
||||
/* Distance of MB to the various image edges.
|
||||
* These are specified to 8th pel as they are always compared to
|
||||
* values that are in 1/8th pel units.
|
||||
*/
|
||||
xd->mb_to_left_edge = -((mb_col * 16) << 3);
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
xd->dst.y_buffer = pc->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset;
|
||||
xd->dst.u_buffer = pc->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset;
|
||||
xd->dst.v_buffer = pc->yv12_fb[dst_fb_idx].v_buffer + recon_uvoffset;
|
||||
|
Loading…
x
Reference in New Issue
Block a user