Commit da01c0dc authored by Debargha Mukherjee's avatar Debargha Mukherjee

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
parent f8daa92d
......@@ -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 @@ static void zero_stats(FIRSTPASS_STATS *section) {
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 @@ static void accumulate_stats(FIRSTPASS_STATS *section,
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 @@ static void subtract_stats(FIRSTPASS_STATS *section,
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,31 +256,61 @@ static double calculate_active_area(const AV1_COMP *cpi,
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);
// 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 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_error *=
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.
......@@ -478,6 +526,170 @@ static double raw_motion_error_stdev(int *raw_motion_err_list,
return raw_err_stdev;
}
#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) {
......@@ -497,6 +709,7 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
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 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
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 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
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 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
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 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
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 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
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 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
}
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 @@ static double calc_correction_factor(double err_per_mb, double err_divisor,
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 @@ void av1_init_second_pass(AV1_COMP *cpi) {
*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 @@ void av1_init_second_pass(AV1_COMP *cpi) {
// This variable monitors how far behind the second ref update is lagging.
twopass->sr_update_lag = 1;