From: Jingning Han Date: Wed, 1 Apr 2015 21:55:03 +0000 (-0700) Subject: Merge "Simplify effective src_diff address computation" X-Git-Tag: v1.5.0~806 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a4364e5146a0612e0ac604cb6a8d636ae6b325fc;hp=19da9167163abe708e99e72b861aeda43e5e4333;p=platform%2Fupstream%2Flibvpx.git Merge "Simplify effective src_diff address computation" --- diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 10a62ef..dfc88d8 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -482,9 +482,9 @@ void vp9_set_vbp_thresholds(VP9_COMP *cpi, int q) { } else { VP9_COMMON *const cm = &cpi->common; const int is_key_frame = (cm->frame_type == KEY_FRAME); - const int threshold_multiplier = is_key_frame ? 80 : 4; + const int threshold_multiplier = is_key_frame ? 20 : 1; const int64_t threshold_base = (int64_t)(threshold_multiplier * - vp9_convert_qindex_to_q(q, cm->bit_depth)); + cpi->y_dequant[q][1]); // TODO(marpan): Allow 4x4 partitions for inter-frames. // use_4x4_partition = (variance4x4downsample[i2 + j] == 1); @@ -492,21 +492,20 @@ void vp9_set_vbp_thresholds(VP9_COMP *cpi, int q) { // if variance of 16x16 block is very high, so use larger threshold // for 16x16 (threshold_bsize_min) in that case. if (is_key_frame) { - cpi->vbp_threshold = threshold_base >> 2; - cpi->vbp_threshold_bsize_max = threshold_base; - cpi->vbp_threshold_bsize_min = threshold_base << 2; - cpi->vbp_threshold_16x16 = cpi->vbp_threshold; + cpi->vbp_threshold_64x64 = threshold_base; + cpi->vbp_threshold_32x32 = threshold_base >> 2; + cpi->vbp_threshold_16x16 = threshold_base >> 2; + cpi->vbp_threshold_8x8 = threshold_base << 2; cpi->vbp_bsize_min = BLOCK_8X8; } else { - cpi->vbp_threshold = threshold_base; + cpi->vbp_threshold_32x32 = threshold_base; if (cm->width <= 352 && cm->height <= 288) { - cpi->vbp_threshold_bsize_max = threshold_base >> 2; - cpi->vbp_threshold_bsize_min = threshold_base << 3; + cpi->vbp_threshold_64x64 = threshold_base >> 2; + cpi->vbp_threshold_16x16 = threshold_base << 3; } else { - cpi->vbp_threshold_bsize_max = threshold_base; - cpi->vbp_threshold_bsize_min = threshold_base << cpi->oxcf.speed; + cpi->vbp_threshold_64x64 = threshold_base; + cpi->vbp_threshold_16x16 = threshold_base << cpi->oxcf.speed; } - cpi->vbp_threshold_16x16 = cpi->vbp_threshold_bsize_min; cpi->vbp_bsize_min = BLOCK_16X16; } } @@ -692,7 +691,7 @@ static void choose_partitioning(VP9_COMP *cpi, } if (is_key_frame || (low_res && vt.split[i].split[j].part_variances.none.variance > - (cpi->vbp_threshold << 1))) { + (cpi->vbp_threshold_32x32 << 1))) { // Go down to 4x4 down-sampling for variance. variance4x4downsample[i2 + j] = 1; for (k = 0; k < 4; k++) { @@ -757,7 +756,7 @@ static void choose_partitioning(VP9_COMP *cpi, // If variance of this 32x32 block is above the threshold, force the block // to split. This also forces a split on the upper (64x64) level. get_variance(&vt.split[i].part_variances.none); - if (vt.split[i].part_variances.none.variance > cpi->vbp_threshold) { + if (vt.split[i].part_variances.none.variance > cpi->vbp_threshold_32x32) { force_split[i + 1] = 1; force_split[0] = 1; } @@ -769,7 +768,7 @@ static void choose_partitioning(VP9_COMP *cpi, // we get to one that's got a variance lower than our threshold. if ( mi_col + 8 > cm->mi_cols || mi_row + 8 > cm->mi_rows || !set_vt_partitioning(cpi, xd, &vt, BLOCK_64X64, mi_row, mi_col, - cpi->vbp_threshold_bsize_max, BLOCK_16X16, + cpi->vbp_threshold_64x64, BLOCK_16X16, force_split[0])) { for (i = 0; i < 4; ++i) { const int x32_idx = ((i & 1) << 2); @@ -777,7 +776,7 @@ static void choose_partitioning(VP9_COMP *cpi, const int i2 = i << 2; if (!set_vt_partitioning(cpi, xd, &vt.split[i], BLOCK_32X32, (mi_row + y32_idx), (mi_col + x32_idx), - cpi->vbp_threshold, + cpi->vbp_threshold_32x32, BLOCK_16X16, force_split[i + 1])) { for (j = 0; j < 4; ++j) { const int x16_idx = ((j & 1) << 1); @@ -801,7 +800,7 @@ static void choose_partitioning(VP9_COMP *cpi, BLOCK_8X8, mi_row + y32_idx + y16_idx + y8_idx, mi_col + x32_idx + x16_idx + x8_idx, - cpi->vbp_threshold_bsize_min, + cpi->vbp_threshold_8x8, BLOCK_8X8, 0)) { set_block_size(cpi, xd, (mi_row + y32_idx + y16_idx + y8_idx), diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index 3c57c86..ee231f7 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -460,10 +460,10 @@ typedef struct VP9_COMP { int resize_pending; // VAR_BASED_PARTITION thresholds - int64_t vbp_threshold; - int64_t vbp_threshold_bsize_min; - int64_t vbp_threshold_bsize_max; + int64_t vbp_threshold_64x64; + int64_t vbp_threshold_32x32; int64_t vbp_threshold_16x16; + int64_t vbp_threshold_8x8; BLOCK_SIZE vbp_bsize_min; // Multi-threading diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index 661934e..ffa8777 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -202,6 +202,248 @@ static int combined_motion_search(VP9_COMP *cpi, MACROBLOCK *x, return rv; } +static void block_variance(const uint8_t *src, int src_stride, + const uint8_t *ref, int ref_stride, + int w, int h, unsigned int *sse, int *sum, + int block_size, unsigned int *sse8x8, + int *sum8x8, unsigned int *var8x8) { + int i, j, k = 0; + + *sse = 0; + *sum = 0; + + for (i = 0; i < h; i += block_size) { + for (j = 0; j < w; j += block_size) { + vp9_get8x8var(src + src_stride * i + j, src_stride, + ref + ref_stride * i + j, ref_stride, + &sse8x8[k], &sum8x8[k]); + *sse += sse8x8[k]; + *sum += sum8x8[k]; + var8x8[k] = sse8x8[k] - (((unsigned int)sum8x8[k] * sum8x8[k]) >> 6); + k++; + } + } +} + +static void calculate_variance(int bw, int bh, TX_SIZE tx_size, + unsigned int *sse_i, int *sum_i, + unsigned int *var_o, unsigned int *sse_o, + int *sum_o) { + const BLOCK_SIZE unit_size = txsize_to_bsize[tx_size]; + const int nw = 1 << (bw - b_width_log2_lookup[unit_size]); + const int nh = 1 << (bh - b_height_log2_lookup[unit_size]); + int i, j, k = 0; + + for (i = 0; i < nh; i += 2) { + for (j = 0; j < nw; j += 2) { + sse_o[k] = sse_i[i * nw + j] + sse_i[i * nw + j + 1] + + sse_i[(i + 1) * nw + j] + sse_i[(i + 1) * nw + j + 1]; + sum_o[k] = sum_i[i * nw + j] + sum_i[i * nw + j + 1] + + sum_i[(i + 1) * nw + j] + sum_i[(i + 1) * nw + j + 1]; + var_o[k] = sse_o[k] - (((unsigned int)sum_o[k] * sum_o[k]) >> + (b_width_log2_lookup[unit_size] + + b_height_log2_lookup[unit_size] + 6)); + k++; + } + } +} + +static void model_rd_for_sb_y_large(VP9_COMP *cpi, BLOCK_SIZE bsize, + MACROBLOCK *x, MACROBLOCKD *xd, + int *out_rate_sum, int64_t *out_dist_sum, + unsigned int *var_y, unsigned int *sse_y, + int mi_row, int mi_col, int *early_term) { + // Note our transform coeffs are 8 times an orthogonal transform. + // Hence quantizer step is also 8 times. To get effective quantizer + // we need to divide by 8 before sending to modeling function. + unsigned int sse; + int rate; + int64_t dist; + struct macroblock_plane *const p = &x->plane[0]; + struct macroblockd_plane *const pd = &xd->plane[0]; + const uint32_t dc_quant = pd->dequant[0]; + const uint32_t ac_quant = pd->dequant[1]; + const int64_t dc_thr = dc_quant * dc_quant >> 6; + const int64_t ac_thr = ac_quant * ac_quant >> 6; + unsigned int var; + int sum; + int skip_dc = 0; + + const int bw = b_width_log2_lookup[bsize]; + const int bh = b_height_log2_lookup[bsize]; + const int num8x8 = 1 << (bw + bh - 2); + unsigned int sse8x8[64] = {0}; + int sum8x8[64] = {0}; + unsigned int var8x8[64] = {0}; + TX_SIZE tx_size; + int i, k; + + // Calculate variance for whole partition, and also save 8x8 blocks' variance + // to be used in following transform skipping test. + block_variance(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, + 4 << bw, 4 << bh, &sse, &sum, 8, sse8x8, sum8x8, var8x8); + var = sse - (((int64_t)sum * sum) >> (bw + bh + 4)); + + *var_y = var; + *sse_y = sse; + + if (cpi->common.tx_mode == TX_MODE_SELECT) { + if (sse > (var << 2)) + tx_size = MIN(max_txsize_lookup[bsize], + tx_mode_to_biggest_tx_size[cpi->common.tx_mode]); + else + tx_size = TX_8X8; + + if (cpi->sf.partition_search_type == VAR_BASED_PARTITION) { + if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && + cyclic_refresh_segment_id_boosted(xd->mi[0].src_mi->mbmi.segment_id)) + tx_size = TX_8X8; + else if (tx_size > TX_16X16) + tx_size = TX_16X16; + } + } else { + tx_size = MIN(max_txsize_lookup[bsize], + tx_mode_to_biggest_tx_size[cpi->common.tx_mode]); + } + + assert(tx_size >= TX_8X8); + xd->mi[0].src_mi->mbmi.tx_size = tx_size; + + // Evaluate if the partition block is a skippable block in Y plane. + { + unsigned int sse16x16[16] = {0}; + int sum16x16[16] = {0}; + unsigned int var16x16[16] = {0}; + const int num16x16 = num8x8 >> 2; + + unsigned int sse32x32[4] = {0}; + int sum32x32[4] = {0}; + unsigned int var32x32[4] = {0}; + const int num32x32 = num8x8 >> 4; + + int ac_test = 1; + int dc_test = 1; + const int num = (tx_size == TX_8X8) ? num8x8 : + ((tx_size == TX_16X16) ? num16x16 : num32x32); + const unsigned int *sse_tx = (tx_size == TX_8X8) ? sse8x8 : + ((tx_size == TX_16X16) ? sse16x16 : sse32x32); + const unsigned int *var_tx = (tx_size == TX_8X8) ? var8x8 : + ((tx_size == TX_16X16) ? var16x16 : var32x32); + + // Calculate variance if tx_size > TX_8X8 + if (tx_size >= TX_16X16) + calculate_variance(bw, bh, TX_8X8, sse8x8, sum8x8, var16x16, sse16x16, + sum16x16); + if (tx_size == TX_32X32) + calculate_variance(bw, bh, TX_16X16, sse16x16, sum16x16, var32x32, + sse32x32, sum32x32); + + // Skipping test + x->skip_txfm[0] = 0; + for (k = 0; k < num; k++) + // Check if all ac coefficients can be quantized to zero. + if (!(var_tx[k] < ac_thr || var == 0)) { + ac_test = 0; + break; + } + + for (k = 0; k < num; k++) + // Check if dc coefficient can be quantized to zero. + if (!(sse_tx[k] - var_tx[k] < dc_thr || sse == var)) { + dc_test = 0; + break; + } + + if (ac_test) { + x->skip_txfm[0] = 2; + + if (dc_test) + x->skip_txfm[0] = 1; + } else if (dc_test) { + skip_dc = 1; + } + } + + if (x->skip_txfm[0] == 1) { + int skip_uv[2] = {0}; + unsigned int var_uv[2]; + unsigned int sse_uv[2]; + + *out_rate_sum = 0; + *out_dist_sum = sse << 4; + + // Transform skipping test in UV planes. + for (i = 1; i <= 2; i++) { + struct macroblock_plane *const p = &x->plane[i]; + struct macroblockd_plane *const pd = &xd->plane[i]; + const TX_SIZE uv_tx_size = get_uv_tx_size(&xd->mi[0].src_mi->mbmi, pd); + const BLOCK_SIZE unit_size = txsize_to_bsize[uv_tx_size]; + const int sf = (bw - b_width_log2_lookup[unit_size]) + + (bh - b_height_log2_lookup[unit_size]); + const BLOCK_SIZE bs = get_plane_block_size(bsize, pd); + const uint32_t uv_dc_thr = pd->dequant[0] * pd->dequant[0] >> (6 - sf); + const uint32_t uv_ac_thr = pd->dequant[1] * pd->dequant[1] >> (6 - sf); + int j = i - 1; + + vp9_build_inter_predictors_sbp(xd, mi_row, mi_col, bsize, i); + var_uv[j] = cpi->fn_ptr[bs].vf(p->src.buf, p->src.stride, + pd->dst.buf, pd->dst.stride, &sse_uv[j]); + + if (var_uv[j] < uv_ac_thr || var_uv[j] == 0) { + if (sse_uv[j] - var_uv[j] < uv_dc_thr || sse_uv[j] == var_uv[j]) + skip_uv[j] = 1; + } + } + + // If the transform in YUV planes are skippable, the mode search checks + // fewer inter modes and doesn't check intra modes. + if (skip_uv[0] & skip_uv[1]) { + *early_term = 1; + } + + return; + } + + if (!skip_dc) { +#if CONFIG_VP9_HIGHBITDEPTH + if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { + vp9_model_rd_from_var_lapndz(sse - var, num_pels_log2_lookup[bsize], + dc_quant >> (xd->bd - 5), &rate, &dist); + } else { + vp9_model_rd_from_var_lapndz(sse - var, num_pels_log2_lookup[bsize], + dc_quant >> 3, &rate, &dist); + } +#else + vp9_model_rd_from_var_lapndz(sse - var, num_pels_log2_lookup[bsize], + dc_quant >> 3, &rate, &dist); +#endif // CONFIG_VP9_HIGHBITDEPTH + } + + if (!skip_dc) { + *out_rate_sum = rate >> 1; + *out_dist_sum = dist << 3; + } else { + *out_rate_sum = 0; + *out_dist_sum = (sse - var) << 4; + } + +#if CONFIG_VP9_HIGHBITDEPTH + if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { + vp9_model_rd_from_var_lapndz(var, num_pels_log2_lookup[bsize], + ac_quant >> (xd->bd - 5), &rate, &dist); + } else { + vp9_model_rd_from_var_lapndz(var, num_pels_log2_lookup[bsize], + ac_quant >> 3, &rate, &dist); + } +#else + vp9_model_rd_from_var_lapndz(var, num_pels_log2_lookup[bsize], + ac_quant >> 3, &rate, &dist); +#endif // CONFIG_VP9_HIGHBITDEPTH + + *out_rate_sum += rate; + *out_dist_sum += dist << 4; +} + static void model_rd_for_sb_y(VP9_COMP *cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, int *out_rate_sum, int64_t *out_dist_sum, @@ -817,6 +1059,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, int ref_frame_skip_mask = 0; int idx; int best_pred_sad = INT_MAX; + int best_early_term = 0; int ref_frame_cost[MAX_REF_FRAMES]; vp9_prob intra_inter_p = vp9_get_intra_inter_prob(cm, xd); vp9_prob ref_single_p1 = vp9_get_pred_prob_single_ref_p1(cm, xd); @@ -924,6 +1167,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, PREDICTION_MODE this_mode = ref_mode_set[idx].pred_mode; int64_t this_sse; int is_skippable; + int this_early_term = 0; if (!(cpi->sf.inter_mode_mask[bsize] & (1 << this_mode))) continue; @@ -1084,8 +1328,18 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, } else { mbmi->interp_filter = (filter_ref == SWITCHABLE) ? EIGHTTAP : filter_ref; vp9_build_inter_predictors_sby(xd, mi_row, mi_col, bsize); - model_rd_for_sb_y(cpi, bsize, x, xd, &this_rdc.rate, &this_rdc.dist, - &var_y, &sse_y); + + // For large partition blocks, extra testing is done. + if (bsize > BLOCK_32X32 && xd->mi[0].src_mi->mbmi.segment_id != 1 && + cm->base_qindex) { + model_rd_for_sb_y_large(cpi, bsize, x, xd, &this_rdc.rate, + &this_rdc.dist, &var_y, &sse_y, mi_row, mi_col, + &this_early_term); + } else { + model_rd_for_sb_y(cpi, bsize, x, xd, &this_rdc.rate, &this_rdc.dist, + &var_y, &sse_y); + } + this_rdc.rate += cm->interp_filter == SWITCHABLE ? vp9_get_switchable_rate(cpi, xd) : 0; @@ -1162,6 +1416,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, best_tx_size = mbmi->tx_size; best_ref_frame = ref_frame; best_mode_skip_txfm = x->skip_txfm[0]; + best_early_term = this_early_term; if (reuse_inter_pred) { free_pred_buffer(best_pred); @@ -1174,6 +1429,13 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, if (x->skip) break; + + // If early termination flag is 1 and at least 2 modes are checked, + // the mode search is terminated. + if (best_early_term && idx > 0) { + x->skip = 1; + break; + } } mbmi->mode = best_mode; diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c index 7350cb3..c2f782b 100644 --- a/vp9/vp9_dx_iface.c +++ b/vp9/vp9_dx_iface.c @@ -755,6 +755,8 @@ static vpx_image_t *decoder_get_frame(vpx_codec_alg_priv_t *ctx, (FrameWorkerData *)worker->data1; ctx->next_output_worker_id = (ctx->next_output_worker_id + 1) % ctx->num_frame_workers; + if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) + set_ppflags(ctx, &flags); // Wait for the frame from worker thread. if (winterface->sync(worker)) { // Check if worker has received any frames. diff --git a/webmdec.cc b/webmdec.cc index d591f3e..60b01ad 100644 --- a/webmdec.cc +++ b/webmdec.cc @@ -63,6 +63,7 @@ int file_is_webm(struct WebmInputContext *webm_ctx, struct VpxInputContext *vpx_ctx) { mkvparser::MkvReader *const reader = new mkvparser::MkvReader(vpx_ctx->file); webm_ctx->reader = reader; + webm_ctx->reached_eos = 0; mkvparser::EBMLHeader header; long long pos = 0; @@ -121,6 +122,11 @@ int webm_read_frame(struct WebmInputContext *webm_ctx, uint8_t **buffer, size_t *bytes_in_buffer, size_t *buffer_size) { + // This check is needed for frame parallel decoding, in which case this + // function could be called even after it has reached end of input stream. + if (webm_ctx->reached_eos) { + return 1; + } mkvparser::Segment *const segment = reinterpret_cast(webm_ctx->segment); const mkvparser::Cluster* cluster = @@ -140,6 +146,7 @@ int webm_read_frame(struct WebmInputContext *webm_ctx, cluster = segment->GetNext(cluster); if (cluster == NULL || cluster->EOS()) { *bytes_in_buffer = 0; + webm_ctx->reached_eos = 1; return 1; } status = cluster->GetFirst(block_entry); diff --git a/webmdec.h b/webmdec.h index 1cd35d4..7d16380 100644 --- a/webmdec.h +++ b/webmdec.h @@ -29,6 +29,7 @@ struct WebmInputContext { int video_track_index; uint64_t timestamp_ns; int is_key_frame; + int reached_eos; }; // Checks if the input is a WebM file. If so, initializes WebMInputContext so