Port first pass stats handling from Vp9 into Av1
Some parameter tuning included.
lowres (q, 30 frames, speed 1):
-1.243% av PSNR, -2.337% ov PSNR, +0.577% SSIM
lowres (vbr, 30 frames, speed 1):
-0.327% av PSNR, -1.007% ov PSNR, +0.182% SSIM
A few videos become a lot worse in SSIM, which needs to be
investigated. But PSNR-wise the patch seems pretty good.
Change-Id: I17c8d812c96ee49ddae7d3959a459aa3ffcea208
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index 8fdb0cb..9d896a2 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -47,26 +47,32 @@
#define GROUP_ADAPTIVE_MAXQ 1
-#define BOOST_BREAKOUT 12.5
-#define BOOST_FACTOR 12.5
-#define FACTOR_PT_LOW 0.70
-#define FACTOR_PT_HIGH 0.90
#define FIRST_PASS_Q 10.0
-#define GF_MAX_BOOST 96.0
#define INTRA_MODE_PENALTY 1024
-#define KF_MAX_BOOST 128.0
-#define MIN_ARF_GF_BOOST 240
#define MIN_DECAY_FACTOR 0.01
-#define MIN_KF_BOOST 300
#define NEW_MV_MODE_PENALTY 32
#define DARK_THRESH 64
#define DEFAULT_GRP_WEIGHT 1.0
-#define RC_FACTOR_MIN 0.75
-#define RC_FACTOR_MAX 1.75
+#define SECTION_NOISE_DEF 250.0
+#define LOW_I_THRESH 24000
+#define ARF_ABS_ZOOM_THRESH 4.0
#define NCOUNT_INTRA_THRESH 8192
#define NCOUNT_INTRA_FACTOR 3
-#define NCOUNT_FRAME_II_THRESH 5.0
+
+#define FRAMES_TO_CHECK_DECAY 8
+#define KF_BOOST_SCAN_MAX_FRAMES 32
+
+#define MIN_ARF_GF_BOOST 240
+#define MIN_KF_TOT_BOOST 300
+#define MAX_KF_TOT_BOOST 5000
+#define KF_MAX_FRAME_BOOST 72.0
+#define GF_MAX_FRAME_BOOST 72.0
+
+#define KF_ABS_ZOOM_THRESH 6.0
+#define ARF_ABS_ZOOM_THRESH 4.0
+
+#define ALWAYS_ADJUST_BPM 0
#define DOUBLE_DIVIDE_CHECK(x) ((x) < 0 ? (x)-0.000001 : (x) + 0.000001)
@@ -145,11 +151,15 @@
section->intra_error = 0.0;
section->coded_error = 0.0;
section->sr_coded_error = 0.0;
+ section->frame_noise_energy = 0.0;
section->pcnt_inter = 0.0;
section->pcnt_motion = 0.0;
section->pcnt_second_ref = 0.0;
section->pcnt_neutral = 0.0;
+ section->pcnt_intra_low = 0.0;
+ section->pcnt_intra_high = 0.0;
section->intra_skip_pct = 0.0;
+ section->intra_smooth_pct = 0.0;
section->inactive_zone_rows = 0.0;
section->inactive_zone_cols = 0.0;
section->MVr = 0.0;
@@ -171,11 +181,15 @@
section->intra_error += frame->intra_error;
section->coded_error += frame->coded_error;
section->sr_coded_error += frame->sr_coded_error;
+ section->frame_noise_energy += frame->frame_noise_energy;
section->pcnt_inter += frame->pcnt_inter;
section->pcnt_motion += frame->pcnt_motion;
section->pcnt_second_ref += frame->pcnt_second_ref;
section->pcnt_neutral += frame->pcnt_neutral;
+ section->pcnt_intra_low += frame->pcnt_intra_low;
+ section->pcnt_intra_high += frame->pcnt_intra_high;
section->intra_skip_pct += frame->intra_skip_pct;
+ section->intra_smooth_pct += frame->intra_smooth_pct;
section->inactive_zone_rows += frame->inactive_zone_rows;
section->inactive_zone_cols += frame->inactive_zone_cols;
section->MVr += frame->MVr;
@@ -197,11 +211,15 @@
section->intra_error -= frame->intra_error;
section->coded_error -= frame->coded_error;
section->sr_coded_error -= frame->sr_coded_error;
+ section->frame_noise_energy -= frame->frame_noise_energy;
section->pcnt_inter -= frame->pcnt_inter;
section->pcnt_motion -= frame->pcnt_motion;
section->pcnt_second_ref -= frame->pcnt_second_ref;
section->pcnt_neutral -= frame->pcnt_neutral;
+ section->pcnt_intra_low -= frame->pcnt_intra_low;
+ section->pcnt_intra_high -= frame->pcnt_intra_high;
section->intra_skip_pct -= frame->intra_skip_pct;
+ section->intra_smooth_pct -= frame->intra_smooth_pct;
section->inactive_zone_rows -= frame->inactive_zone_rows;
section->inactive_zone_cols -= frame->inactive_zone_cols;
section->MVr -= frame->MVr;
@@ -238,17 +256,23 @@
return fclamp(active_pct, MIN_ACTIVE_AREA, MAX_ACTIVE_AREA);
}
+// Get the average weighted error for the clip (or corpus)
+static double get_distribution_av_err(TWO_PASS *const twopass) {
+ const double av_weight =
+ twopass->total_stats.weight / twopass->total_stats.count;
+
+ return (twopass->total_stats.coded_error * av_weight) /
+ twopass->total_stats.count;
+}
+
+#define ACT_AREA_CORRECTION 0.5
// Calculate a modified Error used in distributing bits between easier and
// harder frames.
-#define ACT_AREA_CORRECTION 0.5
-static double calculate_modified_err(const AV1_COMP *cpi,
- const TWO_PASS *twopass,
- const AV1EncoderConfig *oxcf,
- const FIRSTPASS_STATS *this_frame) {
- const FIRSTPASS_STATS *const stats = &twopass->total_stats;
- const double av_weight = stats->weight / stats->count;
- const double av_err = (stats->coded_error * av_weight) / stats->count;
- double modified_error =
+static double calculate_mod_frame_score(const AV1_COMP *cpi,
+ const AV1EncoderConfig *oxcf,
+ const FIRSTPASS_STATS *this_frame,
+ double av_err) {
+ double modified_score =
av_err * pow(this_frame->coded_error * this_frame->weight /
DOUBLE_DIVIDE_CHECK(av_err),
oxcf->two_pass_vbrbias / 100.0);
@@ -258,11 +282,35 @@
// remaining active MBs. The correction here assumes that coding
// 0.5N blocks of complexity 2X is a little easier than coding N
// blocks of complexity X.
- modified_error *=
+ modified_score *=
+ pow(calculate_active_area(cpi, this_frame), ACT_AREA_CORRECTION);
+ return modified_score;
+}
+
+static double calculate_norm_frame_score(const AV1_COMP *cpi,
+ const TWO_PASS *twopass,
+ const AV1EncoderConfig *oxcf,
+ const FIRSTPASS_STATS *this_frame,
+ double av_err) {
+ double modified_score =
+ av_err * pow(this_frame->coded_error * this_frame->weight /
+ DOUBLE_DIVIDE_CHECK(av_err),
+ oxcf->two_pass_vbrbias / 100.0);
+
+ const double min_score = (double)(oxcf->two_pass_vbrmin_section) / 100.0;
+ const double max_score = (double)(oxcf->two_pass_vbrmax_section) / 100.0;
+ // Correction for active area. Frames with a reduced active area
+ // (eg due to formatting bars) have a higher error per mb for the
+ // remaining active MBs. The correction here assumes that coding
+ // 0.5N blocks of complexity 2X is a little easier than coding N
+ // blocks of complexity X.
+ modified_score *=
pow(calculate_active_area(cpi, this_frame), ACT_AREA_CORRECTION);
- return fclamp(modified_error, twopass->modified_error_min,
- twopass->modified_error_max);
+ // Normalize to a midpoint score.
+ modified_score /= DOUBLE_DIVIDE_CHECK(twopass->mean_mod_score);
+
+ return fclamp(modified_score, min_score, max_score);
}
// This function returns the maximum target rate per frame.
@@ -479,6 +527,170 @@
}
#define UL_INTRA_THRESH 50
+static int get_ul_intra_threshold(AV1_COMMON *cm) {
+ int ret_val = UL_INTRA_THRESH;
+ if (cm->use_highbitdepth) {
+ switch (cm->bit_depth) {
+ case AOM_BITS_8: ret_val = UL_INTRA_THRESH; break;
+ case AOM_BITS_10: ret_val = UL_INTRA_THRESH << 2; break;
+ case AOM_BITS_12: ret_val = UL_INTRA_THRESH << 4; break;
+ default:
+ assert(0 &&
+ "cm->bit_depth should be AOM_BITS_8, "
+ "AOM_BITS_10 or AOM_BITS_12");
+ }
+ }
+ return ret_val;
+}
+
+#define SMOOTH_INTRA_THRESH 4000
+static int get_smooth_intra_threshold(AV1_COMMON *cm) {
+ int ret_val = SMOOTH_INTRA_THRESH;
+ if (cm->use_highbitdepth) {
+ switch (cm->bit_depth) {
+ case AOM_BITS_8: ret_val = SMOOTH_INTRA_THRESH; break;
+ case AOM_BITS_10: ret_val = SMOOTH_INTRA_THRESH << 4; break;
+ case AOM_BITS_12: ret_val = SMOOTH_INTRA_THRESH << 8; break;
+ default:
+ assert(0 &&
+ "cm->bit_depth should be AOM_BITS_8, "
+ "AOM_BITS_10 or AOM_BITS_12");
+ }
+ }
+ return ret_val;
+}
+
+#define FP_DN_THRESH 8
+#define FP_MAX_DN_THRESH 16
+#define KERNEL_SIZE 3
+// Baseline Kernal weights for first pass noise metric
+static uint8_t fp_dn_kernel_3[KERNEL_SIZE * KERNEL_SIZE] = { 1, 2, 1, 2, 4,
+ 2, 1, 2, 1 };
+
+static int fp_estimate_point_noise(uint8_t *src_ptr, const int stride) {
+ int sum_weight = 0;
+ int sum_val = 0;
+ int i, j;
+ int max_diff = 0;
+ int diff;
+ int dn_diff;
+ uint8_t *tmp_ptr;
+ uint8_t *kernel_ptr;
+ uint8_t dn_val;
+ uint8_t centre_val = *src_ptr;
+
+ kernel_ptr = fp_dn_kernel_3;
+
+ // Apply the kernel
+ tmp_ptr = src_ptr - stride - 1;
+ for (i = 0; i < KERNEL_SIZE; ++i) {
+ for (j = 0; j < KERNEL_SIZE; ++j) {
+ diff = abs((int)centre_val - (int)tmp_ptr[j]);
+ max_diff = AOMMAX(max_diff, diff);
+ if (diff <= FP_DN_THRESH) {
+ sum_weight += *kernel_ptr;
+ sum_val += (int)tmp_ptr[j] * (int)*kernel_ptr;
+ }
+ ++kernel_ptr;
+ }
+ tmp_ptr += stride;
+ }
+
+ if (max_diff < FP_MAX_DN_THRESH)
+ // Update the source value with the new filtered value
+ dn_val = (sum_val + (sum_weight >> 1)) / sum_weight;
+ else
+ dn_val = *src_ptr;
+ // return the noise energy as the square of the
+ // difference between the denoised and raw value.
+ dn_diff = (int)*src_ptr - (int)dn_val;
+ return dn_diff * dn_diff;
+}
+
+static int fp_highbd_estimate_point_noise(uint8_t *src_ptr, int stride) {
+ int sum_weight = 0;
+ int sum_val = 0;
+ int i, j;
+ int max_diff = 0;
+ int diff;
+ int dn_diff;
+ uint8_t *tmp_ptr;
+ uint16_t *tmp_ptr16;
+ uint8_t *kernel_ptr;
+ uint16_t dn_val;
+ uint16_t centre_val = *CONVERT_TO_SHORTPTR(src_ptr);
+
+ kernel_ptr = fp_dn_kernel_3;
+
+ // Apply the kernel
+ tmp_ptr = src_ptr - stride - 1;
+ for (i = 0; i < KERNEL_SIZE; ++i) {
+ tmp_ptr16 = CONVERT_TO_SHORTPTR(tmp_ptr);
+ for (j = 0; j < KERNEL_SIZE; ++j) {
+ diff = abs((int)centre_val - (int)tmp_ptr16[j]);
+ max_diff = AOMMAX(max_diff, diff);
+ if (diff <= FP_DN_THRESH) {
+ sum_weight += *kernel_ptr;
+ sum_val += (int)tmp_ptr16[j] * (int)*kernel_ptr;
+ }
+ ++kernel_ptr;
+ }
+ tmp_ptr += stride;
+ }
+
+ if (max_diff < FP_MAX_DN_THRESH)
+ // Update the source value with the new filtered value
+ dn_val = (sum_val + (sum_weight >> 1)) / sum_weight;
+ else
+ dn_val = *CONVERT_TO_SHORTPTR(src_ptr);
+
+ // return the noise energy as the square of the difference between the
+ // denoised and raw value.
+ dn_diff = (int)(*CONVERT_TO_SHORTPTR(src_ptr)) - (int)dn_val;
+ return dn_diff * dn_diff;
+}
+
+static int fp_estimate_block_noise(MACROBLOCK *x, BLOCK_SIZE bsize) {
+ MACROBLOCKD *xd = &x->e_mbd;
+ uint8_t *src_ptr = &x->plane[0].src.buf[0];
+ const int width = num_4x4_blocks_wide_lookup[bsize] * 4;
+ const int height = num_4x4_blocks_high_lookup[bsize] * 4;
+ int w, h;
+ int stride = x->plane[0].src.stride;
+ int block_noise = 0;
+
+ // Sampled points to reduce cost overhead.
+ for (h = 0; h < height; h += 2) {
+ for (w = 0; w < width; w += 2) {
+ if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH)
+ block_noise += fp_highbd_estimate_point_noise(src_ptr, stride);
+ else
+ block_noise += fp_estimate_point_noise(src_ptr, stride);
+ ++src_ptr;
+ }
+ src_ptr += (stride - width);
+ }
+ return block_noise << 2; // Scale << 2 to account for sampling.
+}
+
+// Scale an sse threshold to account for 8/10/12 bit.
+static int scale_sse_threshold(AV1_COMMON *cm, int thresh) {
+ int ret_val = thresh;
+ if (cm->use_highbitdepth) {
+ switch (cm->bit_depth) {
+ case AOM_BITS_8: ret_val = thresh; break;
+ case AOM_BITS_10: ret_val = thresh << 4; break;
+ case AOM_BITS_12: ret_val = thresh << 8; break;
+ default:
+ assert(0 &&
+ "cm->bit_depth should be VPX_BITS_8, "
+ "VPX_BITS_10 or VPX_BITS_12");
+ }
+ }
+ return ret_val;
+}
+
+#define UL_INTRA_THRESH 50
#define INVALID_ROW -1
void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
int mb_row, mb_col;
@@ -497,6 +709,7 @@
int64_t intra_error = 0;
int64_t coded_error = 0;
int64_t sr_coded_error = 0;
+ int64_t frame_noise_energy = 0;
int sum_mvr = 0, sum_mvc = 0;
int sum_mvr_abs = 0, sum_mvc_abs = 0;
@@ -505,8 +718,11 @@
int intercount = 0;
int second_ref_count = 0;
const int intrapenalty = INTRA_MODE_PENALTY;
- double neutral_count;
+ double neutral_count = 0.0;
int intra_skip_count = 0;
+ int intra_smooth_count = 0;
+ double intra_count_low = 0.0;
+ double intra_count_high = 0.0;
int image_data_start_row = INVALID_ROW;
int new_mv_count = 0;
int sum_in_vectors = 0;
@@ -611,6 +827,7 @@
for (mb_col = 0; mb_col < cm->mb_cols; ++mb_col) {
int this_error;
+ int this_intra_error;
const int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row);
const BLOCK_SIZE bsize = get_bsize(cm, mb_row, mb_col);
double log_intra;
@@ -645,18 +862,34 @@
use_dc_pred ? (bsize >= BLOCK_16X16 ? TX_16X16 : TX_8X8) : TX_4X4;
av1_encode_intra_block_plane(cpi, x, bsize, 0, 0, mb_row * 2, mb_col * 2);
this_error = aom_get_mb_ss(x->plane[0].src_diff);
+ this_intra_error = this_error;
// 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) {
+ if (this_error < get_ul_intra_threshold(cm)) {
++intra_skip_count;
} else if ((mb_col > 0) && (image_data_start_row == INVALID_ROW)) {
image_data_start_row = mb_row;
}
+ // Blocks that are mainly smooth in the intra domain.
+ // Some special accounting for CQ but also these are better
+ // for testing noise levels.
+ if (this_error < get_smooth_intra_threshold(cm)) {
+ ++intra_smooth_count;
+ }
+
+ if (cm->current_video_frame == 0) {
+ if (this_intra_error < scale_sse_threshold(cm, LOW_I_THRESH)) {
+ frame_noise_energy += fp_estimate_block_noise(x, bsize);
+ } else {
+ frame_noise_energy += (int64_t)SECTION_NOISE_DEF;
+ }
+ }
+
if (cm->use_highbitdepth) {
switch (cm->bit_depth) {
case AOM_BITS_8: break;
@@ -928,6 +1161,24 @@
else if (mv.col < 0)
--sum_in_vectors;
}
+ frame_noise_energy += (int64_t)SECTION_NOISE_DEF;
+ } else if (this_intra_error < scale_sse_threshold(cm, LOW_I_THRESH)) {
+ frame_noise_energy += fp_estimate_block_noise(x, bsize);
+ } else {
+ frame_noise_energy += (int64_t)SECTION_NOISE_DEF;
+ }
+ } else { // Intra < inter error
+ int scaled_low_intra_thresh = scale_sse_threshold(cm, LOW_I_THRESH);
+ if (this_intra_error < scaled_low_intra_thresh) {
+ frame_noise_energy += fp_estimate_block_noise(x, bsize);
+ if (motion_error < scaled_low_intra_thresh) {
+ intra_count_low += 1.0;
+ } else {
+ intra_count_high += 1.0;
+ }
+ } else {
+ frame_noise_energy += (int64_t)SECTION_NOISE_DEF;
+ intra_count_high += 1.0;
}
}
raw_motion_err_list[raw_motion_err_counts++] = raw_motion_error;
@@ -986,14 +1237,19 @@
fps.weight = intra_factor * brightness_factor;
fps.frame = cm->current_video_frame;
- fps.coded_error = (double)(coded_error >> 8) + min_err;
- fps.sr_coded_error = (double)(sr_coded_error >> 8) + min_err;
- fps.intra_error = (double)(intra_error >> 8) + min_err;
+ fps.coded_error = ((double)(coded_error >> 8) + min_err) / num_mbs;
+ fps.sr_coded_error = ((double)(sr_coded_error >> 8) + min_err) / num_mbs;
+ fps.intra_error = ((double)(intra_error >> 8) + min_err) / num_mbs;
+ fps.frame_noise_energy = (double)(frame_noise_energy) / (double)num_mbs;
+
fps.count = 1.0;
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.pcnt_intra_low = (double)intra_count_low / num_mbs;
+ fps.pcnt_intra_high = (double)intra_count_high / num_mbs;
fps.intra_skip_pct = (double)intra_skip_count / num_mbs;
+ fps.intra_smooth_pct = (double)intra_smooth_count / num_mbs;
fps.inactive_zone_rows = (double)image_data_start_row;
fps.inactive_zone_cols = (double)0; // TODO(paulwilkins): fix
fps.raw_error_stdev = raw_err_stdev;
@@ -1090,13 +1346,20 @@
}
static double calc_correction_factor(double err_per_mb, double err_divisor,
- double pt_low, double pt_high, int q,
- aom_bit_depth_t bit_depth) {
- const double error_term = err_per_mb / err_divisor;
+ int q) {
+ static const double q_pow_term[(QINDEX_RANGE >> 5) + 1] = {
+ 0.65, 0.70, 0.75, 0.85, 0.90, 0.90, 0.90, 1.00, 1.25
+ };
+ const double error_term = err_per_mb / DOUBLE_DIVIDE_CHECK(err_divisor);
+ const int index = q >> 5;
+ double power_term;
+
+ assert((index >= 0) && (index < (QINDEX_RANGE >> 5)));
// Adjustment based on actual quantizer to power term.
- const double power_term =
- AOMMIN(av1_convert_qindex_to_q(q, bit_depth) * 0.01 + pt_low, pt_high);
+ power_term =
+ q_pow_term[index] +
+ (((q_pow_term[index + 1] - q_pow_term[index]) * (q % 32)) / 32.0);
// Calculate correction factor.
if (power_term < 1.0) assert(error_term >= 0.0);
@@ -1104,51 +1367,70 @@
return fclamp(pow(error_term, power_term), 0.05, 5.0);
}
-#define ERR_DIVISOR 100.0
-static int get_twopass_worst_quality(const AV1_COMP *cpi,
- const double section_err,
- double inactive_zone,
- int section_target_bandwidth,
- double group_weight_factor) {
+#define ERR_DIVISOR 115.0
+#define NOISE_FACTOR_MIN 0.9
+#define NOISE_FACTOR_MAX 1.1
+static int get_twopass_worst_quality(AV1_COMP *cpi, const double section_err,
+ double inactive_zone, double section_noise,
+ int section_target_bandwidth) {
const RATE_CONTROL *const rc = &cpi->rc;
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
+ TWO_PASS *const twopass = &cpi->twopass;
+ double last_group_rate_err;
+ // Clamp the target rate to VBR min / max limts.
+ const int target_rate =
+ av1_rc_clamp_pframe_target_size(cpi, section_target_bandwidth);
+ double noise_factor = pow((section_noise / SECTION_NOISE_DEF), 0.5);
+ noise_factor = fclamp(noise_factor, NOISE_FACTOR_MIN, NOISE_FACTOR_MAX);
inactive_zone = fclamp(inactive_zone, 0.0, 1.0);
- if (section_target_bandwidth <= 0) {
+// TODO(jimbankoski): remove #if here or below when this has been
+// well tested.
+#if ALWAYS_ADJUST_BPM
+ // based on recent history adjust expectations of bits per
+ // macroblock.
+ last_group_rate_err =
+ (double)twopass->rolling_arf_group_actual_bits /
+ DOUBLE_DIVIDE_CHECK((double)twopass->rolling_arf_group_target_bits);
+ last_group_rate_err = AOMMAX(0.25, AOMMIN(4.0, last_group_rate_err));
+ twopass->bpm_factor *= (3.0 + last_group_rate_err) / 4.0;
+ twopass->bpm_factor = AOMMAX(0.25, AOMMIN(4.0, twopass->bpm_factor));
+#endif
+
+ if (target_rate <= 0) {
return rc->worst_quality; // Highest value allowed
} else {
const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE)
? cpi->initial_mbs
: cpi->common.MBs;
- const int active_mbs = AOMMAX(1, num_mbs - (int)(num_mbs * inactive_zone));
- const double av_err_per_mb = section_err / active_mbs;
- const double speed_term = 1.0;
- double ediv_size_correction;
+ const double active_pct = AOMMAX(0.01, 1.0 - inactive_zone);
+ const int active_mbs = (int)AOMMAX(1, (double)num_mbs * active_pct);
+ const double av_err_per_mb = section_err / active_pct;
+ const double speed_term = 1.0 + 0.04 * oxcf->speed;
const int target_norm_bits_per_mb =
- (int)((uint64_t)section_target_bandwidth << BPER_MB_NORMBITS) /
- active_mbs;
+ (int)(((uint64_t)target_rate << BPER_MB_NORMBITS) / active_mbs);
int q;
- // Larger image formats are expected to be a little harder to code
- // relatively given the same prediction error score. This in part at
- // least relates to the increased size and hence coding overheads of
- // motion vectors. Some account of this is made through adjustment of
- // the error divisor.
- ediv_size_correction =
- AOMMAX(0.2, AOMMIN(5.0, get_linear_size_factor(cpi)));
- if (ediv_size_correction < 1.0)
- ediv_size_correction = -(1.0 / ediv_size_correction);
- ediv_size_correction *= 4.0;
-
+// TODO(jimbankoski): remove #if here or above when this has been
+// well tested.
+#if !ALWAYS_ADJUST_BPM
+ // based on recent history adjust expectations of bits per macroblock.
+ last_group_rate_err =
+ (double)twopass->rolling_arf_group_actual_bits /
+ DOUBLE_DIVIDE_CHECK((double)twopass->rolling_arf_group_target_bits);
+ last_group_rate_err = AOMMAX(0.25, AOMMIN(4.0, last_group_rate_err));
+ twopass->bpm_factor *= (3.0 + last_group_rate_err) / 4.0;
+ twopass->bpm_factor = AOMMAX(0.25, AOMMIN(4.0, twopass->bpm_factor));
+#endif
// Try and pick a max Q that will be high enough to encode the
// content at the given rate.
for (q = rc->best_quality; q < rc->worst_quality; ++q) {
- const double factor = calc_correction_factor(
- av_err_per_mb, ERR_DIVISOR - ediv_size_correction, FACTOR_PT_LOW,
- FACTOR_PT_HIGH, q, cpi->common.bit_depth);
+ const double factor =
+ calc_correction_factor(av_err_per_mb, ERR_DIVISOR, q);
const int bits_per_mb = av1_rc_bits_per_mb(
- INTER_FRAME, q, factor * speed_term * group_weight_factor,
+ INTER_FRAME, q,
+ factor * speed_term * cpi->twopass.bpm_factor * noise_factor,
cpi->common.bit_depth);
if (bits_per_mb <= target_norm_bits_per_mb) break;
}
@@ -1184,6 +1466,32 @@
*stats = *twopass->stats_in_end;
twopass->total_left_stats = *stats;
+ {
+ double modified_score_total = 0.0;
+ const FIRSTPASS_STATS *s = twopass->stats_in;
+ double av_err;
+ av_err = get_distribution_av_err(twopass);
+ // The first scan is unclamped and gives a raw average.
+ while (s < twopass->stats_in_end) {
+ modified_score_total += calculate_mod_frame_score(cpi, oxcf, s, av_err);
+ ++s;
+ }
+
+ // The average error from this first scan is used to define the midpoint
+ // error for the rate distribution function.
+ twopass->mean_mod_score =
+ modified_score_total / DOUBLE_DIVIDE_CHECK(stats->count);
+
+ modified_score_total = 0.0;
+ s = twopass->stats_in;
+ while (s < twopass->stats_in_end) {
+ modified_score_total +=
+ calculate_norm_frame_score(cpi, twopass, oxcf, s, av_err);
+ ++s;
+ }
+ twopass->normalized_score_left = modified_score_total;
+ }
+
frame_rate = 10000000.0 * stats->count / stats->duration;
// Each frame can have a different duration, as the frame rate in the source
// isn't guaranteed to be constant. The frame rate prior to the first frame
@@ -1197,24 +1505,6 @@
// This variable monitors how far behind the second ref update is lagging.
twopass->sr_update_lag = 1;
- // Scan the first pass file and calculate a modified total error based upon
- // the bias/power function used to allocate bits.
- {
- const double avg_error =
- stats->coded_error / DOUBLE_DIVIDE_CHECK(stats->count);
- const FIRSTPASS_STATS *s = twopass->stats_in;
- double modified_error_total = 0.0;
- twopass->modified_error_min =
- (avg_error * oxcf->two_pass_vbrmin_section) / 100;
- twopass->modified_error_max =
- (avg_error * oxcf->two_pass_vbrmax_section) / 100;
- while (s < twopass->stats_in_end) {
- modified_error_total += calculate_modified_err(cpi, twopass, oxcf, s);
- ++s;
- }
- twopass->modified_error_left = modified_error_total;
- }
-
// Reset the vbr bits off target counters
cpi->rc.vbr_bits_off_target = 0;
cpi->rc.vbr_bits_off_target_fast = 0;
@@ -1225,43 +1515,54 @@
twopass->kf_zeromotion_pct = 100;
twopass->last_kfgroup_zeromotion_pct = 100;
+ // Initialize bits per macro_block estimate correction factor.
+ twopass->bpm_factor = 1.0;
+ // Initialize actual and target bits counters for ARF groups so that
+ // at the start we have a neutral bpm adjustment.
+ twopass->rolling_arf_group_target_bits = 1;
+ twopass->rolling_arf_group_actual_bits = 1;
+
if (oxcf->resize_mode != RESIZE_NONE) {
setup_rf_level_maxq(cpi);
}
+
+ // Initialize the arnr strangth adjustment to 0
+ twopass->arnr_strength_adjustment = 0;
}
#define SR_DIFF_PART 0.0015
-#define MOTION_AMP_PART 0.003
#define INTRA_PART 0.005
#define DEFAULT_DECAY_LIMIT 0.75
#define LOW_SR_DIFF_TRHESH 0.1
#define SR_DIFF_MAX 128.0
+#define LOW_CODED_ERR_PER_MB 10.0
+#define NCOUNT_FRAME_II_THRESH 6.0
static double get_sr_decay_rate(const AV1_COMP *cpi,
const FIRSTPASS_STATS *frame) {
- const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs
- : cpi->common.MBs;
- double sr_diff = (frame->sr_coded_error - frame->coded_error) / num_mbs;
+ double sr_diff = (frame->sr_coded_error - frame->coded_error);
double sr_decay = 1.0;
double modified_pct_inter;
double modified_pcnt_intra;
- const double motion_amplitude_factor =
- frame->pcnt_motion * ((frame->mvc_abs + frame->mvr_abs) / 2);
+ const double motion_amplitude_part =
+ frame->pcnt_motion * ((frame->mvc_abs + frame->mvr_abs) /
+ (cpi->initial_height + cpi->initial_width));
modified_pct_inter = frame->pcnt_inter;
- if ((frame->intra_error / DOUBLE_DIVIDE_CHECK(frame->coded_error)) <
- (double)NCOUNT_FRAME_II_THRESH) {
- modified_pct_inter = frame->pcnt_inter - frame->pcnt_neutral;
+ if ((frame->coded_error > LOW_CODED_ERR_PER_MB) &&
+ ((frame->intra_error / DOUBLE_DIVIDE_CHECK(frame->coded_error)) <
+ (double)NCOUNT_FRAME_II_THRESH)) {
+ modified_pct_inter =
+ frame->pcnt_inter + frame->pcnt_intra_low - frame->pcnt_neutral;
}
modified_pcnt_intra = 100 * (1.0 - modified_pct_inter);
if ((sr_diff > LOW_SR_DIFF_TRHESH)) {
sr_diff = AOMMIN(sr_diff, SR_DIFF_MAX);
- sr_decay = 1.0 - (SR_DIFF_PART * sr_diff) -
- (MOTION_AMP_PART * motion_amplitude_factor) -
+ sr_decay = 1.0 - (SR_DIFF_PART * sr_diff) - motion_amplitude_part -
(INTRA_PART * modified_pcnt_intra);
}
- return AOMMAX(sr_decay, AOMMIN(DEFAULT_DECAY_LIMIT, modified_pct_inter));
+ return AOMMAX(sr_decay, DEFAULT_DECAY_LIMIT);
}
// This function gives an estimate of how badly we believe the prediction
@@ -1362,38 +1663,59 @@
}
}
-#define BASELINE_ERR_PER_MB 1000.0
+#define BASELINE_ERR_PER_MB 12500.0
static double calc_frame_boost(AV1_COMP *cpi, const FIRSTPASS_STATS *this_frame,
- double this_frame_mv_in_out, double max_boost) {
+ double this_frame_mv_in_out) {
double frame_boost;
const double lq = av1_convert_qindex_to_q(
cpi->rc.avg_frame_qindex[INTER_FRAME], cpi->common.bit_depth);
const double boost_q_correction = AOMMIN((0.5 + (lq * 0.015)), 1.5);
- int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs
- : cpi->common.MBs;
-
- // Correct for any inactive region in the image
- num_mbs = (int)AOMMAX(1, num_mbs * calculate_active_area(cpi, this_frame));
+ const double active_area = calculate_active_area(cpi, this_frame);
// Underlying boost factor is based on inter error ratio.
- frame_boost = (BASELINE_ERR_PER_MB * num_mbs) /
+ frame_boost = (BASELINE_ERR_PER_MB * active_area) /
DOUBLE_DIVIDE_CHECK(this_frame->coded_error);
- 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
- // (zoom in). The range for this_frame_mv_in_out is -1.0 to +1.0.
if (this_frame_mv_in_out > 0.0)
frame_boost += frame_boost * (this_frame_mv_in_out * 2.0);
- // In the extreme case the boost is halved.
- else
- frame_boost += frame_boost * (this_frame_mv_in_out / 2.0);
+
+ // Q correction and scalling
+ frame_boost = frame_boost * boost_q_correction;
+
+ return AOMMIN(frame_boost, GF_MAX_FRAME_BOOST * boost_q_correction);
+}
+
+#define KF_BASELINE_ERR_PER_MB 12500.0
+static double calc_kf_frame_boost(AV1_COMP *cpi,
+ const FIRSTPASS_STATS *this_frame,
+ double *sr_accumulator,
+ double this_frame_mv_in_out,
+ double max_boost) {
+ double frame_boost;
+ const double lq = av1_convert_qindex_to_q(
+ cpi->rc.avg_frame_qindex[INTER_FRAME], cpi->common.bit_depth);
+ const double boost_q_correction = AOMMIN((0.50 + (lq * 0.015)), 2.00);
+ const double active_area = calculate_active_area(cpi, this_frame);
+
+ // Underlying boost factor is based on inter error ratio.
+ frame_boost = (KF_BASELINE_ERR_PER_MB * active_area) /
+ DOUBLE_DIVIDE_CHECK(this_frame->coded_error + *sr_accumulator);
+ // Update the accumulator for second ref error difference.
+ // This is intended to give an indication of how much the coded error is
+ // increasing over time.
+ *sr_accumulator += (this_frame->sr_coded_error - this_frame->coded_error);
+ *sr_accumulator = AOMMAX(0.0, *sr_accumulator);
+
+ // Small adjustment for cases where there is a zoom out
+ if (this_frame_mv_in_out > 0.0)
+ frame_boost += frame_boost * (this_frame_mv_in_out * 2.0);
+ // Q correction and scalling
+ frame_boost = frame_boost * boost_q_correction;
return AOMMIN(frame_boost, max_boost * boost_q_correction);
}
-static int calc_arf_boost(AV1_COMP *cpi, int offset, int f_frames, int b_frames,
- int *f_boost, int *b_boost) {
+static int calc_arf_boost(AV1_COMP *cpi, int f_frames, int b_frames) {
TWO_PASS *const twopass = &cpi->twopass;
int i;
double boost_score = 0.0;
@@ -1407,7 +1729,7 @@
// Search forward from the proposed arf/next gf position.
for (i = 0; i < f_frames; ++i) {
- const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i + offset);
+ const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i);
if (this_frame == NULL) break;
// Update the motion related elements to the boost calculation.
@@ -1417,8 +1739,7 @@
// We want to discount the flash frame itself and the recovery
// frame that follows as both will have poor scores.
- flash_detected = detect_flash(twopass, i + offset) ||
- detect_flash(twopass, i + offset + 1);
+ flash_detected = detect_flash(twopass, i) || detect_flash(twopass, i + 1);
// Accumulate the effect of prediction quality decay.
if (!flash_detected) {
@@ -1428,12 +1749,11 @@
: decay_accumulator;
}
- boost_score +=
- decay_accumulator *
- calc_frame_boost(cpi, this_frame, this_frame_mv_in_out, GF_MAX_BOOST);
+ boost_score += decay_accumulator *
+ calc_frame_boost(cpi, this_frame, this_frame_mv_in_out);
}
- *f_boost = (int)boost_score;
+ arf_boost = (int)boost_score;
// Reset for backward looking loop.
boost_score = 0.0;
@@ -1445,7 +1765,7 @@
// Search backward towards last gf position.
for (i = -1; i >= -b_frames; --i) {
- const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i + offset);
+ const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i);
if (this_frame == NULL) break;
// Update the motion related elements to the boost calculation.
@@ -1455,8 +1775,7 @@
// We want to discount the the flash frame itself and the recovery
// frame that follows as both will have poor scores.
- flash_detected = detect_flash(twopass, i + offset) ||
- detect_flash(twopass, i + offset + 1);
+ flash_detected = detect_flash(twopass, i) || detect_flash(twopass, i + 1);
// Cumulative effect of prediction quality decay.
if (!flash_detected) {
@@ -1466,15 +1785,13 @@
: decay_accumulator;
}
- boost_score +=
- decay_accumulator *
- calc_frame_boost(cpi, this_frame, this_frame_mv_in_out, GF_MAX_BOOST);
+ boost_score += decay_accumulator *
+ calc_frame_boost(cpi, this_frame, this_frame_mv_in_out);
}
- *b_boost = (int)boost_score;
+ arf_boost += (int)boost_score;
- arf_boost = (*f_boost + *b_boost);
- if (arf_boost < ((b_frames + f_frames) * 20))
- arf_boost = ((b_frames + f_frames) * 20);
+ if (arf_boost < ((b_frames + f_frames) * 40))
+ arf_boost = ((b_frames + f_frames) * 40);
arf_boost = AOMMAX(arf_boost, MIN_ARF_GF_BOOST);
return arf_boost;
@@ -2346,7 +2663,7 @@
}
static void allocate_gf_group_bits(AV1_COMP *cpi, int64_t gf_group_bits,
- double group_error, int gf_arf_bits) {
+ int gf_arf_bits) {
RATE_CONTROL *const rc = &cpi->rc;
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
TWO_PASS *const twopass = &cpi->twopass;
@@ -2356,10 +2673,8 @@
int frame_index = 0;
int target_frame_size;
int key_frame;
- const int max_bits = frame_max_bits(&cpi->rc, &cpi->oxcf);
+ const int max_bits = frame_max_bits(&cpi->rc, oxcf);
int64_t total_group_bits = gf_group_bits;
- double modified_err = 0.0;
- double err_fraction;
int mid_boost_bits = 0;
int ext_arf_boost[MAX_EXT_ARFS];
@@ -2403,18 +2718,23 @@
}
}
+ int normal_frames = (rc->baseline_gf_interval - rc->source_alt_ref_pending);
+ int normal_frame_bits;
+ int last_frame_reduction = 0;
+ if (normal_frames > 1)
+ normal_frame_bits = (int)(total_group_bits / normal_frames);
+ else
+ normal_frame_bits = (int)total_group_bits;
+
// Allocate bits to the other frames in the group.
- for (i = 0; i < rc->baseline_gf_interval - rc->source_alt_ref_pending; ++i) {
+ for (i = 0; i < normal_frames; ++i) {
if (EOF == input_stats(twopass, &frame_stats)) break;
- modified_err = calculate_modified_err(cpi, twopass, oxcf, &frame_stats);
-
- if (group_error > 0)
- err_fraction = modified_err / DOUBLE_DIVIDE_CHECK(group_error);
- else
- err_fraction = 0.0;
-
- target_frame_size = (int)((double)total_group_bits * err_fraction);
+ target_frame_size = normal_frame_bits;
+ if ((i == (normal_frames - 1)) && (i >= 1)) {
+ last_frame_reduction = normal_frame_bits / 16;
+ target_frame_size -= last_frame_reduction;
+ }
if (rc->source_alt_ref_pending && cpi->multi_arf_enabled) {
mid_boost_bits += (target_frame_size >> 4);
@@ -2479,6 +2799,20 @@
cpi->multi_arf_last_grp_enabled = cpi->multi_arf_enabled;
}
+// Adjusts the ARNF filter for a GF group.
+static void adjust_group_arnr_filter(AV1_COMP *cpi, double section_noise,
+ double section_inter,
+ double section_motion) {
+ TWO_PASS *const twopass = &cpi->twopass;
+ double section_zeromv = section_inter - section_motion;
+
+ twopass->arnr_strength_adjustment = 0;
+
+ if ((section_zeromv < 0.10) || (section_noise <= (SECTION_NOISE_DEF * 0.75)))
+ twopass->arnr_strength_adjustment -= 1;
+ if (section_zeromv > 0.50) twopass->arnr_strength_adjustment += 1;
+}
+
// Analyse and define a gf/arf group.
static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) {
AV1_COMMON *const cm = &cpi->common;
@@ -2489,19 +2823,22 @@
const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
int i;
- double boost_score = 0.0;
- double old_boost_score = 0.0;
double gf_group_err = 0.0;
#if GROUP_ADAPTIVE_MAXQ
double gf_group_raw_error = 0.0;
#endif
+ double gf_group_noise = 0.0;
double gf_group_skip_pct = 0.0;
double gf_group_inactive_zone_rows = 0.0;
+ double gf_group_inter = 0.0;
+ double gf_group_motion = 0.0;
double gf_first_frame_err = 0.0;
double mod_frame_err = 0.0;
double mv_ratio_accumulator = 0.0;
+#if CONFIG_BGSPRITE
double decay_accumulator = 1.0;
+#endif // CONFIG_BGSPRITE
double zero_motion_accumulator = 1.0;
double loop_decay_rate = 1.00;
@@ -2511,15 +2848,14 @@
double mv_in_out_accumulator = 0.0;
double abs_mv_in_out_accumulator = 0.0;
double mv_ratio_accumulator_thresh;
+ double sr_accumulator = 0.0;
+ const double av_err = get_distribution_av_err(twopass);
unsigned int allow_alt_ref = is_altref_enabled(cpi);
- int f_boost = 0;
- int b_boost = 0;
int flash_detected;
int active_max_gf_interval;
int active_min_gf_interval;
int64_t gf_group_bits;
- double gf_group_error_left;
int gf_arf_bits;
const int is_key_frame = frame_is_intra_only(cm);
const int arf_active_or_kf = is_key_frame || rc->source_alt_ref_active;
@@ -2537,7 +2873,8 @@
av1_zero(next_frame);
// Load stats for the current frame.
- mod_frame_err = calculate_modified_err(cpi, twopass, oxcf, this_frame);
+ mod_frame_err =
+ calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
// Note the error of the frame at the start of the group. This will be
// the GF frame error if we code a normal gf.
@@ -2550,8 +2887,11 @@
#if GROUP_ADAPTIVE_MAXQ
gf_group_raw_error -= this_frame->coded_error;
#endif
+ gf_group_noise -= this_frame->frame_noise_energy;
gf_group_skip_pct -= this_frame->intra_skip_pct;
gf_group_inactive_zone_rows -= this_frame->inactive_zone_rows;
+ gf_group_inter -= this_frame->pcnt_inter;
+ gf_group_motion -= this_frame->pcnt_motion;
}
// Motion breakout threshold for loop below depends on image size.
@@ -2566,9 +2906,10 @@
int int_lbq = (int)(av1_convert_qindex_to_q(rc->last_boosted_qindex,
cpi->common.bit_depth));
- active_min_gf_interval = rc->min_gf_interval + AOMMIN(2, int_max_q / 200);
- if (active_min_gf_interval > rc->max_gf_interval)
- active_min_gf_interval = rc->max_gf_interval;
+ active_min_gf_interval =
+ rc->min_gf_interval + arf_active_or_kf + AOMMIN(2, int_max_q / 200);
+ active_min_gf_interval =
+ AOMMIN(active_min_gf_interval, rc->max_gf_interval + arf_active_or_kf);
if (cpi->multi_arf_allowed) {
active_max_gf_interval = rc->max_gf_interval;
@@ -2577,13 +2918,19 @@
// bits to spare and are better with a smaller interval and smaller boost.
// At high Q when there are few bits to spare we are better with a longer
// interval to spread the cost of the GF.
- active_max_gf_interval = 12 + AOMMIN(4, (int_lbq / 6));
+ // active_max_gf_interval = 12 + AOMMIN(4, (int_lbq / 6));
+ active_max_gf_interval = 12 + arf_active_or_kf + AOMMIN(4, (int_lbq / 6));
// We have: active_min_gf_interval <= rc->max_gf_interval
if (active_max_gf_interval < active_min_gf_interval)
active_max_gf_interval = active_min_gf_interval;
else if (active_max_gf_interval > rc->max_gf_interval)
- active_max_gf_interval = rc->max_gf_interval;
+ active_max_gf_interval = AOMMIN(active_max_gf_interval,
+ rc->max_gf_interval + arf_active_or_kf);
+ // Would the active max drop us out just before the near the next kf?
+ if ((active_max_gf_interval <= rc->frames_to_key) &&
+ (active_max_gf_interval >= (rc->frames_to_key - rc->min_gf_interval)))
+ active_max_gf_interval = rc->frames_to_key / 2;
}
}
@@ -2600,13 +2947,17 @@
++i;
// Accumulate error score of frames in this gf group.
- mod_frame_err = calculate_modified_err(cpi, twopass, oxcf, this_frame);
+ mod_frame_err =
+ calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
gf_group_err += mod_frame_err;
#if GROUP_ADAPTIVE_MAXQ
gf_group_raw_error += this_frame->coded_error;
#endif
+ gf_group_noise += this_frame->frame_noise_energy;
gf_group_skip_pct += this_frame->intra_skip_pct;
gf_group_inactive_zone_rows += this_frame->inactive_zone_rows;
+ gf_group_inter += this_frame->pcnt_inter;
+ gf_group_motion += this_frame->pcnt_motion;
if (EOF == input_stats(twopass, &next_frame)) break;
@@ -2636,7 +2987,9 @@
last_loop_decay_rate = loop_decay_rate;
loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame);
+#if CONFIG_BGSPRITE
decay_accumulator = decay_accumulator * loop_decay_rate;
+#endif // CONFIG_BGSPRITE
// Monitor for static sections.
zero_motion_accumulator = AOMMIN(
@@ -2649,55 +3002,52 @@
allow_alt_ref = 0;
break;
}
- }
- // Calculate a boost number for this frame.
- boost_score +=
- decay_accumulator *
- calc_frame_boost(cpi, &next_frame, this_frame_mv_in_out, GF_MAX_BOOST);
+ // Update the accumulator for second ref error difference.
+ // This is intended to give an indication of how much the coded error is
+ // increasing over time.
+ if (i == 1) {
+ sr_accumulator += next_frame.coded_error;
+ } else {
+ sr_accumulator += (next_frame.sr_coded_error - next_frame.coded_error);
+ }
+ }
// Break out conditions.
if (
// Break at active_max_gf_interval unless almost totally static.
- (i >= (active_max_gf_interval + arf_active_or_kf) &&
- zero_motion_accumulator < 0.995) ||
+ (i >= active_max_gf_interval && zero_motion_accumulator < 0.995) ||
(
// Don't break out with a very short interval.
- (i >= active_min_gf_interval + arf_active_or_kf) &&
+ (i >= active_min_gf_interval) &&
+ ((rc->frames_to_key - i) >= rc->min_gf_interval) &&
(!flash_detected) &&
((mv_ratio_accumulator > mv_ratio_accumulator_thresh) ||
- (abs_mv_in_out_accumulator > 3.0) ||
- (mv_in_out_accumulator < -2.0) ||
- ((boost_score - old_boost_score) < BOOST_BREAKOUT)))) {
+ (abs_mv_in_out_accumulator > ARF_ABS_ZOOM_THRESH) ||
+ (sr_accumulator > next_frame.intra_error)))) {
// If GF group interval is < 12, we force it to be 8. Otherwise,
// if it is >= 12, we keep it as is.
// NOTE: 'i' is 1 more than the GF group interval candidate that is being
// checked.
- if (i == (8 + 1) || i >= (12 + 1)) {
- boost_score = old_boost_score;
- break;
- }
+ if (i == (8 + 1) || i >= (12 + 1)) break;
}
*this_frame = next_frame;
- old_boost_score = boost_score;
}
- twopass->gf_zeromotion_pct = (int)(zero_motion_accumulator * 1000.0);
-
// Was the group length constrained by the requirement for a new KF?
rc->constrained_gf_group = (i >= rc->frames_to_key) ? 1 : 0;
const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs
: cpi->common.MBs;
- assert(num_mbs > 0);
- if (i) avg_sr_coded_error /= i;
// Should we use the alternate reference frame.
if (allow_alt_ref && (i < cpi->oxcf.lag_in_frames) &&
(i >= rc->min_gf_interval)) {
+ const int forward_frames = (rc->frames_to_key - i >= i - 1)
+ ? i - 1
+ : AOMMAX(0, rc->frames_to_key - i);
// Calculate the boost for alt ref.
- rc->gfu_boost =
- calc_arf_boost(cpi, 0, (i - 1), (i - 1), &f_boost, &b_boost);
+ rc->gfu_boost = calc_arf_boost(cpi, forward_frames, (i - 1));
rc->source_alt_ref_pending = 1;
// Test to see if multi arf is appropriate.
@@ -2707,6 +3057,8 @@
? 1
: 0;
#if CONFIG_BGSPRITE
+ if (i) avg_sr_coded_error /= i;
+
if (non_zero_pcnt_second_ref_count) {
avg_pcnt_second_ref /= non_zero_pcnt_second_ref_count;
}
@@ -2718,12 +3070,15 @@
}
#endif // CONFIG_BGSPRITE
} else {
- rc->gfu_boost = AOMMAX((int)boost_score, MIN_ARF_GF_BOOST);
+ rc->gfu_boost = calc_arf_boost(cpi, 0, (i - 1));
rc->source_alt_ref_pending = 0;
}
+ rc->gfu_boost = AOMMIN((int)rc->gfu_boost, i * 200);
+
// Set the interval until the next gf.
rc->baseline_gf_interval = i - (is_key_frame || rc->source_alt_ref_pending);
+
if (non_zero_stdev_count) avg_raw_err_stdev /= non_zero_stdev_count;
// Disable extra altrefs and backward refs for "still" gf group:
@@ -2771,30 +3126,34 @@
const int vbr_group_bits_per_frame =
(int)(gf_group_bits / rc->baseline_gf_interval);
const double group_av_err = gf_group_raw_error / rc->baseline_gf_interval;
+ const double group_av_noise = gf_group_noise / rc->baseline_gf_interval;
const double group_av_skip_pct =
gf_group_skip_pct / rc->baseline_gf_interval;
const double group_av_inactive_zone =
((gf_group_inactive_zone_rows * 2) /
(rc->baseline_gf_interval * (double)cm->mb_rows));
-
- int tmp_q;
- // rc factor is a weight factor that corrects for local rate control drift.
- double rc_factor = 1.0;
- if (rc->rate_error_estimate > 0) {
- rc_factor = AOMMAX(RC_FACTOR_MIN,
- (double)(100 - rc->rate_error_estimate) / 100.0);
- } else {
- rc_factor = AOMMIN(RC_FACTOR_MAX,
- (double)(100 - rc->rate_error_estimate) / 100.0);
- }
- tmp_q = get_twopass_worst_quality(
+ int tmp_q = get_twopass_worst_quality(
cpi, group_av_err, (group_av_skip_pct + group_av_inactive_zone),
- vbr_group_bits_per_frame, twopass->kfgroup_inter_fraction * rc_factor);
+ group_av_noise, vbr_group_bits_per_frame);
twopass->active_worst_quality =
- AOMMAX(tmp_q, twopass->active_worst_quality >> 1);
+ (tmp_q + (twopass->active_worst_quality * 3)) >> 2;
+#if ALWAYS_ADJUST_BPM
+ // Reset rolling actual and target bits counters for ARF groups.
+ twopass->rolling_arf_group_target_bits = 0;
+ twopass->rolling_arf_group_actual_bits = 0;
+#endif // ALWAYS_ADJUST_BPM
}
#endif
+ // Context Adjustment of ARNR filter strength
+ if (rc->baseline_gf_interval > 1) {
+ adjust_group_arnr_filter(cpi, (gf_group_noise / rc->baseline_gf_interval),
+ (gf_group_inter / rc->baseline_gf_interval),
+ (gf_group_motion / rc->baseline_gf_interval));
+ } else {
+ twopass->arnr_strength_adjustment = 0;
+ }
+
// Calculate the extra bits to be used for boosted frame(s)
gf_arf_bits = calculate_boost_bits(rc->baseline_gf_interval, rc->gfu_boost,
gf_group_bits);
@@ -2802,22 +3161,8 @@
// Adjust KF group bits and error remaining.
twopass->kf_group_error_left -= (int64_t)gf_group_err;
- // If this is an arf update we want to remove the score for the overlay
- // frame at the end which will usually be very cheap to code.
- // The overlay frame has already, in effect, been coded so we want to spread
- // the remaining bits among the other frames.
- // For normal GFs remove the score for the GF itself unless this is
- // also a key frame in which case it has already been accounted for.
- if (rc->source_alt_ref_pending) {
- gf_group_error_left = gf_group_err - mod_frame_err;
- } else if (is_key_frame == 0) {
- gf_group_error_left = gf_group_err - gf_first_frame_err;
- } else {
- gf_group_error_left = gf_group_err;
- }
-
// Allocate bits to each of the frames in the GF group.
- allocate_gf_group_bits(cpi, gf_group_bits, gf_group_error_left, gf_arf_bits);
+ allocate_gf_group_bits(cpi, gf_group_bits, gf_arf_bits);
// Reset the file position.
reset_fpf_position(twopass, start_pos);
@@ -2827,6 +3172,11 @@
twopass->section_intra_rating = calculate_section_intra_ratio(
start_pos, twopass->stats_in_end, rc->baseline_gf_interval);
}
+#if !ALWAYS_ADJUST_BPM
+ // Reset rolling actual and target bits counters for ARF groups.
+ twopass->rolling_arf_group_target_bits = 0;
+ twopass->rolling_arf_group_actual_bits = 0;
+#endif // !ALWAYS_ADJUST_BPM
}
// Threshold for use of the lagging second reference frame. High second ref
@@ -2854,6 +3204,9 @@
// ratio in the next frame.
#define II_IMPROVEMENT_THRESHOLD 3.5
#define KF_II_MAX 128.0
+#define II_FACTOR 12.5
+// Test for very low intra complexity which could cause false key frames
+#define V_LOW_INTRA 0.5
static int test_candidate_kf(TWO_PASS *twopass,
const FIRSTPASS_STATS *last_frame,
@@ -2893,7 +3246,7 @@
// Examine how well the key frame predicts subsequent frames.
for (i = 0; i < 16; ++i) {
- double next_iiratio = (BOOST_FACTOR * local_next_frame.intra_error /
+ double next_iiratio = (II_FACTOR * local_next_frame.intra_error /
DOUBLE_DIVIDE_CHECK(local_next_frame.coded_error));
if (next_iiratio > KF_II_MAX) next_iiratio = KF_II_MAX;
@@ -2913,7 +3266,7 @@
0.20) &&
(next_iiratio < 3.0)) ||
((boost_score - old_boost_score) < 3.0) ||
- (local_next_frame.intra_error < 200)) {
+ (local_next_frame.intra_error < V_LOW_INTRA)) {
break;
}
@@ -2951,14 +3304,15 @@
FIRSTPASS_STATS next_frame;
FIRSTPASS_STATS last_frame;
int kf_bits = 0;
- int loop_decay_counter = 0;
double decay_accumulator = 1.0;
- double av_decay_accumulator = 0.0;
double zero_motion_accumulator = 1.0;
double boost_score = 0.0;
double kf_mod_err = 0.0;
double kf_group_err = 0.0;
double recent_loop_decay[FRAMES_TO_CHECK_DECAY];
+ double sr_accumulator = 0.0;
+ double abs_mv_in_out_accumulator = 0.0;
+ const double av_err = get_distribution_av_err(twopass);
av1_zero(next_frame);
@@ -2983,7 +3337,8 @@
twopass->kf_group_bits = 0; // Total bits available to kf group
twopass->kf_group_error_left = 0; // Group modified error score.
- kf_mod_err = calculate_modified_err(cpi, twopass, oxcf, this_frame);
+ kf_mod_err =
+ calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
// Initialize the decay rates for the recent frames to check
for (j = 0; j < FRAMES_TO_CHECK_DECAY; ++j) recent_loop_decay[j] = 1.0;
@@ -2993,7 +3348,8 @@
while (twopass->stats_in < twopass->stats_in_end &&
rc->frames_to_key < cpi->oxcf.key_freq) {
// Accumulate kf group error.
- kf_group_err += calculate_modified_err(cpi, twopass, oxcf, this_frame);
+ kf_group_err +=
+ calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
// Load the next frame's stats.
last_frame = *this_frame;
@@ -3053,7 +3409,8 @@
// Rescan to get the correct error data for the forced kf group.
for (i = 0; i < rc->frames_to_key; ++i) {
- kf_group_err += calculate_modified_err(cpi, twopass, oxcf, &tmp_frame);
+ kf_group_err +=
+ calculate_norm_frame_score(cpi, twopass, oxcf, &tmp_frame, av_err);
input_stats(twopass, &tmp_frame);
}
rc->next_key_frame_forced = 1;
@@ -3067,11 +3424,12 @@
// Special case for the last key frame of the file.
if (twopass->stats_in >= twopass->stats_in_end) {
// Accumulate kf group error.
- kf_group_err += calculate_modified_err(cpi, twopass, oxcf, this_frame);
+ kf_group_err +=
+ calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
}
// Calculate the number of bits that should be assigned to the kf group.
- if (twopass->bits_left > 0 && twopass->modified_error_left > 0.0) {
+ if (twopass->bits_left > 0 && twopass->normalized_score_left > 0.0) {
// Maximum number of bits for a single normal frame (not key frame).
const int max_bits = frame_max_bits(rc, &cpi->oxcf);
@@ -3081,7 +3439,7 @@
// Default allocation based on bits left and relative
// complexity of the section.
twopass->kf_group_bits = (int64_t)(
- twopass->bits_left * (kf_group_err / twopass->modified_error_left));
+ twopass->bits_left * (kf_group_err / twopass->normalized_score_left));
// Clip based on maximum per frame rate defined by the user.
max_grp_bits = (int64_t)max_bits * (int64_t)rc->frames_to_key;
@@ -3097,35 +3455,43 @@
// Scan through the kf group collating various stats used to determine
// how many bits to spend on it.
- decay_accumulator = 1.0;
boost_score = 0.0;
+
for (i = 0; i < (rc->frames_to_key - 1); ++i) {
if (EOF == input_stats(twopass, &next_frame)) break;
- // Monitor for static sections.
- zero_motion_accumulator = AOMMIN(zero_motion_accumulator,
- get_zero_motion_factor(cpi, &next_frame));
+ if (i <= KF_BOOST_SCAN_MAX_FRAMES) {
+ double frame_boost;
+ double zm_factor;
- // Not all frames in the group are necessarily used in calculating boost.
- if ((i <= rc->max_gf_interval) ||
- ((i <= (rc->max_gf_interval * 4)) && (decay_accumulator > 0.5))) {
- const double frame_boost =
- calc_frame_boost(cpi, this_frame, 0, KF_MAX_BOOST);
+ // Monitor for static sections.
+ zero_motion_accumulator = AOMMIN(
+ zero_motion_accumulator, get_zero_motion_factor(cpi, &next_frame));
- // How fast is prediction quality decaying.
- if (!detect_flash(twopass, 0)) {
- const double loop_decay_rate =
- get_prediction_decay_rate(cpi, &next_frame);
- decay_accumulator *= loop_decay_rate;
- decay_accumulator = AOMMAX(decay_accumulator, MIN_DECAY_FACTOR);
- av_decay_accumulator += decay_accumulator;
- ++loop_decay_counter;
- }
- boost_score += (decay_accumulator * frame_boost);
+ // Factor 0.75-1.25 based on how much of frame is static.
+ zm_factor = (0.75 + (zero_motion_accumulator / 2.0));
+
+ // The second (lagging) ref error is not valid immediately after
+ // a key frame because either the lag has not built up (in the
+ // case of the first key frame or it points to a refernce before
+ // the new key frame.
+ if (i < 2) sr_accumulator = 0.0;
+ frame_boost = calc_kf_frame_boost(cpi, &next_frame, &sr_accumulator, 0,
+ KF_MAX_FRAME_BOOST * zm_factor);
+
+ boost_score += frame_boost;
+
+ // Measure of zoom. Large zoom tends to indicate reduced boost.
+ abs_mv_in_out_accumulator +=
+ fabs(next_frame.mv_in_out_count * next_frame.pcnt_motion);
+
+ if ((frame_boost < 25.00) ||
+ (abs_mv_in_out_accumulator > KF_ABS_ZOOM_THRESH))
+ break;
+ } else {
+ break;
}
}
- if (loop_decay_counter > 0)
- av_decay_accumulator /= (double)loop_decay_counter;
reset_fpf_position(twopass, start_position);
@@ -3137,24 +3503,13 @@
start_position, twopass->stats_in_end, rc->frames_to_key);
// Apply various clamps for min and max boost
- rc->kf_boost = (int)(av_decay_accumulator * boost_score);
- rc->kf_boost = AOMMAX(rc->kf_boost, (rc->frames_to_key * 3));
- rc->kf_boost = AOMMAX(rc->kf_boost, MIN_KF_BOOST);
+ rc->kf_boost = AOMMAX((int)boost_score, (rc->frames_to_key * 3));
+ rc->kf_boost = AOMMAX(rc->kf_boost, MIN_KF_TOT_BOOST);
+ rc->kf_boost = AOMMIN(rc->kf_boost, MAX_KF_TOT_BOOST);
// Work out how many bits to allocate for the key frame itself.
kf_bits = calculate_boost_bits((rc->frames_to_key - 1), rc->kf_boost,
twopass->kf_group_bits);
-
- // Work out the fraction of the kf group bits reserved for the inter frames
- // within the group after discounting the bits for the kf itself.
- if (twopass->kf_group_bits) {
- twopass->kfgroup_inter_fraction =
- (double)(twopass->kf_group_bits - kf_bits) /
- (double)twopass->kf_group_bits;
- } else {
- twopass->kfgroup_inter_fraction = 1.0;
- }
-
twopass->kf_group_bits -= kf_bits;
// Save the bits to spend on the key frame.
@@ -3163,12 +3518,12 @@
gf_group->rf_level[0] = KF_STD;
// Note the total error score of the kf group minus the key frame itself.
- twopass->kf_group_error_left = (int)(kf_group_err - kf_mod_err);
+ twopass->kf_group_error_left = (kf_group_err - kf_mod_err);
// Adjust the count of total modified error left.
// The count of bits left is adjusted elsewhere based on real coded frame
// sizes.
- twopass->modified_error_left -= kf_group_err;
+ twopass->normalized_score_left -= kf_group_err;
}
#if USE_GF16_MULTI_LAYER
@@ -3507,9 +3862,11 @@
const double section_inactive_zone =
(twopass->total_left_stats.inactive_zone_rows * 2) /
((double)cm->mb_rows * section_length);
+ const double section_noise =
+ twopass->total_left_stats.frame_noise_energy / section_length;
const int tmp_q = get_twopass_worst_quality(
cpi, section_error, section_intra_skip + section_inactive_zone,
- section_target_bandwidth, DEFAULT_GRP_WEIGHT);
+ section_noise, section_target_bandwidth);
twopass->active_worst_quality = tmp_q;
twopass->baseline_active_worst_quality = tmp_q;
@@ -3608,6 +3965,10 @@
rc->vbr_bits_off_target += rc->base_frame_target - rc->projected_frame_size;
twopass->bits_left = AOMMAX(twopass->bits_left - bits_used, 0);
+ // Target vs actual bits for this arf group.
+ twopass->rolling_arf_group_target_bits += rc->this_frame_target;
+ twopass->rolling_arf_group_actual_bits += rc->projected_frame_size;
+
// Calculate the pct rc error.
if (rc->total_actual_bits) {
rc->rate_error_estimate =
@@ -3627,9 +3988,7 @@
++twopass->gf_group.index;
// If the rate control is drifting consider adjustment to min or maxq.
- if ((cpi->oxcf.rc_mode != AOM_Q) &&
- (cpi->twopass.gf_zeromotion_pct < VLOW_MOTION_THRESHOLD) &&
- !cpi->rc.is_src_frame_alt_ref) {
+ if ((cpi->oxcf.rc_mode != AOM_Q) && !cpi->rc.is_src_frame_alt_ref) {
const int maxq_adj_limit =
rc->worst_quality - twopass->active_worst_quality;
const int minq_adj_limit =
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index ee21b65..892eae5 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -72,11 +72,15 @@
double intra_error;
double coded_error;
double sr_coded_error;
+ double frame_noise_energy;
double pcnt_inter;
double pcnt_motion;
double pcnt_second_ref;
double pcnt_neutral;
+ double pcnt_intra_low; // Coded intra but low variance
+ double pcnt_intra_high; // Coded intra high variance
double intra_skip_pct;
+ double intra_smooth_pct; // % of blocks that are smooth
double inactive_zone_rows; // Image mask rows top and bottom.
double inactive_zone_cols; // Image mask columns at left and right edges.
double MVr;
@@ -139,10 +143,10 @@
FIRSTPASS_STATS total_left_stats;
int first_pass_done;
int64_t bits_left;
- double modified_error_min;
- double modified_error_max;
- double modified_error_left;
+ double normalized_score_left;
+ double mean_mod_score;
double mb_av_energy;
+ double mb_smooth_pct;
#if CONFIG_FP_MB_STATS
uint8_t *frame_mb_stats_buf;
@@ -156,21 +160,25 @@
int64_t kf_group_bits;
// Error score of frames still to be coded in kf group
- int64_t kf_group_error_left;
+ double kf_group_error_left;
// The fraction for a kf groups total bits allocated to the inter frames
double kfgroup_inter_fraction;
+ double bpm_factor;
+ int rolling_arf_group_target_bits;
+ int rolling_arf_group_actual_bits;
+
int sr_update_lag;
int kf_zeromotion_pct;
int last_kfgroup_zeromotion_pct;
- int gf_zeromotion_pct;
int active_worst_quality;
int baseline_active_worst_quality;
int extend_minq;
int extend_maxq;
int extend_minq_fast;
+ int arnr_strength_adjustment;
GF_GROUP gf_group;
} TWO_PASS;
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 523ffa1..86e371b 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -121,7 +121,7 @@
kf_high_m[i] = get_minq_index(maxq, 0.0000021, -0.00125, 0.55, bit_depth);
arfgf_low[i] = get_minq_index(maxq, 0.0000015, -0.0009, 0.30, bit_depth);
arfgf_high[i] = get_minq_index(maxq, 0.0000021, -0.00125, 0.55, bit_depth);
- inter[i] = get_minq_index(maxq, 0.00000271, -0.00113, 0.90, bit_depth);
+ inter[i] = get_minq_index(maxq, 0.00000271, -0.00113, 0.70, bit_depth);
rtc[i] = get_minq_index(maxq, 0.00000271, -0.00113, 0.70, bit_depth);
}
}
@@ -178,17 +178,19 @@
int av1_rc_clamp_pframe_target_size(const AV1_COMP *const cpi, int target) {
const RATE_CONTROL *rc = &cpi->rc;
const AV1EncoderConfig *oxcf = &cpi->oxcf;
- const int min_frame_target =
- AOMMAX(rc->min_frame_bandwidth, rc->avg_frame_bandwidth >> 5);
- // Clip the frame target to the minimum setup value.
- if (cpi->rc.is_src_frame_alt_ref) {
- // If there is an active ARF at this location use the minimum
- // bits on this frame even if it is a constructed arf.
- // The active maximum quantizer insures that an appropriate
- // number of bits will be spent if needed for constructed ARFs.
- target = min_frame_target;
- } else if (target < min_frame_target) {
- target = min_frame_target;
+
+ if (cpi->oxcf.pass != 2) {
+ const int min_frame_target =
+ AOMMAX(rc->min_frame_bandwidth, rc->avg_frame_bandwidth >> 5);
+ if (target < min_frame_target) target = min_frame_target;
+ if (cpi->refresh_golden_frame && rc->is_src_frame_alt_ref) {
+ // If there is an active ARF at this location use the minimum
+ // bits on this frame even if it is a constructed arf.
+ // The active maximum quantizer insures that an appropriate
+ // number of bits will be spent if needed for
+ // constructed ARFs.
+ target = min_frame_target;
+ }
}
// Clip the frame target to the maximum allowed value.
@@ -450,6 +452,11 @@
else
cpi->rc.rc_1_frame = 0;
+ if (cpi->rc.rc_1_frame == -1 && cpi->rc.rc_2_frame == 1 &&
+ correction_factor > 1000) {
+ cpi->rc.rc_2_frame = 0;
+ }
+
if (correction_factor > 102) {
// We are not already at the worst allowable quality
correction_factor =
@@ -1028,8 +1035,7 @@
// Extension to max or min Q if undershoot or overshoot is outside
// the permitted range.
- if ((cpi->oxcf.rc_mode != AOM_Q) &&
- (cpi->twopass.gf_zeromotion_pct < VLOW_MOTION_THRESHOLD)) {
+ if (cpi->oxcf.rc_mode != AOM_Q) {
if (frame_is_intra_only(cm) ||
(!rc->is_src_frame_alt_ref &&
(cpi->refresh_golden_frame || cpi->refresh_alt2_ref_frame ||
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c
index 987f34c..3e2e558 100644
--- a/av1/encoder/temporal_filter.c
+++ b/av1/encoder/temporal_filter.c
@@ -538,7 +538,16 @@
av1_lookahead_depth(cpi->lookahead) - distance - 1;
int frames_fwd = (cpi->oxcf.arnr_max_frames - 1) >> 1;
int frames_bwd;
- int q, frames, strength;
+ int q, frames, base_strength, strength;
+
+ // Context dependent two pass adjustment to strength.
+ if (oxcf->pass == 2) {
+ base_strength = oxcf->arnr_strength + cpi->twopass.arnr_strength_adjustment;
+ // Clip to allowed range.
+ base_strength = AOMMIN(6, AOMMAX(0, base_strength));
+ } else {
+ base_strength = oxcf->arnr_strength;
+ }
// Define the forward and backwards filter limits for this arnr group.
if (frames_fwd > frames_after_arf) frames_fwd = frames_after_arf;
@@ -560,10 +569,11 @@
else
q = ((int)av1_convert_qindex_to_q(cpi->rc.avg_frame_qindex[KEY_FRAME],
cpi->common.bit_depth));
+
if (q > 16) {
- strength = oxcf->arnr_strength;
+ strength = base_strength;
} else {
- strength = oxcf->arnr_strength - ((16 - q) / 2);
+ strength = base_strength - ((16 - q) / 2);
if (strength < 0) strength = 0;
}