From 668e804504021aee1ad1c6ee095b746885596135 Mon Sep 17 00:00:00 2001 From: Paul Wilkins Date: Wed, 27 May 2015 01:37:18 +0100 Subject: [PATCH] Animation and dead zone detection. Adds code to detect dead zone bars at the top and bottom of reformatted letterbox video (note that the code only looks at the top of the image and assumes any dead zone is symmetrical). Use of this to adapt rate control etc. will follow in a subsequent patch. Also counts other blocks (excluding the dead zone) that have no intra signal. The presence of a significant number of such blocks can be used as a identify that the frame may be artificial (e.g. animation, screen capture, graphics). This patch contains plumbing only and does not use the signal. Change-Id: I59bc93529cd4065416cef773e405fda3ae006a20 --- vp9/encoder/vp9_firstpass.c | 48 ++++++++++++++++++++++++++++---- vp9/encoder/vp9_firstpass.h | 2 ++ vp9/encoder/vp9_speed_features.c | 47 +++++++++++++++---------------- 3 files changed, 68 insertions(+), 29 deletions(-) diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index 856a6655c..802fb849a 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -113,8 +113,8 @@ static void output_stats(FIRSTPASS_STATS *stats, fpfile = fopen("firstpass.stt", "a"); fprintf(fpfile, "%12.0lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf %12.4lf" - "%12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf" - "%12.4lf %12.0lf %12.0lf %12.0lf %12.4lf\n", + "%12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf" + "%12.4lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf\n", stats->frame, stats->weight, stats->intra_error, @@ -124,6 +124,8 @@ static void output_stats(FIRSTPASS_STATS *stats, stats->pcnt_motion, stats->pcnt_second_ref, stats->pcnt_neutral, + stats->ul_intra_pct, + stats->image_start_row, stats->MVr, stats->mvr_abs, stats->MVc, @@ -160,7 +162,9 @@ static void zero_stats(FIRSTPASS_STATS *section) { section->pcnt_motion = 0.0; section->pcnt_second_ref = 0.0; section->pcnt_neutral = 0.0; - section->MVr = 0.0; + section->ul_intra_pct = 0.0; + section->image_start_row = 0.0; + section->MVr = 0.0; section->mvr_abs = 0.0; section->MVc = 0.0; section->mvc_abs = 0.0; @@ -185,7 +189,9 @@ static void accumulate_stats(FIRSTPASS_STATS *section, section->pcnt_motion += frame->pcnt_motion; section->pcnt_second_ref += frame->pcnt_second_ref; section->pcnt_neutral += frame->pcnt_neutral; - section->MVr += frame->MVr; + section->ul_intra_pct += frame->ul_intra_pct; + section->image_start_row += frame->image_start_row; + section->MVr += frame->MVr; section->mvr_abs += frame->mvr_abs; section->MVc += frame->MVc; section->mvc_abs += frame->mvc_abs; @@ -208,7 +214,9 @@ static void subtract_stats(FIRSTPASS_STATS *section, section->pcnt_motion -= frame->pcnt_motion; section->pcnt_second_ref -= frame->pcnt_second_ref; section->pcnt_neutral -= frame->pcnt_neutral; - section->MVr -= frame->MVr; + section->ul_intra_pct -= frame->ul_intra_pct; + section->image_start_row -= frame->image_start_row; + section->MVr -= frame->MVr; section->mvr_abs -= frame->mvr_abs; section->MVc -= frame->MVc; section->mvc_abs -= frame->mvc_abs; @@ -453,6 +461,8 @@ static void set_first_pass_params(VP9_COMP *cpi) { cpi->rc.frames_to_key = INT_MAX; } +#define UL_INTRA_THRESH 50 +#define INVALID_ROW -1 void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { int mb_row, mb_col; MACROBLOCK *const x = &cpi->td.mb; @@ -477,6 +487,8 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { int second_ref_count = 0; const int intrapenalty = INTRA_MODE_PENALTY; double neutral_count; + int ul_intra_count = 0; + int image_data_start_row = INVALID_ROW; int new_mv_count = 0; int sum_in_vectors = 0; MV lastmv = {0, 0}; @@ -636,6 +648,18 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { (bsize >= BLOCK_16X16 ? TX_16X16 : TX_8X8) : TX_4X4; vp9_encode_intra_block_plane(x, bsize, 0); this_error = vpx_get_mb_ss(x->plane[0].src_diff); + + // Keep a record of blocks that have almost no intra error residual + // (i.e. are in effect completely flat and untextured in the intra + // domain). In natural videos this is uncommon, but it is much more + // common in animations, graphics and screen content, so may be used + // as a signal to detect these types of content. + if (this_error < UL_INTRA_THRESH) { + ++ul_intra_count; + } else if ((mb_col > 0) && (image_data_start_row == INVALID_ROW)) { + image_data_start_row = mb_row; + } + #if CONFIG_VP9_HIGHBITDEPTH if (cm->use_highbitdepth) { switch (cm->bit_depth) { @@ -963,6 +987,18 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { vp9_clear_system_state(); } + // Clamp the image start to rows/2. This number of rows is discarded top + // and bottom as dead data so rows / 2 means the frame is blank. + if ((image_data_start_row > cm->mb_rows / 2) || + (image_data_start_row == INVALID_ROW)) { + image_data_start_row = cm->mb_rows / 2; + } + // Exclude any image dead zone + if (image_data_start_row > 0) { + ul_intra_count = + MAX(0, ul_intra_count - (image_data_start_row * cm->mb_cols * 2)); + } + { FIRSTPASS_STATS fps; // The minimum error here insures some bit allocation to frames even @@ -987,6 +1023,8 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { fps.pcnt_inter = (double)intercount / num_mbs; fps.pcnt_second_ref = (double)second_ref_count / num_mbs; fps.pcnt_neutral = (double)neutral_count / num_mbs; + fps.ul_intra_pct = (double)ul_intra_count / num_mbs; + fps.image_start_row = (double)image_data_start_row; if (mvcount > 0) { fps.MVr = (double)sum_mvr / mvcount; diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h index 4a0385506..ac2ce13a0 100644 --- a/vp9/encoder/vp9_firstpass.h +++ b/vp9/encoder/vp9_firstpass.h @@ -51,6 +51,8 @@ typedef struct { double pcnt_motion; double pcnt_second_ref; double pcnt_neutral; + double ul_intra_pct; + double image_start_row; double MVr; double mvr_abs; double MVc; diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c index 61c066e5d..3697ec0ec 100644 --- a/vp9/encoder/vp9_speed_features.c +++ b/vp9/encoder/vp9_speed_features.c @@ -19,6 +19,28 @@ static int frame_is_boosted(const VP9_COMP *cpi) { return frame_is_kf_gf_arf(cpi) || vp9_is_upper_layer_key_frame(cpi); } +// Sets a partition size down to which the auto partition code will always +// search (can go lower), based on the image dimensions. The logic here +// is that the extent to which ringing artefacts are offensive, depends +// partly on the screen area that over which they propogate. Propogation is +// limited by transform block size but the screen area take up by a given block +// size will be larger for a small image format stretched to full screen. +static BLOCK_SIZE set_partition_min_limit(VP9_COMMON *const cm) { + unsigned int screen_area = (cm->width * cm->height); + + // Select block size based on image format size. + if (screen_area < 1280 * 720) { + // Formats smaller in area than 720P + return BLOCK_4X4; + } else if (screen_area < 1920 * 1080) { + // Format >= 720P and < 1080P + return BLOCK_8X8; + } else { + // Formats 1080P and up + return BLOCK_16X16; + } +} + static void set_good_speed_feature_framesize_dependent(VP9_COMMON *cm, SPEED_FEATURES *sf, int speed) { @@ -45,6 +67,7 @@ static void set_good_speed_feature_framesize_dependent(VP9_COMMON *cm, sf->partition_search_breakout_dist_thr = (1 << 22); sf->partition_search_breakout_rate_thr = 100; } + sf->rd_auto_partition_min_limit = set_partition_min_limit(cm); } if (speed >= 3) { @@ -72,29 +95,6 @@ static void set_good_speed_feature_framesize_dependent(VP9_COMMON *cm, } } -// Sets a partition size down to which the auto partition code will always -// search (can go lower), based on the image dimensions. The logic here -// is that the extent to which ringing artefacts are offensive, depends -// partly on the screen area that over which they propogate. Propogation is -// limited by transform block size but the screen area take up by a given block -// size will be larger for a small image format stretched to full screen. -static BLOCK_SIZE set_partition_min_limit(VP9_COMP *cpi) { - VP9_COMMON *const cm = &cpi->common; - unsigned int screen_area = (cm->width * cm->height); - - // Select block size based on image format size. - if (screen_area < 1280 * 720) { - // Formats smaller in area than 720P - return BLOCK_4X4; - } else if (screen_area < 1920 * 1080) { - // Format >= 720P and < 1080P - return BLOCK_8X8; - } else { - // Formats 1080P and up - return BLOCK_16X16; - } -} - static void set_good_speed_feature(VP9_COMP *cpi, VP9_COMMON *cm, SPEED_FEATURES *sf, int speed) { const int boosted = frame_is_boosted(cpi); @@ -139,7 +139,6 @@ static void set_good_speed_feature(VP9_COMP *cpi, VP9_COMMON *cm, sf->disable_filter_search_var_thresh = 100; sf->comp_inter_joint_search_thresh = BLOCK_SIZES; sf->auto_min_max_partition_size = RELAXED_NEIGHBORING_MIN_MAX; - sf->rd_auto_partition_min_limit = set_partition_min_limit(cpi); sf->allow_partition_search_skip = 1; } -- 2.40.0