diff options
Diffstat (limited to 'vp9')
-rw-r--r-- | vp9/decoder/vp9_decoder.c | 8 | ||||
-rw-r--r-- | vp9/encoder/vp9_bitstream.c | 9 | ||||
-rw-r--r-- | vp9/encoder/vp9_encodeframe.c | 129 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.c | 497 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.h | 2 | ||||
-rw-r--r-- | vp9/encoder/vp9_firstpass.c | 58 | ||||
-rw-r--r-- | vp9/encoder/vp9_pickmode.c | 6 | ||||
-rw-r--r-- | vp9/encoder/vp9_ratectrl.c | 4 | ||||
-rw-r--r-- | vp9/encoder/vp9_rd.c | 12 | ||||
-rw-r--r-- | vp9/encoder/vp9_rd.h | 5 | ||||
-rw-r--r-- | vp9/encoder/vp9_rdopt.c | 9 | ||||
-rw-r--r-- | vp9/encoder/vp9_svc_layercontext.c | 63 | ||||
-rw-r--r-- | vp9/encoder/vp9_svc_layercontext.h | 10 | ||||
-rw-r--r-- | vp9/encoder/vp9_temporal_filter.c | 3 | ||||
-rw-r--r-- | vp9/encoder/x86/vp9_denoiser_sse2.c | 56 | ||||
-rw-r--r-- | vp9/vp9_cx_iface.c | 6 |
16 files changed, 472 insertions, 405 deletions
diff --git a/vp9/decoder/vp9_decoder.c b/vp9/decoder/vp9_decoder.c index 3c9469c4c..baf6ab7ef 100644 --- a/vp9/decoder/vp9_decoder.c +++ b/vp9/decoder/vp9_decoder.c @@ -232,6 +232,8 @@ int vp9_receive_compressed_data(VP9Decoder *pbi, cm->frame_refs[0].buf->corrupted = 1; } + pbi->ready_for_new_data = 0; + // Check if the previous frame was a frame without any references to it. if (cm->new_fb_idx >= 0 && cm->frame_bufs[cm->new_fb_idx].ref_count == 0) cm->release_fb_cb(cm->cb_priv, @@ -279,8 +281,6 @@ int vp9_receive_compressed_data(VP9Decoder *pbi, cm->current_video_frame++; } - pbi->ready_for_new_data = 0; - cm->error.setjmp = 0; return retcode; } @@ -296,12 +296,12 @@ int vp9_get_raw_frame(VP9Decoder *pbi, YV12_BUFFER_CONFIG *sd, if (pbi->ready_for_new_data == 1) return ret; + pbi->ready_for_new_data = 1; + /* no raw frame to show!!! */ if (!cm->show_frame) return ret; - pbi->ready_for_new_data = 1; - #if CONFIG_VP9_POSTPROC if (!cm->show_existing_frame) { ret = vp9_post_proc_frame(cm, sd, flags); diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 694cac76f..3954fe6a7 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -1013,7 +1013,11 @@ static void write_frame_size_with_refs(VP9_COMP *cpi, ((cpi->svc.number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) || (cpi->svc.number_spatial_layers > 1 && - cpi->svc.layer_context[cpi->svc.spatial_layer_id].is_key_frame))) { + cpi->svc.layer_context[cpi->svc.spatial_layer_id].is_key_frame) || + (is_two_pass_svc(cpi) && + cpi->svc.encode_empty_frame_state == ENCODING && + cpi->svc.layer_context[0].frames_from_key_frame < + cpi->svc.number_temporal_layers + 1))) { found = 0; } vp9_wb_write_bit(wb, found); @@ -1105,8 +1109,7 @@ static void write_uncompressed_header(VP9_COMP *cpi, // will change to show_frame flag to 0, then add an one byte frame with // show_existing_frame flag which tells the decoder which frame we want to // show. - if (!cm->show_frame || - (is_two_pass_svc(cpi) && cm->error_resilient_mode == 0)) + if (!cm->show_frame) vp9_wb_write_bit(wb, cm->intra_only); if (!cm->error_resilient_mode) diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index a4e4fa325..87114f1bd 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -412,29 +412,47 @@ static int set_vt_partitioning(VP9_COMP *cpi, return 1; } - // Vertical split is available on all but the bottom border. - if (mi_row + block_height / 2 < cm->mi_rows && - vt.part_variances->vert[0].variance < threshold && - vt.part_variances->vert[1].variance < threshold) { - BLOCK_SIZE subsize = get_subsize(bsize, PARTITION_VERT); - set_block_size(cpi, mi_row, mi_col, subsize); - set_block_size(cpi, mi_row, mi_col + block_width / 2, subsize); - return 1; - } - - // Horizontal split is available on all but the right border. - if (mi_col + block_width / 2 < cm->mi_cols && - vt.part_variances->horz[0].variance < threshold && - vt.part_variances->horz[1].variance < threshold) { - BLOCK_SIZE subsize = get_subsize(bsize, PARTITION_HORZ); - set_block_size(cpi, mi_row, mi_col, subsize); - set_block_size(cpi, mi_row + block_height / 2, mi_col, subsize); - return 1; + // Only allow split for blocks above 16x16. + if (bsize > BLOCK_16X16) { + // Vertical split is available on all but the bottom border. + if (mi_row + block_height / 2 < cm->mi_rows && + vt.part_variances->vert[0].variance < threshold && + vt.part_variances->vert[1].variance < threshold) { + BLOCK_SIZE subsize = get_subsize(bsize, PARTITION_VERT); + set_block_size(cpi, mi_row, mi_col, subsize); + set_block_size(cpi, mi_row, mi_col + block_width / 2, subsize); + return 1; + } + + // Horizontal split is available on all but the right border. + if (mi_col + block_width / 2 < cm->mi_cols && + vt.part_variances->horz[0].variance < threshold && + vt.part_variances->horz[1].variance < threshold) { + BLOCK_SIZE subsize = get_subsize(bsize, PARTITION_HORZ); + set_block_size(cpi, mi_row, mi_col, subsize); + set_block_size(cpi, mi_row + block_height / 2, mi_col, subsize); + return 1; + } + } + + // This will only allow 8x8 if the 16x16 variance is very large. + if (bsize == BLOCK_16X16) { + if (mi_col + block_width / 2 < cm->mi_cols && + mi_row + block_height / 2 < cm->mi_rows && + vt.part_variances->none.variance < (threshold << 6)) { + set_block_size(cpi, mi_row, mi_col, bsize); + return 1; + } } return 0; } -// TODO(debargha): Fix this function and make it work as expected. +// This function chooses partitioning based on the variance +// between source and reconstructed last, where variance is +// computed for 8x8 downsampled inputs. Some things to check: +// using the last source rather than reconstructed last, and +// allowing for small downsampling (4x4 or 2x2) for selection +// of smaller block sizes (i.e., < 16x16). static void choose_partitioning(VP9_COMP *cpi, const TileInfo *const tile, int mi_row, int mi_col) { @@ -549,27 +567,11 @@ static void choose_partitioning(VP9_COMP *cpi, for (j = 0; j < 4; ++j) { const int x16_idx = ((j & 1) << 1); const int y16_idx = ((j >> 1) << 1); - // NOTE: This is a temporary hack to disable 8x8 partitions, - // since it works really bad - possibly due to a bug -#define DISABLE_8X8_VAR_BASED_PARTITION -#ifdef DISABLE_8X8_VAR_BASED_PARTITION - if (mi_row + y32_idx + y16_idx + 1 < cm->mi_rows && - mi_row + x32_idx + x16_idx + 1 < cm->mi_cols) { - set_block_size(cpi, - (mi_row + y32_idx + y16_idx), - (mi_col + x32_idx + x16_idx), - BLOCK_16X16); - } else { - for (k = 0; k < 4; ++k) { - const int x8_idx = (k & 1); - const int y8_idx = (k >> 1); - set_block_size(cpi, - (mi_row + y32_idx + y16_idx + y8_idx), - (mi_col + x32_idx + x16_idx + x8_idx), - BLOCK_8X8); - } - } -#else + // NOTE: Since this uses 8x8 downsampling for variance calculation + // we cannot really select block size 8x8 (or even 8x16/16x8), + // since we do not sufficient samples for variance. + // For now, 8x8 partition is only set if the variance of the 16x16 + // block is very high. This is controlled in set_vt_partitioning. if (!set_vt_partitioning(cpi, &vt.split[i].split[j], BLOCK_16X16, mi_row + y32_idx + y16_idx, @@ -583,7 +585,6 @@ static void choose_partitioning(VP9_COMP *cpi, BLOCK_8X8); } } -#endif } } } @@ -1521,9 +1522,7 @@ static void rd_use_partition(VP9_COMP *cpi, const TileInfo *const tile, BLOCK_SIZE subsize; ENTROPY_CONTEXT l[16 * MAX_MB_PLANE], a[16 * MAX_MB_PLANE]; PARTITION_CONTEXT sl[8], sa[8]; - RD_COST last_part_rdc = {INT_MAX, INT64_MAX, INT64_MAX}; - RD_COST none_rdc = {INT_MAX, INT64_MAX, INT64_MAX}; - RD_COST chosen_rdc = {INT_MAX, INT64_MAX, INT64_MAX}; + RD_COST last_part_rdc, none_rdc, chosen_rdc; BLOCK_SIZE sub_subsize = BLOCK_4X4; int splits_below = 0; BLOCK_SIZE bs_type = mi_8x8[0].src_mi->mbmi.sb_type; @@ -1536,6 +1535,10 @@ static void rd_use_partition(VP9_COMP *cpi, const TileInfo *const tile, assert(num_4x4_blocks_wide_lookup[bsize] == num_4x4_blocks_high_lookup[bsize]); + vp9_rd_cost_reset(&last_part_rdc); + vp9_rd_cost_reset(&none_rdc); + vp9_rd_cost_reset(&chosen_rdc); + partition = partition_lookup[bsl][bs_type]; subsize = get_subsize(bsize, partition); @@ -1597,16 +1600,15 @@ static void rd_use_partition(VP9_COMP *cpi, const TileInfo *const tile, INT64_MAX); if (last_part_rdc.rate != INT_MAX && bsize >= BLOCK_8X8 && mi_row + (mi_step >> 1) < cm->mi_rows) { - RD_COST tmp_rdc = {0, 0, 0}; + RD_COST tmp_rdc; PICK_MODE_CONTEXT *ctx = &pc_tree->horizontal[0]; + vp9_rd_cost_init(&tmp_rdc); update_state(cpi, ctx, mi_row, mi_col, subsize, 0); encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize, ctx); rd_pick_sb_modes(cpi, tile, mi_row + (mi_step >> 1), mi_col, &tmp_rdc, subsize, &pc_tree->horizontal[1], INT64_MAX); if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) { - last_part_rdc.rate = INT_MAX; - last_part_rdc.dist = INT64_MAX; - last_part_rdc.rdcost = INT64_MAX; + vp9_rd_cost_reset(&last_part_rdc); break; } last_part_rdc.rate += tmp_rdc.rate; @@ -1619,17 +1621,16 @@ static void rd_use_partition(VP9_COMP *cpi, const TileInfo *const tile, subsize, &pc_tree->vertical[0], INT64_MAX); if (last_part_rdc.rate != INT_MAX && bsize >= BLOCK_8X8 && mi_col + (mi_step >> 1) < cm->mi_cols) { - RD_COST tmp_rdc = {0, 0, 0}; + RD_COST tmp_rdc; PICK_MODE_CONTEXT *ctx = &pc_tree->vertical[0]; + vp9_rd_cost_init(&tmp_rdc); update_state(cpi, ctx, mi_row, mi_col, subsize, 0); encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize, ctx); rd_pick_sb_modes(cpi, tile, mi_row, mi_col + (mi_step >> 1), &tmp_rdc, subsize, &pc_tree->vertical[bsize > BLOCK_8X8], INT64_MAX); if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) { - last_part_rdc.rate = INT_MAX; - last_part_rdc.dist = INT64_MAX; - last_part_rdc.rdcost = INT64_MAX; + vp9_rd_cost_reset(&last_part_rdc); break; } last_part_rdc.rate += tmp_rdc.rate; @@ -1650,19 +1651,17 @@ static void rd_use_partition(VP9_COMP *cpi, const TileInfo *const tile, int x_idx = (i & 1) * (mi_step >> 1); int y_idx = (i >> 1) * (mi_step >> 1); int jj = i >> 1, ii = i & 0x01; - RD_COST tmp_rdc = {0, 0, 0}; - + RD_COST tmp_rdc; if ((mi_row + y_idx >= cm->mi_rows) || (mi_col + x_idx >= cm->mi_cols)) continue; + vp9_rd_cost_init(&tmp_rdc); rd_use_partition(cpi, tile, mi_8x8 + jj * bss * mis + ii * bss, tp, mi_row + y_idx, mi_col + x_idx, subsize, &tmp_rdc.rate, &tmp_rdc.dist, i != 3, pc_tree->split[i]); if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) { - last_part_rdc.rate = INT_MAX; - last_part_rdc.dist = INT64_MAX; - last_part_rdc.rdcost = INT64_MAX; + vp9_rd_cost_reset(&last_part_rdc); break; } last_part_rdc.rate += tmp_rdc.rate; @@ -1709,15 +1708,12 @@ static void rd_use_partition(VP9_COMP *cpi, const TileInfo *const tile, save_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize); pc_tree->split[i]->partitioning = PARTITION_NONE; rd_pick_sb_modes(cpi, tile, mi_row + y_idx, mi_col + x_idx, &tmp_rdc, - split_subsize, &pc_tree->split[i]->none, - INT64_MAX); + split_subsize, &pc_tree->split[i]->none, INT64_MAX); restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize); if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) { - chosen_rdc.rate = INT_MAX; - chosen_rdc.dist = INT64_MAX; - chosen_rdc.rdcost = INT64_MAX; + vp9_rd_cost_reset(&chosen_rdc); break; } @@ -2122,9 +2118,7 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, PICK_MODE_CONTEXT *ctx = &pc_tree->none; int i, pl; BLOCK_SIZE subsize; - RD_COST this_rdc = {0, 0, 0}; - RD_COST sum_rdc = {0, 0, 0}; - RD_COST best_rdc = {INT_MAX, INT64_MAX, best_rd}; + RD_COST this_rdc, sum_rdc, best_rdc; int do_split = bsize >= BLOCK_8X8; int do_rect = 1; @@ -2152,6 +2146,11 @@ static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile, assert(num_8x8_blocks_wide_lookup[bsize] == num_8x8_blocks_high_lookup[bsize]); + vp9_rd_cost_init(&this_rdc); + vp9_rd_cost_init(&sum_rdc); + vp9_rd_cost_reset(&best_rdc); + best_rdc.rdcost = best_rd; + set_offsets(cpi, tile, mi_row, mi_col, bsize); if (bsize == BLOCK_16X16 && cpi->oxcf.aq_mode) diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index dea93062b..1758e3fdb 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -160,7 +160,7 @@ static void dealloc_compressor_data(VP9_COMP *cpi) { VP9_COMMON *const cm = &cpi->common; int i; - // Delete segmentation map. + // Delete sementation map vpx_free(cpi->segmentation_map); cpi->segmentation_map = NULL; vpx_free(cm->last_frame_seg_map); @@ -225,6 +225,9 @@ static void dealloc_compressor_data(VP9_COMP *cpi) { } vpx_memset(&cpi->svc.scaled_frames[0], 0, MAX_LAG_BUFFERS * sizeof(cpi->svc.scaled_frames[0])); + + vp9_free_frame_buffer(&cpi->svc.empty_frame.img); + vpx_memset(&cpi->svc.empty_frame, 0, sizeof(cpi->svc.empty_frame)); } static void save_coding_context(VP9_COMP *cpi) { @@ -2413,33 +2416,30 @@ void vp9_scale_references(VP9_COMP *cpi) { const VP9_REFFRAME ref_mask[3] = {VP9_LAST_FLAG, VP9_GOLD_FLAG, VP9_ALT_FLAG}; for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { - // Need to convert from VP9_REFFRAME to index into ref_mask (subtract 1). - if (cpi->ref_frame_flags & ref_mask[ref_frame - 1]) { - const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)]; - const YV12_BUFFER_CONFIG *const ref = &cm->frame_bufs[idx].buf; + const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)]; + const YV12_BUFFER_CONFIG *const ref = &cm->frame_bufs[idx].buf; - if (ref->y_crop_width != cm->width || ref->y_crop_height != cm->height) { - const int new_fb = get_free_fb(cm); - vp9_realloc_frame_buffer(&cm->frame_bufs[new_fb].buf, - cm->width, cm->height, - cm->subsampling_x, cm->subsampling_y, + // Need to convert from VP9_REFFRAME to index into ref_mask (subtract 1). + if ((cpi->ref_frame_flags & ref_mask[ref_frame - 1]) && + (ref->y_crop_width != cm->width || ref->y_crop_height != cm->height)) { + const int new_fb = get_free_fb(cm); + vp9_realloc_frame_buffer(&cm->frame_bufs[new_fb].buf, + cm->width, cm->height, + cm->subsampling_x, cm->subsampling_y, #if CONFIG_VP9_HIGHBITDEPTH - cm->use_highbitdepth, + cm->use_highbitdepth, #endif // CONFIG_VP9_HIGHBITDEPTH - VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL); + VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL); #if CONFIG_VP9_HIGHBITDEPTH - scale_and_extend_frame(ref, &cm->frame_bufs[new_fb].buf, - (int)cm->bit_depth); + scale_and_extend_frame(ref, &cm->frame_bufs[new_fb].buf, + (int)cm->bit_depth); #else - scale_and_extend_frame(ref, &cm->frame_bufs[new_fb].buf); + scale_and_extend_frame(ref, &cm->frame_bufs[new_fb].buf); #endif // CONFIG_VP9_HIGHBITDEPTH - cpi->scaled_ref_idx[ref_frame - 1] = new_fb; - } else { - cpi->scaled_ref_idx[ref_frame - 1] = idx; - ++cm->frame_bufs[idx].ref_count; - } + cpi->scaled_ref_idx[ref_frame - 1] = new_fb; } else { - cpi->scaled_ref_idx[ref_frame - 1] = INVALID_REF_BUFFER_IDX; + cpi->scaled_ref_idx[ref_frame - 1] = idx; + cm->frame_bufs[idx].ref_count++; } } } @@ -2447,13 +2447,9 @@ void vp9_scale_references(VP9_COMP *cpi) { static void release_scaled_references(VP9_COMP *cpi) { VP9_COMMON *cm = &cpi->common; int i; - for (i = 0; i < 3; ++i) { - const int idx = cpi->scaled_ref_idx[i]; - RefCntBuffer *const buf = - idx != INVALID_REF_BUFFER_IDX ? &cm->frame_bufs[idx] : NULL; - if (buf != NULL) - --buf->ref_count; - } + + for (i = 0; i < 3; i++) + cm->frame_bufs[cpi->scaled_ref_idx[i]].ref_count--; } static void full_to_model_count(unsigned int *model_count, @@ -2538,181 +2534,10 @@ static void output_frame_level_debug_stats(VP9_COMP *cpi) { } #endif -static void set_mv_search_params(VP9_COMP *cpi) { - const VP9_COMMON *const cm = &cpi->common; - const unsigned int max_mv_def = MIN(cm->width, cm->height); - - // Default based on max resolution. - cpi->mv_step_param = vp9_init_search_range(max_mv_def); - - if (cpi->sf.mv.auto_mv_step_size) { - if (frame_is_intra_only(cm)) { - // Initialize max_mv_magnitude for use in the first INTER frame - // after a key/intra-only frame. - cpi->max_mv_magnitude = max_mv_def; - } else { - if (cm->show_frame) - // Allow mv_steps to correspond to twice the max mv magnitude found - // in the previous frame, capped by the default max_mv_magnitude based - // on resolution. - cpi->mv_step_param = - vp9_init_search_range(MIN(max_mv_def, 2 * cpi->max_mv_magnitude)); - cpi->max_mv_magnitude = 0; - } - } -} - -static void set_size_dependent_vars(VP9_COMP *cpi, int *q, - int *bottom_index, int *top_index) { +static void encode_without_recode_loop(VP9_COMP *cpi, + int q) { VP9_COMMON *const cm = &cpi->common; - const VP9EncoderConfig *const oxcf = &cpi->oxcf; - - // Setup variables that depend on the dimensions of the frame. - set_mv_search_params(cpi); - - // Configure experimental use of segmentation for enhanced coding of - // static regions if indicated. - // Only allowed in the second pass of a two pass encode, as it requires - // lagged coding, and if the relevant speed feature flag is set. - if (oxcf->pass == 2 && cpi->sf.static_segmentation) - configure_static_seg_features(cpi); - -#if CONFIG_VP9_POSTPROC - if (oxcf->noise_sensitivity > 0) { - int l = 0; - switch (oxcf->noise_sensitivity) { - case 1: - l = 20; - break; - case 2: - l = 40; - break; - case 3: - l = 60; - break; - case 4: - case 5: - l = 100; - break; - case 6: - l = 150; - break; - } - vp9_denoise(cpi->Source, cpi->Source, l); - } -#endif // CONFIG_VP9_POSTPROC - - vp9_set_speed_features(cpi); - - vp9_set_rd_speed_thresholds(cpi); - vp9_set_rd_speed_thresholds_sub8x8(cpi); - - // Decide q and q bounds. - *q = vp9_rc_pick_q_and_bounds(cpi, bottom_index, top_index); - - if (!frame_is_intra_only(cm)) { - cm->interp_filter = cpi->sf.default_interp_filter; - // TODO: Decide this more intelligently. - vp9_set_high_precision_mv(cpi, (*q) < HIGH_PRECISION_MV_QTHRESH); - } -} - -static void init_motion_estimation(VP9_COMP *cpi) { - int y_stride = cpi->scaled_source.y_stride; - - if (cpi->sf.mv.search_method == NSTEP) { - vp9_init3smotion_compensation(&cpi->ss_cfg, y_stride); - } else if (cpi->sf.mv.search_method == DIAMOND) { - vp9_init_dsmotion_compensation(&cpi->ss_cfg, y_stride); - } -} - -void set_frame_size(VP9_COMP *cpi) { - int ref_frame; - VP9_COMMON *const cm = &cpi->common; - const VP9EncoderConfig *const oxcf = &cpi->oxcf; - MACROBLOCKD *const xd = &cpi->mb.e_mbd; - - // For two pass encodes analyse the first pass stats and determine - // the bit allocation and other parameters for this frame / group of frames. - if ((oxcf->pass == 2) && (!cpi->use_svc || is_two_pass_svc(cpi))) { - vp9_rc_get_second_pass_params(cpi); - } - - if (!cpi->use_svc && cpi->multi_arf_allowed) { - if (cm->frame_type == KEY_FRAME) { - init_buffer_indices(cpi); - } else if (oxcf->pass == 2) { - const GF_GROUP *const gf_group = &cpi->twopass.gf_group; - cpi->alt_fb_idx = gf_group->arf_ref_idx[gf_group->index]; - } - } - - if (oxcf->pass == 2 && - cm->current_video_frame == 0 && - oxcf->allow_spatial_resampling && - oxcf->rc_mode == VPX_VBR) { - // Internal scaling is triggered on the first frame. - vp9_set_size_literal(cpi, oxcf->scaled_frame_width, - oxcf->scaled_frame_height); - } - - // Reset the frame pointers to the current frame size. - vp9_realloc_frame_buffer(get_frame_new_buffer(cm), - cm->width, cm->height, - cm->subsampling_x, cm->subsampling_y, -#if CONFIG_VP9_HIGHBITDEPTH - cm->use_highbitdepth, -#endif - VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL); - - alloc_util_frame_buffers(cpi); - init_motion_estimation(cpi); - - for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { - const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)]; - YV12_BUFFER_CONFIG *const buf = &cm->frame_bufs[idx].buf; - RefBuffer *const ref_buf = &cm->frame_refs[ref_frame - 1]; - ref_buf->buf = buf; - ref_buf->idx = idx; -#if CONFIG_VP9_HIGHBITDEPTH - vp9_setup_scale_factors_for_frame(&ref_buf->sf, - buf->y_crop_width, buf->y_crop_height, - cm->width, cm->height, - (buf->flags & YV12_FLAG_HIGHBITDEPTH) ? - 1 : 0); -#else - vp9_setup_scale_factors_for_frame(&ref_buf->sf, - buf->y_crop_width, buf->y_crop_height, - cm->width, cm->height); -#endif // CONFIG_VP9_HIGHBITDEPTH - if (vp9_is_scaled(&ref_buf->sf)) - vp9_extend_frame_borders(buf); - } - - set_ref_ptrs(cm, xd, LAST_FRAME, LAST_FRAME); -} - -static void encode_without_recode_loop(VP9_COMP *cpi) { - int q; - int bottom_index, top_index; // Dummy. - VP9_COMMON *const cm = &cpi->common; - vp9_clear_system_state(); - - set_frame_size(cpi); - - cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source, - &cpi->scaled_source); - - if (cpi->unscaled_last_source != NULL) - cpi->Last_Source = vp9_scale_if_required(cm, cpi->unscaled_last_source, - &cpi->scaled_last_source); - - vp9_scale_references(cpi); - - set_size_dependent_vars(cpi, &q, &bottom_index, &top_index); - vp9_set_quantizer(cm, q); setup_frame(cpi); // Variance adaptive and in frame q adjustment experiments are mutually @@ -2735,45 +2560,28 @@ static void encode_without_recode_loop(VP9_COMP *cpi) { static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, - uint8_t *dest) { + uint8_t *dest, + int q, + int bottom_index, + int top_index) { VP9_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; - int q; - int q_low, q_high; - int bottom_index, top_index; int loop_count = 0; int loop = 0; int overshoot_seen = 0; int undershoot_seen = 0; + int q_low = bottom_index, q_high = top_index; int frame_over_shoot_limit; int frame_under_shoot_limit; + // Decide frame size bounds + vp9_rc_compute_frame_size_bounds(cpi, rc->this_frame_target, + &frame_under_shoot_limit, + &frame_over_shoot_limit); + do { vp9_clear_system_state(); - if (loop_count == 0) { - set_frame_size(cpi); - - // Decide frame size bounds - vp9_rc_compute_frame_size_bounds(cpi, rc->this_frame_target, - &frame_under_shoot_limit, - &frame_over_shoot_limit); - - cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source, - &cpi->scaled_source); - - if (cpi->unscaled_last_source != NULL) - cpi->Last_Source = vp9_scale_if_required(cm, cpi->unscaled_last_source, - &cpi->scaled_last_source); - - vp9_scale_references(cpi); - - set_size_dependent_vars(cpi, &q, &bottom_index, &top_index); - - q_low = bottom_index; - q_high = top_index; - } - vp9_set_quantizer(cm, q); if (loop_count == 0) @@ -3050,6 +2858,31 @@ static void set_arf_sign_bias(VP9_COMP *cpi) { cm->ref_frame_sign_bias[ALTREF_FRAME] = arf_sign_bias; } +static void set_mv_search_params(VP9_COMP *cpi) { + const VP9_COMMON *const cm = &cpi->common; + const unsigned int max_mv_def = MIN(cm->width, cm->height); + + // Default based on max resolution. + cpi->mv_step_param = vp9_init_search_range(max_mv_def); + + if (cpi->sf.mv.auto_mv_step_size) { + if (frame_is_intra_only(cm)) { + // Initialize max_mv_magnitude for use in the first INTER frame + // after a key/intra-only frame. + cpi->max_mv_magnitude = max_mv_def; + } else { + if (cm->show_frame) + // Allow mv_steps to correspond to twice the max mv magnitude found + // in the previous frame, capped by the default max_mv_magnitude based + // on resolution. + cpi->mv_step_param = + vp9_init_search_range(MIN(max_mv_def, 2 * cpi->max_mv_magnitude)); + cpi->max_mv_magnitude = 0; + } + } +} + + int setup_interp_filter_search_mask(VP9_COMP *cpi) { INTERP_FILTER ifilter; int ref_total[MAX_REF_FRAMES] = {0}; @@ -3084,9 +2917,21 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, const VP9EncoderConfig *const oxcf = &cpi->oxcf; struct segmentation *const seg = &cm->seg; TX_SIZE t; + int q; + int top_index; + int bottom_index; set_ext_overrides(cpi); + cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source, + &cpi->scaled_source); + + if (cpi->unscaled_last_source != NULL) + cpi->Last_Source = vp9_scale_if_required(cm, cpi->unscaled_last_source, + &cpi->scaled_last_source); + + vp9_scale_references(cpi); + vp9_clear_system_state(); // Enable or disable mode based tweaking of the zbin. @@ -3101,11 +2946,14 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, // Set default state for segment based loop filter update flags. cm->lf.mode_ref_delta_update = 0; + set_mv_search_params(cpi); + if (cpi->oxcf.pass == 2 && cpi->sf.adaptive_interp_filter_search) cpi->sf.interp_filter_search_mask = setup_interp_filter_search_mask(cpi); + // Set various flags etc to special state if it is a key frame. if (frame_is_intra_only(cm)) { // Reset the loop filter deltas and segmentation map. @@ -3134,7 +2982,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, } } if (is_two_pass_svc(cpi) && cm->error_resilient_mode == 0) { + // Use the last frame context for the empty frame. cm->frame_context_idx = + (cpi->svc.encode_empty_frame_state == ENCODING) ? FRAME_CONTEXTS - 1 : cpi->svc.spatial_layer_id * cpi->svc.number_temporal_layers + cpi->svc.temporal_layer_id; @@ -3163,6 +3013,13 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, } } + // Configure experimental use of segmentation for enhanced coding of + // static regions if indicated. + // Only allowed in second pass of two pass (as requires lagged coding) + // and if the relevant speed feature flag is set. + if (oxcf->pass == 2 && cpi->sf.static_segmentation) + configure_static_seg_features(cpi); + // Check if the current frame is skippable for the partition search in the // second pass according to the first pass stats if (cpi->sf.allow_partition_search_skip && oxcf->pass == 2 && @@ -3184,6 +3041,31 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, vp9_clear_system_state(); +#if CONFIG_VP9_POSTPROC + if (oxcf->noise_sensitivity > 0) { + int l = 0; + switch (oxcf->noise_sensitivity) { + case 1: + l = 20; + break; + case 2: + l = 40; + break; + case 3: + l = 60; + break; + case 4: + case 5: + l = 100; + break; + case 6: + l = 150; + break; + } + vp9_denoise(cpi->Source, cpi->Source, l); + } +#endif + #if CONFIG_INTERNAL_STATS { int i; @@ -3192,10 +3074,24 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, } #endif + vp9_set_speed_features(cpi); + + vp9_set_rd_speed_thresholds(cpi); + vp9_set_rd_speed_thresholds_sub8x8(cpi); + + // Decide q and q bounds. + q = vp9_rc_pick_q_and_bounds(cpi, &bottom_index, &top_index); + + if (!frame_is_intra_only(cm)) { + cm->interp_filter = cpi->sf.default_interp_filter; + /* TODO: Decide this more intelligently */ + vp9_set_high_precision_mv(cpi, q < HIGH_PRECISION_MV_QTHRESH); + } + if (cpi->sf.recode_loop == DISALLOW_RECODE) { - encode_without_recode_loop(cpi); + encode_without_recode_loop(cpi, q); } else { - encode_with_recode_loop(cpi, size, dest); + encode_with_recode_loop(cpi, size, dest, q, bottom_index, top_index); } #if CONFIG_VP9_TEMPORAL_DENOISING @@ -3269,7 +3165,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, cpi->ref_frame_flags = get_ref_frame_flags(cpi); cm->last_frame_type = cm->frame_type; - vp9_rc_postencode_update(cpi, *size); + + if (!(is_two_pass_svc(cpi) && cpi->svc.encode_empty_frame_state == ENCODING)) + vp9_rc_postencode_update(cpi, *size); #if 0 output_frame_level_debug_stats(cpi); @@ -3293,12 +3191,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, cm->last_height = cm->height; // reset to normal state now that we are done. - if (!cm->show_existing_frame) { - if (is_two_pass_svc(cpi) && cm->error_resilient_mode == 0) - cm->last_show_frame = 0; - else - cm->last_show_frame = cm->show_frame; - } + if (!cm->show_existing_frame) + cm->last_show_frame = cm->show_frame; if (cm->show_frame) { vp9_swap_mi_and_prev_mi(cm); @@ -3335,7 +3229,19 @@ static void Pass2Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest, unsigned int *frame_flags) { cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED; encode_frame_to_data_rate(cpi, size, dest, frame_flags); - vp9_twopass_postencode_update(cpi); + + if (!(is_two_pass_svc(cpi) && cpi->svc.encode_empty_frame_state == ENCODING)) + vp9_twopass_postencode_update(cpi); +} + +static void init_motion_estimation(VP9_COMP *cpi) { + int y_stride = cpi->scaled_source.y_stride; + + if (cpi->sf.mv.search_method == NSTEP) { + vp9_init3smotion_compensation(&cpi->ss_cfg, y_stride); + } else if (cpi->sf.mv.search_method == DIAMOND) { + vp9_init_dsmotion_compensation(&cpi->ss_cfg, y_stride); + } } static void check_initial_width(VP9_COMP *cpi, @@ -3356,11 +3262,10 @@ static void check_initial_width(VP9_COMP *cpi, alloc_ref_frame_buffers(cpi); alloc_util_frame_buffers(cpi); - init_motion_estimation(cpi); // TODO(agrange) This can be removed. + init_motion_estimation(cpi); cpi->initial_width = cm->width; cpi->initial_height = cm->height; - cpi->initial_mbs = cm->MBs; } } @@ -3502,17 +3407,21 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, int64_t *time_stamp, int64_t *time_end, int flush) { const VP9EncoderConfig *const oxcf = &cpi->oxcf; VP9_COMMON *const cm = &cpi->common; + MACROBLOCKD *const xd = &cpi->mb.e_mbd; RATE_CONTROL *const rc = &cpi->rc; struct vpx_usec_timer cmptimer; YV12_BUFFER_CONFIG *force_src_buffer = NULL; struct lookahead_entry *last_source = NULL; struct lookahead_entry *source = NULL; + MV_REFERENCE_FRAME ref_frame; int arf_src_index; - int i; if (is_two_pass_svc(cpi)) { #if CONFIG_SPATIAL_SVC vp9_svc_start_frame(cpi); + // Use a small empty frame instead of a real frame + if (cpi->svc.encode_empty_frame_state == ENCODING) + source = &cpi->svc.empty_frame; #endif if (oxcf->pass == 2) vp9_restore_layer_context(cpi); @@ -3531,6 +3440,11 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, // Should we encode an arf frame. arf_src_index = get_arf_src_index(cpi); + + // Skip alt frame if we encode the empty frame + if (is_two_pass_svc(cpi) && source != NULL) + arf_src_index = 0; + if (arf_src_index) { assert(arf_src_index <= rc->frames_to_key); @@ -3630,28 +3544,83 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, vp9_restore_layer_context(cpi); } - // Find a free buffer for the new frame, releasing the reference previously - // held. + // start with a 0 size frame + *size = 0; + + /* find a free buffer for the new frame, releasing the reference previously + * held. + */ cm->frame_bufs[cm->new_fb_idx].ref_count--; cm->new_fb_idx = get_free_fb(cm); - // Start with a 0 size frame. - *size = 0; + // For two pass encodes analyse the first pass stats and determine + // the bit allocation and other parameters for this frame / group of frames. + if ((oxcf->pass == 2) && + (!cpi->use_svc || + (is_two_pass_svc(cpi) && + cpi->svc.encode_empty_frame_state != ENCODING))) { + vp9_rc_get_second_pass_params(cpi); + } + + if (!cpi->use_svc && cpi->multi_arf_allowed) { + if (cm->frame_type == KEY_FRAME) { + init_buffer_indices(cpi); + } else if (oxcf->pass == 2) { + const GF_GROUP *const gf_group = &cpi->twopass.gf_group; + cpi->alt_fb_idx = gf_group->arf_ref_idx[gf_group->index]; + } + } cpi->frame_flags = *frame_flags; - // Delay setting frame-size until the encode loop for 2-pass non-SVC. - if (!(oxcf->pass == 2 && (!cpi->use_svc || is_two_pass_svc(cpi)))) { - set_frame_size(cpi); + if (oxcf->pass == 2 && + cm->current_video_frame == 0 && + oxcf->allow_spatial_resampling && + oxcf->rc_mode == VPX_VBR) { + // Internal scaling is triggered on the first frame. + vp9_set_size_literal(cpi, oxcf->scaled_frame_width, + oxcf->scaled_frame_height); + } + + // Reset the frame pointers to the current frame size + vp9_realloc_frame_buffer(get_frame_new_buffer(cm), + cm->width, cm->height, + cm->subsampling_x, cm->subsampling_y, +#if CONFIG_VP9_HIGHBITDEPTH + cm->use_highbitdepth, +#endif + VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL); + + alloc_util_frame_buffers(cpi); + init_motion_estimation(cpi); + + for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { + const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)]; + YV12_BUFFER_CONFIG *const buf = &cm->frame_bufs[idx].buf; + RefBuffer *const ref_buf = &cm->frame_refs[ref_frame - 1]; + ref_buf->buf = buf; + ref_buf->idx = idx; +#if CONFIG_VP9_HIGHBITDEPTH + vp9_setup_scale_factors_for_frame(&ref_buf->sf, + buf->y_crop_width, buf->y_crop_height, + cm->width, cm->height, + (buf->flags & YV12_FLAG_HIGHBITDEPTH) ? + 1 : 0); +#else + vp9_setup_scale_factors_for_frame(&ref_buf->sf, + buf->y_crop_width, buf->y_crop_height, + cm->width, cm->height); +#endif // CONFIG_VP9_HIGHBITDEPTH + if (vp9_is_scaled(&ref_buf->sf)) + vp9_extend_frame_borders(buf); } + set_ref_ptrs(cm, xd, LAST_FRAME, LAST_FRAME); + if (oxcf->aq_mode == VARIANCE_AQ) { vp9_vaq_init(); } - for (i = 0; i < 3; ++i) - cpi->scaled_ref_idx[i] = INVALID_REF_BUFFER_IDX; - if (oxcf->pass == 1 && (!cpi->use_svc || is_two_pass_svc(cpi))) { const int lossless = is_lossless_requested(oxcf); @@ -3680,7 +3649,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, if (cm->refresh_frame_context) cm->frame_contexts[cm->frame_context_idx] = cm->fc; - // No frame encoded, or frame was dropped, release scaled references. + // Frame was dropped, release scaled references. if (*size == 0) { release_scaled_references(cpi); } @@ -3818,10 +3787,18 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, #endif - if (is_two_pass_svc(cpi) && cm->show_frame) { - ++cpi->svc.spatial_layer_to_encode; - if (cpi->svc.spatial_layer_to_encode >= cpi->svc.number_spatial_layers) - cpi->svc.spatial_layer_to_encode = 0; + if (is_two_pass_svc(cpi)) { + if (cpi->svc.encode_empty_frame_state == ENCODING) + cpi->svc.encode_empty_frame_state = ENCODED; + + if (cm->show_frame) { + ++cpi->svc.spatial_layer_to_encode; + if (cpi->svc.spatial_layer_to_encode >= cpi->svc.number_spatial_layers) + cpi->svc.spatial_layer_to_encode = 0; + + // May need the empty frame after an visible frame. + cpi->svc.encode_empty_frame_state = NEED_TO_ENCODE; + } } return 0; } @@ -3912,10 +3889,6 @@ int vp9_set_size_literal(VP9_COMP *cpi, unsigned int width, if (width) { cm->width = width; - if (cm->width * 5 < cpi->initial_width) { - cm->width = cpi->initial_width / 5 + 1; - printf("Warning: Desired width too small, changed to %d\n", cm->width); - } if (cm->width > cpi->initial_width) { cm->width = cpi->initial_width; printf("Warning: Desired width too large, changed to %d\n", cm->width); @@ -3924,10 +3897,6 @@ int vp9_set_size_literal(VP9_COMP *cpi, unsigned int width, if (height) { cm->height = height; - if (cm->height * 5 < cpi->initial_height) { - cm->height = cpi->initial_height / 5 + 1; - printf("Warning: Desired height too small, changed to %d\n", cm->height); - } if (cm->height > cpi->initial_height) { cm->height = cpi->initial_height; printf("Warning: Desired height too large, changed to %d\n", cm->height); diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index 1eb2629e1..6091ae290 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -44,7 +44,6 @@ extern "C" { #endif #define DEFAULT_GF_INTERVAL 10 -#define INVALID_REF_BUFFER_IDX -1 typedef struct { int nmvjointcost[MV_JOINTS]; @@ -376,7 +375,6 @@ typedef struct VP9_COMP { int initial_width; int initial_height; - int initial_mbs; int use_svc; diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index 9e204d7e9..96c3e0aa4 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -145,7 +145,7 @@ static void output_fpmb_stats(uint8_t *this_frame_mb_stats, VP9_COMMON *cm, struct vpx_codec_cx_pkt pkt; pkt.kind = VPX_CODEC_FPMB_STATS_PKT; pkt.data.firstpass_mb_stats.buf = this_frame_mb_stats; - pkt.data.firstpass_mb_stats.sz = cpi->initial_mbs * sizeof(uint8_t); + pkt.data.firstpass_mb_stats.sz = cm->MBs * sizeof(uint8_t); vpx_codec_pkt_list_add(pktlist, &pkt); } #endif @@ -339,9 +339,9 @@ static unsigned int highbd_get_prediction_error(BLOCK_SIZE bsize, // Refine the motion search range according to the frame dimension // for first pass test. -static int get_search_range(const VP9_COMP *cpi) { +static int get_search_range(const VP9_COMMON *cm) { int sr = 0; - const int dim = MIN(cpi->initial_width, cpi->initial_height); + const int dim = MIN(cm->width, cm->height); while ((dim << sr) < MAX_FULL_PEL_VAL) ++sr; @@ -361,7 +361,7 @@ static void first_pass_motion_search(VP9_COMP *cpi, MACROBLOCK *x, int step_param = 3; int further_steps = (MAX_MVSEARCH_STEPS - 1) - step_param; - const int sr = get_search_range(cpi); + const int sr = get_search_range(&cpi->common); step_param += sr; further_steps -= sr; @@ -490,7 +490,7 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { #if CONFIG_FP_MB_STATS if (cpi->use_fp_mb_stats) { - vp9_zero_array(cpi->twopass.frame_mb_stats_buf, cpi->initial_mbs); + vp9_zero_array(cpi->twopass.frame_mb_stats_buf, cm->MBs); } #endif @@ -946,7 +946,7 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { // where the typical "real" energy per MB also falls. // Initial estimate here uses sqrt(mbs) to define the min_err, where the // number of mbs is propotional to image area. - const double min_err = 200 * sqrt(cpi->initial_mbs); + const double min_err = 200 * sqrt(cm->MBs); fps.frame = cm->current_video_frame; fps.spatial_layer_id = cpi->svc.spatial_layer_id; @@ -954,9 +954,9 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { fps.sr_coded_error = (double)(sr_coded_error >> 8) + min_err; fps.intra_error = (double)(intra_error >> 8) + min_err; fps.count = 1.0; - fps.pcnt_inter = (double)intercount / cpi->initial_mbs; - fps.pcnt_second_ref = (double)second_ref_count / cpi->initial_mbs; - fps.pcnt_neutral = (double)neutral_count / cpi->initial_mbs; + fps.pcnt_inter = (double)intercount / cm->MBs; + fps.pcnt_second_ref = (double)second_ref_count / cm->MBs; + fps.pcnt_neutral = (double)neutral_count / cm->MBs; if (mvcount > 0) { fps.MVr = (double)sum_mvr / mvcount; @@ -967,7 +967,7 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { fps.MVcv = ((double)sum_mvcs - (fps.MVc * fps.MVc / mvcount)) / mvcount; fps.mv_in_out_count = (double)sum_in_vectors / (mvcount * 2); fps.new_mv_count = new_mv_count; - fps.pcnt_motion = (double)mvcount / cpi->initial_mbs; + fps.pcnt_motion = (double)mvcount / cm->MBs; } else { fps.MVr = 0.0; fps.mvr_abs = 0.0; @@ -1081,7 +1081,7 @@ static int get_twopass_worst_quality(const VP9_COMP *cpi, if (section_target_bandwidth <= 0) { return rc->worst_quality; // Highest value allowed } else { - const int num_mbs = cpi->initial_mbs; + const int num_mbs = cpi->common.MBs; const double section_err = stats->coded_error / stats->count; const double err_per_mb = section_err / num_mbs; const double speed_term = 1.0 + 0.04 * oxcf->speed; @@ -1195,10 +1195,9 @@ void vp9_init_second_pass(VP9_COMP *cpi) { #define LOW_SR_DIFF_TRHESH 0.1 #define SR_DIFF_MAX 128.0 -static double get_sr_decay_rate(const VP9_COMP *cpi, +static double get_sr_decay_rate(const VP9_COMMON *cm, const FIRSTPASS_STATS *frame) { - double sr_diff = - (frame->sr_coded_error - frame->coded_error) / cpi->initial_mbs; + double sr_diff = (frame->sr_coded_error - frame->coded_error) / cm->MBs; double sr_decay = 1.0; const double motion_amplitude_factor = frame->pcnt_motion * ((frame->mvc_abs + frame->mvr_abs) / 2); @@ -1215,19 +1214,19 @@ static double get_sr_decay_rate(const VP9_COMP *cpi, // This function gives an estimate of how badly we believe the prediction // quality is decaying from frame to frame. -static double get_zero_motion_factor(const VP9_COMP *cpi, +static double get_zero_motion_factor(const VP9_COMMON *cm, const FIRSTPASS_STATS *frame) { const double zero_motion_pct = frame->pcnt_inter - frame->pcnt_motion; - double sr_decay = get_sr_decay_rate(cpi, frame); + double sr_decay = get_sr_decay_rate(cm, frame); return MIN(sr_decay, zero_motion_pct); } #define ZM_POWER_FACTOR 0.75 -static double get_prediction_decay_rate(const VP9_COMP *cpi, +static double get_prediction_decay_rate(const VP9_COMMON *cm, const FIRSTPASS_STATS *next_frame) { - const double sr_decay_rate = get_sr_decay_rate(cpi, next_frame); + const double sr_decay_rate = get_sr_decay_rate(cm, next_frame); const double zero_motion_factor = (0.95 * pow((next_frame->pcnt_inter - next_frame->pcnt_motion), ZM_POWER_FACTOR)); @@ -1323,7 +1322,7 @@ static double calc_frame_boost(VP9_COMP *cpi, const double q_correction = MIN((0.8 + (lq * 0.001)), 1.0); // Underlying boost factor is based on inter error ratio. - frame_boost = (BASELINE_ERR_PER_MB * cpi->initial_mbs) / + frame_boost = (BASELINE_ERR_PER_MB * cpi->common.MBs) / DOUBLE_DIVIDE_CHECK(this_frame->coded_error); frame_boost = frame_boost * BOOST_FACTOR * q_correction; @@ -1372,7 +1371,7 @@ static int calc_arf_boost(VP9_COMP *cpi, int offset, // Accumulate the effect of prediction quality decay. if (!flash_detected) { - decay_accumulator *= get_prediction_decay_rate(cpi, this_frame); + decay_accumulator *= get_prediction_decay_rate(&cpi->common, this_frame); decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR ? MIN_DECAY_FACTOR : decay_accumulator; } @@ -1411,7 +1410,7 @@ static int calc_arf_boost(VP9_COMP *cpi, int offset, // Cumulative effect of prediction quality decay. if (!flash_detected) { - decay_accumulator *= get_prediction_decay_rate(cpi, this_frame); + decay_accumulator *= get_prediction_decay_rate(&cpi->common, this_frame); decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR ? MIN_DECAY_FACTOR : decay_accumulator; } @@ -1730,8 +1729,7 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { gf_group_err -= gf_first_frame_err; // Motion breakout threshold for loop below depends on image size. - mv_ratio_accumulator_thresh = - (cpi->initial_height + cpi->initial_width) / 4.0; + mv_ratio_accumulator_thresh = (cpi->common.width + cpi->common.height) / 4.0; // Set a maximum and minimum interval for the GF group. // If the image appears almost completely static we can extend beyond this. @@ -1783,14 +1781,14 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { // Accumulate the effect of prediction quality decay. if (!flash_detected) { last_loop_decay_rate = loop_decay_rate; - loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame); + loop_decay_rate = get_prediction_decay_rate(&cpi->common, &next_frame); decay_accumulator = decay_accumulator * loop_decay_rate; // Monitor for static sections. zero_motion_accumulator = MIN(zero_motion_accumulator, - get_zero_motion_factor(cpi, &next_frame)); + get_zero_motion_factor(&cpi->common, &next_frame)); // Break clause to detect very still sections after motion. For example, // a static image after a fade or other transition. @@ -2067,7 +2065,8 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { break; // How fast is the prediction quality decaying? - loop_decay_rate = get_prediction_decay_rate(cpi, twopass->stats_in); + loop_decay_rate = get_prediction_decay_rate(&cpi->common, + twopass->stats_in); // We want to know something about the recent past... rather than // as used elsewhere where we are concerned with decay in prediction @@ -2178,7 +2177,7 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { // Monitor for static sections. zero_motion_accumulator = MIN(zero_motion_accumulator, - get_zero_motion_factor(cpi, &next_frame)); + get_zero_motion_factor(&cpi->common, &next_frame)); // Not all frames in the group are necessarily used in calculating boost. if ((i <= rc->max_gf_interval) || @@ -2189,7 +2188,7 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { // How fast is prediction quality decaying. if (!detect_flash(twopass, 0)) { const double loop_decay_rate = - get_prediction_decay_rate(cpi, &next_frame); + get_prediction_decay_rate(&cpi->common, &next_frame); decay_accumulator *= loop_decay_rate; decay_accumulator = MAX(decay_accumulator, MIN_DECAY_FACTOR); av_decay_accumulator += decay_accumulator; @@ -2406,6 +2405,9 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) { cpi->ref_frame_flags &= (~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG); lc->frames_from_key_frame = 0; + // Reset the empty frame resolution since we have a key frame. + cpi->svc.empty_frame_width = cm->width; + cpi->svc.empty_frame_height = cm->height; } } else { cm->frame_type = INTER_FRAME; diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index 42f46917c..b74b2dd56 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -486,8 +486,12 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, // var_y and sse_y are saved to be used in skipping checking unsigned int var_y = UINT_MAX; unsigned int sse_y = UINT_MAX; + // Reduce the intra cost penalty for small blocks (<=16x16). + const int reduction_fac = + (cpi->sf.partition_search_type == VAR_BASED_PARTITION && + bsize <= BLOCK_16X16) ? 4 : 1; const int intra_cost_penalty = vp9_get_intra_cost_penalty( - cm->base_qindex, cm->y_dc_delta_q, cm->bit_depth); + cm->base_qindex, cm->y_dc_delta_q, cm->bit_depth) / reduction_fac; const int64_t inter_mode_thresh = RDCOST(x->rdmult, x->rddiv, intra_cost_penalty, 0); const int intra_mode_cost = 50; diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index ef32fe179..65bca669a 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -1500,9 +1500,7 @@ void vp9_rc_set_gf_max_interval(const VP9_COMP *const cpi, rc->max_gf_interval = 16; // Extended interval for genuinely static scenes - rc->static_scene_max_gf_interval = oxcf->key_freq >> 1; - if (rc->static_scene_max_gf_interval > (MAX_LAG_BUFFERS * 2)) - rc->static_scene_max_gf_interval = MAX_LAG_BUFFERS * 2; + rc->static_scene_max_gf_interval = MAX_LAG_BUFFERS * 2; if (is_altref_enabled(cpi)) { if (rc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1) diff --git a/vp9/encoder/vp9_rd.c b/vp9/encoder/vp9_rd.c index 75c396433..7f526fc42 100644 --- a/vp9/encoder/vp9_rd.c +++ b/vp9/encoder/vp9_rd.c @@ -44,6 +44,18 @@ // Factor to weigh the rate for switchable interp filters. #define SWITCHABLE_INTERP_RATE_FACTOR 1 +void vp9_rd_cost_reset(RD_COST *rd_cost) { + rd_cost->rate = INT_MAX; + rd_cost->dist = INT64_MAX; + rd_cost->rdcost = INT64_MAX; +} + +void vp9_rd_cost_init(RD_COST *rd_cost) { + rd_cost->rate = 0; + rd_cost->dist = 0; + rd_cost->rdcost = 0; +} + // The baseline rd thresholds for breaking out of the rd loop for // certain modes are assumed to be based on 8x8 blocks. // This table is used to correct for block size. diff --git a/vp9/encoder/vp9_rd.h b/vp9/encoder/vp9_rd.h index 33fb4ac94..1aa52663a 100644 --- a/vp9/encoder/vp9_rd.h +++ b/vp9/encoder/vp9_rd.h @@ -123,6 +123,11 @@ typedef struct RD_COST { int64_t rdcost; } RD_COST; +// Reset the rate distortion cost values to maximum (invalid) value. +void vp9_rd_cost_reset(RD_COST *rd_cost); +// Initialize the rate distortion cost values to zero. +void vp9_rd_cost_init(RD_COST *rd_cost); + struct TileInfo; struct VP9_COMP; struct macroblock; diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index 7565cc5c9..eca8e5880 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -1140,12 +1140,14 @@ static int super_block_uvrd(const VP9_COMP *cpi, MACROBLOCK *x, *sse = 0; *skippable = 1; - for (plane = 1; plane < MAX_MB_PLANE && is_cost_valid; ++plane) { + for (plane = 1; plane < MAX_MB_PLANE; ++plane) { txfm_rd_in_plane(x, &pnrate, &pndist, &pnskip, &pnsse, ref_best_rd, plane, bsize, uv_tx_size, cpi->sf.use_fast_coef_costing); - if (pnrate == INT_MAX) + if (pnrate == INT_MAX) { is_cost_valid = 0; + break; + } *rate += pnrate; *distortion += pndist; *sse += pnsse; @@ -3392,6 +3394,7 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, } if (best_mode_index < 0 || best_rd >= best_rd_so_far) { + rd_cost->rate = INT_MAX; rd_cost->rdcost = INT64_MAX; return; } @@ -3562,6 +3565,7 @@ void vp9_rd_pick_inter_mode_sb_seg_skip(VP9_COMP *cpi, MACROBLOCK *x, rd_cost->rdcost = this_rd; if (this_rd >= best_rd_so_far) { + rd_cost->rate = INT_MAX; rd_cost->rdcost = INT64_MAX; return; } @@ -4113,6 +4117,7 @@ void vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x, } if (best_rd >= best_rd_so_far) { + rd_cost->rate = INT_MAX; rd_cost->rdcost = INT64_MAX; return; } diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c index eed681c96..1573557d4 100644 --- a/vp9/encoder/vp9_svc_layercontext.c +++ b/vp9/encoder/vp9_svc_layercontext.c @@ -14,6 +14,8 @@ #include "vp9/encoder/vp9_svc_layercontext.h" #include "vp9/encoder/vp9_extend.h" +#define SMALL_FRAME_FB_IDX 7 + void vp9_init_layer_context(VP9_COMP *const cpi) { SVC *const svc = &cpi->svc; const VP9EncoderConfig *const oxcf = &cpi->oxcf; @@ -28,6 +30,25 @@ void vp9_init_layer_context(VP9_COMP *const cpi) { layer_end = svc->number_temporal_layers; } else { layer_end = svc->number_spatial_layers; + + if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) { + if (vp9_realloc_frame_buffer(&cpi->svc.empty_frame.img, + cpi->common.width, cpi->common.height, + cpi->common.subsampling_x, + cpi->common.subsampling_y, +#if CONFIG_VP9_HIGHBITDEPTH + cpi->common.use_highbitdepth, +#endif + VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate empty frame for multiple frame " + "contexts"); + + vpx_memset(cpi->svc.empty_frame.img.buffer_alloc, 0x80, + cpi->svc.empty_frame.img.buffer_alloc_sz); + cpi->svc.empty_frame_width = cpi->common.width; + cpi->svc.empty_frame_height = cpi->common.height; + } } for (layer = 0; layer < layer_end; ++layer) { @@ -310,6 +331,47 @@ int vp9_svc_start_frame(VP9_COMP *const cpi) { get_layer_resolution(cpi->oxcf.width, cpi->oxcf.height, lc->scaling_factor_num, lc->scaling_factor_den, &width, &height); + + // Workaround for multiple frame contexts. In some frames we can't use prev_mi + // since its previous frame could be changed during decoding time. The idea is + // we put a empty invisible frame in front of them, then we will not use + // prev_mi when encoding these frames. + if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2 && + cpi->svc.encode_empty_frame_state == NEED_TO_ENCODE) { + if ((cpi->svc.number_temporal_layers > 1 && + cpi->svc.temporal_layer_id < cpi->svc.number_temporal_layers - 1) || + (cpi->svc.number_spatial_layers > 1 && + cpi->svc.spatial_layer_id == 0)) { + struct lookahead_entry *buf = vp9_lookahead_peek(cpi->lookahead, 0); + + if (buf != NULL) { + cpi->svc.empty_frame.ts_start = buf->ts_start; + cpi->svc.empty_frame.ts_end = buf->ts_end; + cpi->svc.encode_empty_frame_state = ENCODING; + cpi->common.show_frame = 0; + cpi->ref_frame_flags = 0; + cpi->common.frame_type = INTER_FRAME; + cpi->lst_fb_idx = + cpi->gld_fb_idx = cpi->alt_fb_idx = SMALL_FRAME_FB_IDX; + + // Gradually make the empty frame smaller to save bits. Make it half of + // its previous size because of the scaling factor restriction. + cpi->svc.empty_frame_width >>= 1; + cpi->svc.empty_frame_width = (cpi->svc.empty_frame_width + 1) & ~1; + if (cpi->svc.empty_frame_width < 16) + cpi->svc.empty_frame_width = 16; + + cpi->svc.empty_frame_height >>= 1; + cpi->svc.empty_frame_height = (cpi->svc.empty_frame_height + 1) & ~1; + if (cpi->svc.empty_frame_height < 16) + cpi->svc.empty_frame_height = 16; + + width = cpi->svc.empty_frame_width; + height = cpi->svc.empty_frame_height; + } + } + } + if (vp9_set_size_literal(cpi, width, height) != 0) return VPX_CODEC_INVALID_PARAM; @@ -317,7 +379,6 @@ int vp9_svc_start_frame(VP9_COMP *const cpi) { cpi->oxcf.best_allowed_q = vp9_quantizer_to_qindex(lc->min_q); vp9_change_config(cpi, &cpi->oxcf); - vp9_set_high_precision_mv(cpi, 1); cpi->alt_ref_source = get_layer_context(cpi)->alt_ref_source; diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h index 47a5456b6..e9645ce9f 100644 --- a/vp9/encoder/vp9_svc_layercontext.h +++ b/vp9/encoder/vp9_svc_layercontext.h @@ -50,6 +50,16 @@ typedef struct { int spatial_layer_to_encode; + // Workaround for multiple frame contexts + enum { + ENCODED = 0, + ENCODING, + NEED_TO_ENCODE + }encode_empty_frame_state; + struct lookahead_entry empty_frame; + int empty_frame_width; + int empty_frame_height; + // Store scaled source frames to be used for temporal filter to generate // a alt ref frame. YV12_BUFFER_CONFIG scaled_frames[MAX_LAG_BUFFERS]; diff --git a/vp9/encoder/vp9_temporal_filter.c b/vp9/encoder/vp9_temporal_filter.c index 9ae81e761..5599227ce 100644 --- a/vp9/encoder/vp9_temporal_filter.c +++ b/vp9/encoder/vp9_temporal_filter.c @@ -719,6 +719,9 @@ void vp9_temporal_filter(VP9_COMP *cpi, int distance) { ++frame_used; } } + cm->mi = cm->mip + cm->mi_stride + 1; + cpi->mb.e_mbd.mi = cm->mi; + cpi->mb.e_mbd.mi[0].src_mi = &cpi->mb.e_mbd.mi[0]; } else { // ARF is produced at the native frame size and resized when coded. #if CONFIG_VP9_HIGHBITDEPTH diff --git a/vp9/encoder/x86/vp9_denoiser_sse2.c b/vp9/encoder/x86/vp9_denoiser_sse2.c index bf400d38b..bf5fa889f 100644 --- a/vp9/encoder/x86/vp9_denoiser_sse2.c +++ b/vp9/encoder/x86/vp9_denoiser_sse2.c @@ -41,40 +41,40 @@ static INLINE int sum_diff_16x1(__m128i acc_diff) { static INLINE __m128i vp9_denoiser_16x1_sse2(const uint8_t *sig, const uint8_t *mc_running_avg_y, uint8_t *running_avg_y, - const __m128i k_0, - const __m128i k_4, - const __m128i k_8, - const __m128i k_16, - const __m128i l3, - const __m128i l32, - const __m128i l21, + const __m128i *k_0, + const __m128i *k_4, + const __m128i *k_8, + const __m128i *k_16, + const __m128i *l3, + const __m128i *l32, + const __m128i *l21, __m128i acc_diff) { // Calculate differences - const __m128i v_sig = _mm_loadu_si128((__m128i *)(&sig[0])); + const __m128i v_sig = _mm_loadu_si128((const __m128i *)(&sig[0])); const __m128i v_mc_running_avg_y = _mm_loadu_si128( - (__m128i *)(&mc_running_avg_y[0])); + (const __m128i *)(&mc_running_avg_y[0])); __m128i v_running_avg_y; const __m128i pdiff = _mm_subs_epu8(v_mc_running_avg_y, v_sig); const __m128i ndiff = _mm_subs_epu8(v_sig, v_mc_running_avg_y); // Obtain the sign. FF if diff is negative. - const __m128i diff_sign = _mm_cmpeq_epi8(pdiff, k_0); + const __m128i diff_sign = _mm_cmpeq_epi8(pdiff, *k_0); // Clamp absolute difference to 16 to be used to get mask. Doing this // allows us to use _mm_cmpgt_epi8, which operates on signed byte. const __m128i clamped_absdiff = _mm_min_epu8( - _mm_or_si128(pdiff, ndiff), k_16); + _mm_or_si128(pdiff, ndiff), *k_16); // Get masks for l2 l1 and l0 adjustments. - const __m128i mask2 = _mm_cmpgt_epi8(k_16, clamped_absdiff); - const __m128i mask1 = _mm_cmpgt_epi8(k_8, clamped_absdiff); - const __m128i mask0 = _mm_cmpgt_epi8(k_4, clamped_absdiff); + const __m128i mask2 = _mm_cmpgt_epi8(*k_16, clamped_absdiff); + const __m128i mask1 = _mm_cmpgt_epi8(*k_8, clamped_absdiff); + const __m128i mask0 = _mm_cmpgt_epi8(*k_4, clamped_absdiff); // Get adjustments for l2, l1, and l0. - __m128i adj2 = _mm_and_si128(mask2, l32); - const __m128i adj1 = _mm_and_si128(mask1, l21); + __m128i adj2 = _mm_and_si128(mask2, *l32); + const __m128i adj1 = _mm_and_si128(mask1, *l21); const __m128i adj0 = _mm_and_si128(mask0, clamped_absdiff); __m128i adj, padj, nadj; // Combine the adjustments and get absolute adjustments. adj2 = _mm_add_epi8(adj2, adj1); - adj = _mm_sub_epi8(l3, adj2); + adj = _mm_sub_epi8(*l3, adj2); adj = _mm_andnot_si128(mask0, adj); adj = _mm_or_si128(adj, adj0); @@ -103,9 +103,9 @@ static INLINE __m128i vp9_denoiser_adj_16x1_sse2(const uint8_t *sig, __m128i acc_diff) { __m128i v_running_avg_y = _mm_loadu_si128((__m128i *)(&running_avg_y[0])); // Calculate differences. - const __m128i v_sig = _mm_loadu_si128((__m128i *)(&sig[0])); + const __m128i v_sig = _mm_loadu_si128((const __m128i *)(&sig[0])); const __m128i v_mc_running_avg_y = - _mm_loadu_si128((__m128i *)(&mc_running_avg_y[0])); + _mm_loadu_si128((const __m128i *)(&mc_running_avg_y[0])); const __m128i pdiff = _mm_subs_epu8(v_mc_running_avg_y, v_sig); const __m128i ndiff = _mm_subs_epu8(v_sig, v_mc_running_avg_y); // Obtain the sign. FF if diff is negative. @@ -178,8 +178,8 @@ static int vp9_denoiser_4xM_sse2(const uint8_t *sig, int sig_stride, acc_diff = vp9_denoiser_16x1_sse2(sig_buffer[r], mc_running_buffer[r], running_buffer[r], - k_0, k_4, k_8, k_16, - l3, l32, l21, acc_diff); + &k_0, &k_4, &k_8, &k_16, + &l3, &l32, &l21, acc_diff); vpx_memcpy(running_avg_y, running_buffer[r], 4); vpx_memcpy(running_avg_y + avg_y_stride, running_buffer[r] + 4, 4); vpx_memcpy(running_avg_y + avg_y_stride * 2, @@ -279,8 +279,8 @@ static int vp9_denoiser_8xM_sse2(const uint8_t *sig, int sig_stride, acc_diff = vp9_denoiser_16x1_sse2(sig_buffer[r], mc_running_buffer[r], running_buffer[r], - k_0, k_4, k_8, k_16, - l3, l32, l21, acc_diff); + &k_0, &k_4, &k_8, &k_16, + &l3, &l32, &l21, acc_diff); vpx_memcpy(running_avg_y, running_buffer[r], 8); vpx_memcpy(running_avg_y + avg_y_stride, running_buffer[r] + 8, 8); // Update pointers for next iteration. @@ -357,9 +357,9 @@ static int vp9_denoiser_64_32_16xM_sse2(const uint8_t *sig, int sig_stride, const __m128i l21 = _mm_set1_epi8(1); int sum_diff = 0; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - acc_diff[i][j] = _mm_setzero_si128(); + for (c = 0; c < 4; ++c) { + for (r = 0; r < 4; ++r) { + acc_diff[c][r] = _mm_setzero_si128(); } } @@ -368,8 +368,8 @@ static int vp9_denoiser_64_32_16xM_sse2(const uint8_t *sig, int sig_stride, acc_diff[c>>4][r>>4] = vp9_denoiser_16x1_sse2( sig, mc_running_avg_y, running_avg_y, - k_0, k_4, k_8, k_16, - l3, l32, l21, acc_diff[c>>4][r>>4]); + &k_0, &k_4, &k_8, &k_16, + &l3, &l32, &l21, acc_diff[c>>4][r>>4]); // Update pointers for next iteration. sig += 16; mc_running_avg_y += 16; diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index 041ba27da..d0ca5242c 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -188,11 +188,9 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, } if (alt_ref_sum > REF_FRAMES - cfg->ss_number_layers) ERROR("Not enough ref buffers for svc alt ref frames"); - if ((cfg->ss_number_layers > 3 || - cfg->ss_number_layers * cfg->ts_number_layers > 4) && + if (cfg->ss_number_layers * cfg->ts_number_layers > 3 && cfg->g_error_resilient == 0) - ERROR("Multiple frame context are not supported for more than 3 spatial " - "layers or more than 4 spatial x temporal layers"); + ERROR("Multiple frame context are not supported for more than 3 layers"); } #endif |