diff --git a/examples/decode_with_partial_drops.txt b/examples/decode_with_partial_drops.txt index 30854d669c20883d012a0e9645d1382e78a1915d..7b0d3d2ca8e1b1f9b9f03f901cfb367c6a830fe5 100644 --- a/examples/decode_with_partial_drops.txt +++ b/examples/decode_with_partial_drops.txt @@ -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 diff --git a/vp8/decoder/decodframe.c b/vp8/decoder/decodframe.c index 734ab36fc9467ab4ef2e0715cc4d4ed049a18b98..00e001733f5dca1829a12f654727be5641a89a92 100644 --- a/vp8/decoder/decodframe.c +++ b/vp8/decoder/decodframe.c @@ -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 */ diff --git a/vp8/decoder/error_concealment.c b/vp8/decoder/error_concealment.c index c06bdcf07be50959808ea9167b182fc5f6aad877..4f8f1a66c22304bef3b84677a5081a811b6a76a9 100644 --- a/vp8/decoder/error_concealment.c +++ b/vp8/decoder/error_concealment.c @@ -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) diff --git a/vp8/decoder/threading.c b/vp8/decoder/threading.c index c1df823f108929bc01f73607caaa8d83f861ef2b..a7af9acfb4850ad3ad09ea109bf0bf40fafd5856 100644 --- a/vp8/decoder/threading.c +++ b/vp8/decoder/threading.c @@ -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;