From: Paul Wilkins Date: Tue, 4 Nov 2014 13:13:39 +0000 (+0000) Subject: Add intra complexity and brightness weight to first pass. X-Git-Tag: v1.4.0~521^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5e935126a66aa9cbb0008310ca05500f3eec8269;p=libvpx Add intra complexity and brightness weight to first pass. The aim of this patch is to apply a positive weighting to frames that have a significant number of blocks that are of low spatial complexity and are dark. The rationale behind this is that artifacts tend to be more visible in such frames. In this patch the weight is only applied in regard to the distribution of bits between frames. Hence if all the frames share similar characteristics (as is the case for most of our short test clips) there will be little or no net effect. However, the effect can be seen on some longer form test content. For example Tears of steel baseline test: 2323.09 Kbit/s opsnr 39.915 ssim 74.729 With this patch:- 2213.34 Kbit/s opsnr 39.963 ssim 74.808 (Sligtly better metrics and about 5% smaller) The weighting may well need some further tuning along side changes to the aq modes. Change-Id: Ieced379bca03938166ab87b2b97f55d94948904c --- diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index c8c784b73..85b2db146 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -53,6 +53,7 @@ #define MIN_KF_BOOST 300 #define NEW_MV_MODE_PENALTY 32 #define SVC_FACTOR_PT_LOW 0.45 +#define DARK_THRESH 64 #define DOUBLE_DIVIDE_CHECK(x) ((x) < 0 ? (x) - 0.000001 : (x) + 0.000001) @@ -106,10 +107,11 @@ static void output_stats(FIRSTPASS_STATS *stats, FILE *fpfile; fpfile = fopen("firstpass.stt", "a"); - fprintf(fpfile, "%12.0f %12.0f %12.0f %12.0f %12.4f %12.4f" + fprintf(fpfile, "%12.0f %12.4f %12.0f %12.0f %12.0f %12.4f %12.4f" "%12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f" "%12.0f %12.0f %12.4f %12.0f %12.0f %12.4f\n", stats->frame, + stats->weight, stats->intra_error, stats->coded_error, stats->sr_coded_error, @@ -144,7 +146,8 @@ static void output_fpmb_stats(uint8_t *this_frame_mb_stats, VP9_COMMON *cm, #endif static void zero_stats(FIRSTPASS_STATS *section) { - section->frame = 0.0; + section->frame = 0.0; + section->weight = 0.0; section->intra_error = 0.0; section->coded_error = 0.0; section->sr_coded_error = 0.0; @@ -168,6 +171,7 @@ static void zero_stats(FIRSTPASS_STATS *section) { static void accumulate_stats(FIRSTPASS_STATS *section, const FIRSTPASS_STATS *frame) { section->frame += frame->frame; + section->weight += frame->weight; section->spatial_layer_id = frame->spatial_layer_id; section->intra_error += frame->intra_error; section->coded_error += frame->coded_error; @@ -191,6 +195,7 @@ static void accumulate_stats(FIRSTPASS_STATS *section, static void subtract_stats(FIRSTPASS_STATS *section, const FIRSTPASS_STATS *frame) { section->frame -= frame->frame; + section->weight -= frame->weight; section->intra_error -= frame->intra_error; section->coded_error -= frame->coded_error; section->sr_coded_error -= frame->sr_coded_error; @@ -217,10 +222,11 @@ static double calculate_modified_err(const TWO_PASS *twopass, const VP9EncoderConfig *oxcf, const FIRSTPASS_STATS *this_frame) { const FIRSTPASS_STATS *const stats = &twopass->total_stats; - const double av_err = stats->coded_error / stats->count; - const double modified_error = av_err * - pow(this_frame->coded_error / DOUBLE_DIVIDE_CHECK(av_err), - oxcf->two_pass_vbrbias / 100.0); + const double av_weight = stats->weight / stats->count; + const double av_err = (stats->coded_error * av_weight) / stats->count; + const double modified_error = + av_err * pow(this_frame->coded_error * this_frame->weight / + DOUBLE_DIVIDE_CHECK(av_err), oxcf->two_pass_vbrbias / 100.0); return fclamp(modified_error, twopass->modified_error_min, twopass->modified_error_max); } @@ -480,6 +486,8 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { const YV12_BUFFER_CONFIG *first_ref_buf = lst_yv12; LAYER_CONTEXT *const lc = is_two_pass_svc(cpi) ? &cpi->svc.layer_context[cpi->svc.spatial_layer_id] : NULL; + double intra_factor = 0.0; + double brightness_factor = 0.0; #if CONFIG_FP_MB_STATS if (cpi->use_fp_mb_stats) { @@ -587,6 +595,9 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { const int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row); double error_weight = 1.0; const BLOCK_SIZE bsize = get_bsize(cm, mb_row, mb_col); + double log_intra; + int level_sample; + #if CONFIG_FP_MB_STATS const int mb_index = mb_row * cm->mb_cols + mb_col; #endif @@ -635,6 +646,25 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { } #endif // CONFIG_VP9_HIGHBITDEPTH + log_intra = log(this_error + 1.0); + if (log_intra < 10.0) + intra_factor += 1.0 + ((10.0 - log_intra) * 0.05); + else + intra_factor += 1.0; + +#if CONFIG_VP9_HIGHBITDEPTH + if (cm->use_highbitdepth) + level_sample = CONVERT_TO_SHORTPTR(x->plane[0].src.buf)[0]; + else + level_sample = x->plane[0].src.buf[0]; +#else + level_sample = x->plane[0].src.buf[0]; +#endif + if ((level_sample < DARK_THRESH) && (log_intra < 9.0)) + brightness_factor += 1.0 + (0.01 * (DARK_THRESH - level_sample)); + else + brightness_factor += 1.0; + if (cpi->oxcf.aq_mode == VARIANCE_AQ) { vp9_clear_system_state(); this_error = (int)(this_error * error_weight); @@ -943,6 +973,10 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { cpi->oxcf.allow_spatial_resampling ? cpi->initial_mbs : cpi->common.MBs; const double min_err = 200 * sqrt(num_mbs); + intra_factor = intra_factor / (double)num_mbs; + brightness_factor = brightness_factor / (double)num_mbs; + fps.weight = intra_factor * brightness_factor; + fps.frame = cm->current_video_frame; fps.spatial_layer_id = cpi->svc.spatial_layer_id; fps.coded_error = (double)(coded_error >> 8) + min_err; @@ -1094,7 +1128,8 @@ static int get_twopass_worst_quality(const VP9_COMP *cpi, // content at the given rate. for (q = rc->best_quality; q < rc->worst_quality; ++q) { const double factor = - calc_correction_factor(err_per_mb, ERR_DIVISOR - ediv_size_correction, + calc_correction_factor(err_per_mb, + ERR_DIVISOR - ediv_size_correction, is_svc_upper_layer ? SVC_FACTOR_PT_LOW : FACTOR_PT_LOW, FACTOR_PT_HIGH, q, cpi->common.bit_depth); @@ -1319,14 +1354,14 @@ static double calc_frame_boost(VP9_COMP *cpi, const double lq = vp9_convert_qindex_to_q(cpi->rc.avg_frame_qindex[INTER_FRAME], cpi->common.bit_depth); - const double boost_correction = MIN((0.5 + (lq * 0.015)), 1.5); + const double boost_q_correction = MIN((0.5 + (lq * 0.015)), 1.5); const int num_mbs = cpi->oxcf.allow_spatial_resampling ? cpi->initial_mbs : cpi->common.MBs; // Underlying boost factor is based on inter error ratio. frame_boost = (BASELINE_ERR_PER_MB * num_mbs) / DOUBLE_DIVIDE_CHECK(this_frame->coded_error); - frame_boost = frame_boost * BOOST_FACTOR * boost_correction; + frame_boost = frame_boost * BOOST_FACTOR * boost_q_correction; // Increase boost for frames where new data coming into frame (e.g. zoom out). // Slightly reduce boost if there is a net balance of motion out of the frame @@ -1337,7 +1372,7 @@ static double calc_frame_boost(VP9_COMP *cpi, else frame_boost += frame_boost * (this_frame_mv_in_out / 2.0); - return MIN(frame_boost, max_boost * boost_correction); + return MIN(frame_boost, max_boost * boost_q_correction); } static int calc_arf_boost(VP9_COMP *cpi, int offset, diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h index e21d86928..0a8f756bf 100644 --- a/vp9/encoder/vp9_firstpass.h +++ b/vp9/encoder/vp9_firstpass.h @@ -43,6 +43,7 @@ typedef struct { typedef struct { double frame; + double weight; double intra_error; double coded_error; double sr_coded_error;