From a126b6ce7d9f81552e02fbe76d4fac276916992e Mon Sep 17 00:00:00 2001 From: paulwilkins Date: Wed, 24 Jun 2015 11:36:51 +0100 Subject: [PATCH] Change speed and rd features for formatting bars. Change speed features / behavior for split mode when there is an internal active edge (e.g. formatting bars). Remove some threshold constraints in rd code near the active edge of the image. Add some plumbing for left and right active edge detection. Patch set 5. Limit rd pass through for sub 8x8 to internal active edges. This takes away any speed penalty for most clips but keeps the enhanced edge coding for the more critical case of internal image edges Change-Id: If644e4762874de4fe9cbb0a66211953fa74c13a5 --- vp9/encoder/vp9_encodeframe.c | 34 +--------------------- vp9/encoder/vp9_firstpass.c | 5 ++++ vp9/encoder/vp9_firstpass.h | 1 + vp9/encoder/vp9_rdopt.c | 48 ++++++++++++++++++++++++++++++-- vp9/encoder/vp9_rdopt.h | 4 +++ vp9/encoder/vp9_speed_features.c | 5 +++- 6 files changed, 61 insertions(+), 36 deletions(-) diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 02d986e85..ca7359d65 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -2123,38 +2123,6 @@ static const BLOCK_SIZE max_partition_size[BLOCK_SIZES] = { BLOCK_64X64 }; -// Checks to see if a macro block is at the edge of the active image. -// In most cases this is the "real" edge unless there are formatting -// bars embedded in the stream. -static int active_edge_sb(VP9_COMP *cpi, - int mi_row, int mi_col) { - int is_active_edge = 0; - int top_edge = 0; - int bottom_edge = cpi->common.mi_rows; - int left_edge = 0; - int right_edge = cpi->common.mi_cols; - - // For two pass account for any formatting bars detected. - if (cpi->oxcf.pass == 2) { - TWO_PASS *twopass = &cpi->twopass; - - // The inactive region is specified in MBs not mi units. - // The image edge is in the following MB row. - top_edge += (int)(twopass->this_frame_stats.inactive_zone_rows * 2); - - bottom_edge -= (int)(twopass->this_frame_stats.inactive_zone_rows * 2); - bottom_edge = MAX(top_edge, bottom_edge); - } - - if (((top_edge >= mi_row) && (top_edge < (mi_row + MI_BLOCK_SIZE))) || - ((bottom_edge >= mi_row) && (bottom_edge < (mi_row + MI_BLOCK_SIZE))) || - ((left_edge >= mi_col) && (left_edge < (mi_col + MI_BLOCK_SIZE))) || - ((right_edge >= mi_col) && (right_edge < (mi_col + MI_BLOCK_SIZE)))) { - is_active_edge = 1; - } - - return is_active_edge; -} // Look at all the mode_info entries for blocks that are part of this // partition and find the min and max values for sb_type. @@ -2253,7 +2221,7 @@ static void rd_auto_partition_range(VP9_COMP *cpi, const TileInfo *const tile, // Test for blocks at the edge of the active image. // This may be the actual edge of the image or where there are formatting // bars. - if (active_edge_sb(cpi, mi_row, mi_col)) { + if (vp9_active_edge_sb(cpi, mi_row, mi_col)) { min_size = BLOCK_4X4; } else { min_size = MIN(cpi->sf.rd_auto_partition_min_limit, diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index a85b70b99..61279f872 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -126,6 +126,7 @@ static void output_stats(FIRSTPASS_STATS *stats, stats->pcnt_neutral, stats->intra_skip_pct, stats->inactive_zone_rows, + stats->inactive_zone_cols, stats->MVr, stats->mvr_abs, stats->MVc, @@ -164,6 +165,7 @@ static void zero_stats(FIRSTPASS_STATS *section) { section->pcnt_neutral = 0.0; section->intra_skip_pct = 0.0; section->inactive_zone_rows = 0.0; + section->inactive_zone_cols = 0.0; section->MVr = 0.0; section->mvr_abs = 0.0; section->MVc = 0.0; @@ -191,6 +193,7 @@ static void accumulate_stats(FIRSTPASS_STATS *section, section->pcnt_neutral += frame->pcnt_neutral; section->intra_skip_pct += frame->intra_skip_pct; section->inactive_zone_rows += frame->inactive_zone_rows; + section->inactive_zone_cols += frame->inactive_zone_cols; section->MVr += frame->MVr; section->mvr_abs += frame->mvr_abs; section->MVc += frame->MVc; @@ -216,6 +219,7 @@ static void subtract_stats(FIRSTPASS_STATS *section, section->pcnt_neutral -= frame->pcnt_neutral; section->intra_skip_pct -= frame->intra_skip_pct; section->inactive_zone_rows -= frame->inactive_zone_rows; + section->inactive_zone_cols -= frame->inactive_zone_cols; section->MVr -= frame->MVr; section->mvr_abs -= frame->mvr_abs; section->MVc -= frame->MVc; @@ -1050,6 +1054,7 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { fps.pcnt_neutral = (double)neutral_count / num_mbs; fps.intra_skip_pct = (double)intra_skip_count / num_mbs; fps.inactive_zone_rows = (double)image_data_start_row; + fps.inactive_zone_cols = (double)0; // TODO(paulwilkins): fix if (mvcount > 0) { fps.MVr = (double)sum_mvr / mvcount; diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h index 00479322d..49f9da38e 100644 --- a/vp9/encoder/vp9_firstpass.h +++ b/vp9/encoder/vp9_firstpass.h @@ -53,6 +53,7 @@ typedef struct { double pcnt_neutral; double intra_skip_pct; double inactive_zone_rows; // Image mask rows top and bottom. + double inactive_zone_cols; // Image mask columns at left and right edges. double MVr; double mvr_abs; double MVc; diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index 3a27e8989..409300b8f 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -2898,6 +2898,47 @@ static void rd_variance_adjustment(VP9_COMP *cpi, *this_rd += (*this_rd * var_factor) / 100; } + +// Do we have an internal image edge (e.g. formatting bars). +int vp9_internal_image_edge(VP9_COMP *cpi) { + return (cpi->oxcf.pass == 2) && + ((cpi->twopass.this_frame_stats.inactive_zone_rows > 0) || + (cpi->twopass.this_frame_stats.inactive_zone_cols > 0)); +} + +// Checks to see if a macro block is at the edge of the active image. +// In most cases this is the "real" edge unless there are formatting +// bars embedded in the stream. +int vp9_active_edge_sb(VP9_COMP *cpi, + int mi_row, int mi_col) { + int is_active_edge = 0; + int top_edge = 0; + int bottom_edge = cpi->common.mi_rows; + int left_edge = 0; + int right_edge = cpi->common.mi_cols; + + // For two pass account for any formatting bars detected. + if (cpi->oxcf.pass == 2) { + TWO_PASS *twopass = &cpi->twopass; + + // The inactive region is specified in MBs not mi units. + // The image edge is in the following MB row. + top_edge += (int)(twopass->this_frame_stats.inactive_zone_rows * 2); + + bottom_edge -= (int)(twopass->this_frame_stats.inactive_zone_rows * 2); + bottom_edge = MAX(top_edge, bottom_edge); + } + + if (((top_edge >= mi_row) && (top_edge < (mi_row + MI_BLOCK_SIZE))) || + ((bottom_edge >= mi_row) && (bottom_edge < (mi_row + MI_BLOCK_SIZE))) || + ((left_edge >= mi_col) && (left_edge < (mi_col + MI_BLOCK_SIZE))) || + ((right_edge >= mi_col) && (right_edge < (mi_col + MI_BLOCK_SIZE)))) { + is_active_edge = 1; + } + + return is_active_edge; +} + void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, TileDataEnc *tile_data, MACROBLOCK *x, @@ -3751,13 +3792,15 @@ void vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, int skip_uv; PREDICTION_MODE mode_uv = DC_PRED; 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); int_mv seg_mvs[4][MAX_REF_FRAMES]; b_mode_info best_bmodes[4]; int best_skip2 = 0; int ref_frame_skip_mask[2] = { 0 }; int64_t mask_filter = 0; int64_t filter_cache[SWITCHABLE_FILTER_CONTEXTS]; + int internal_active_edge = + vp9_active_edge_sb(cpi, mi_row, mi_col) && vp9_internal_image_edge(cpi); x->skip_encode = sf->skip_encode_frame && x->q_index < QIDX_SKIP_THRESH; memset(x->zcoeff_blk[TX_4X4], 0, 4); @@ -3843,7 +3886,8 @@ void vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, continue; // Test best rd so far against threshold for trying this mode. - if (rd_less_than_thresh(best_rd, + if (!internal_active_edge && + rd_less_than_thresh(best_rd, rd_opt->threshes[segment_id][bsize][ref_index], tile_data->thresh_freq_fact[bsize][ref_index])) continue; diff --git a/vp9/encoder/vp9_rdopt.h b/vp9/encoder/vp9_rdopt.h index 459b0324b..16a8c68ee 100644 --- a/vp9/encoder/vp9_rdopt.h +++ b/vp9/encoder/vp9_rdopt.h @@ -54,6 +54,9 @@ void vp9_rd_pick_inter_mode_sb_seg_skip(struct VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far); +int vp9_internal_image_edge(struct VP9_COMP *cpi); +int vp9_active_edge_sb(struct VP9_COMP *cpi, int mi_row, int mi_col); + void vp9_rd_pick_inter_mode_sub8x8(struct VP9_COMP *cpi, struct TileDataEnc *tile_data, struct macroblock *x, @@ -61,6 +64,7 @@ void vp9_rd_pick_inter_mode_sub8x8(struct VP9_COMP *cpi, struct RD_COST *rd_cost, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far); + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c index 6c6c4ed30..b3e5a0e4d 100644 --- a/vp9/encoder/vp9_speed_features.c +++ b/vp9/encoder/vp9_speed_features.c @@ -12,6 +12,8 @@ #include "vp9/encoder/vp9_encoder.h" #include "vp9/encoder/vp9_speed_features.h" +#include "vp9/encoder/vp9_rdopt.h" + // Intra only frames, golden frames (except alt ref overlays) and // alt ref frames tend to be coded at a higher than ambient quality @@ -90,7 +92,8 @@ static void set_good_speed_feature_framesize_dependent(VP9_COMP *cpi, // If this is a two pass clip that fits the criteria for animated or // graphics content then reset disable_split_mask for speeds 1-4. if ((speed >= 1) && (cpi->oxcf.pass == 2) && - (cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION)) { + ((cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION) || + (vp9_internal_image_edge(cpi)))) { sf->disable_split_mask = DISABLE_COMPOUND_SPLIT; } -- 2.50.0