Commit 21ff7bdc authored by Paul Wilkins's avatar Paul Wilkins
Browse files

Adjustments to key frame sizing.

Adjustments take heavier account of the frame near a kf
in deciding boost and limit the total number that can contribute.
Also adjusted the minq calculations such that in most cases we
generate a smaller key frame.
Modified the code that accounts for how static the sequence is and
added some adjustment based on image size. This is still very
crude but smaller images tend to behave better with a larger
delta between KF Q and other frames than larger image formats.
Changes give sizable gains in overall PSNR  on all the test sets but the
biggest gains (~3%) were on the std-hd set.
The gains were smaller for SSIM but still significant.
Average PSNR results are mixed because this metric can very easily
be altered by having a very good / lossless coding of one or two frames.
Some of the YT and YT-HD clips in particular have blank lead ins and
allowing lossless coding of these appears to make a big difference to
average PSNR but it reality does not help much at all.

Change-Id: I6bfe485a1d330b47c783832f1717c95c535464ec
Showing with 67 additions and 59 deletions
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#define IIFACTOR 12.5 #define IIFACTOR 12.5
#define IIKFACTOR1 12.5 #define IIKFACTOR1 12.5
#define IIKFACTOR2 15.0 #define IIKFACTOR2 15.0
#define RMAX 128.0 #define RMAX 512.0
#define GF_RMAX 96.0 #define GF_RMAX 96.0
#define ERR_DIVISOR 150.0 #define ERR_DIVISOR 150.0
#define MIN_DECAY_FACTOR 0.1 #define MIN_DECAY_FACTOR 0.1
...@@ -2350,7 +2350,6 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { ...@@ -2350,7 +2350,6 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
double decay_accumulator = 1.0; double decay_accumulator = 1.0;
double zero_motion_accumulator = 1.0; double zero_motion_accumulator = 1.0;
double boost_score = 0; double boost_score = 0;
double old_boost_score = 0.0;
double loop_decay_rate; double loop_decay_rate;
double kf_mod_err = 0.0; double kf_mod_err = 0.0;
...@@ -2522,22 +2521,13 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { ...@@ -2522,22 +2521,13 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
boost_score = 0.0; boost_score = 0.0;
loop_decay_rate = 1.00; // Starting decay rate loop_decay_rate = 1.00; // Starting decay rate
// Scan through the kf group collating various stats.
for (i = 0; i < cpi->twopass.frames_to_key; i++) { for (i = 0; i < cpi->twopass.frames_to_key; i++) {
double r; double r;
if (EOF == input_stats(cpi, &next_frame)) if (EOF == input_stats(cpi, &next_frame))
break; break;
if (next_frame.intra_error > cpi->twopass.kf_intra_err_min)
r = (IIKFACTOR2 * next_frame.intra_error /
DOUBLE_DIVIDE_CHECK(next_frame.coded_error));
else
r = (IIKFACTOR2 * cpi->twopass.kf_intra_err_min /
DOUBLE_DIVIDE_CHECK(next_frame.coded_error));
if (r > RMAX)
r = RMAX;
// Monitor for static sections. // Monitor for static sections.
if ((next_frame.pcnt_inter - next_frame.pcnt_motion) < if ((next_frame.pcnt_inter - next_frame.pcnt_motion) <
zero_motion_accumulator) { zero_motion_accumulator) {
...@@ -2545,22 +2535,28 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { ...@@ -2545,22 +2535,28 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
(next_frame.pcnt_inter - next_frame.pcnt_motion); (next_frame.pcnt_inter - next_frame.pcnt_motion);
} }
// How fast is prediction quality decaying // For the first few frames collect data to decide kf boost.
if (!detect_flash(cpi, 0)) { if (i <= (cpi->max_gf_interval * 2)) {
loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame); if (next_frame.intra_error > cpi->twopass.kf_intra_err_min)
decay_accumulator = decay_accumulator * loop_decay_rate; r = (IIKFACTOR2 * next_frame.intra_error /
decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR DOUBLE_DIVIDE_CHECK(next_frame.coded_error));
? MIN_DECAY_FACTOR : decay_accumulator; else
} r = (IIKFACTOR2 * cpi->twopass.kf_intra_err_min /
DOUBLE_DIVIDE_CHECK(next_frame.coded_error));
boost_score += (decay_accumulator * r); if (r > RMAX)
r = RMAX;
if ((i > MIN_GF_INTERVAL) && // How fast is prediction quality decaying
((boost_score - old_boost_score) < 6.25)) { if (!detect_flash(cpi, 0)) {
break; loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame);
} decay_accumulator = decay_accumulator * loop_decay_rate;
decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR
? MIN_DECAY_FACTOR : decay_accumulator;
}
old_boost_score = boost_score; boost_score += (decay_accumulator * r);
}
} }
{ {
...@@ -2590,8 +2586,8 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) { ...@@ -2590,8 +2586,8 @@ static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
int allocation_chunks; int allocation_chunks;
int alt_kf_bits; int alt_kf_bits;
if (kf_boost < (cpi->twopass.frames_to_key * 5)) if (kf_boost < (cpi->twopass.frames_to_key * 3))
kf_boost = (cpi->twopass.frames_to_key * 5); kf_boost = (cpi->twopass.frames_to_key * 3);
if (kf_boost < 300) // Min KF boost if (kf_boost < 300) // Min KF boost
kf_boost = 300; kf_boost = 300;
......
...@@ -177,15 +177,16 @@ static void init_minq_luts(void) { ...@@ -177,15 +177,16 @@ static void init_minq_luts(void) {
kf_low_motion_minq[i] = calculate_minq_index(maxq, kf_low_motion_minq[i] = calculate_minq_index(maxq,
0.0000003, 0.000001,
-0.000015, -0.0004,
0.074, 0.15,
0.0); 0.0);
kf_high_motion_minq[i] = calculate_minq_index(maxq, kf_high_motion_minq[i] = calculate_minq_index(maxq,
0.0000004, 0.000002,
-0.000125, -0.0012,
0.14, 0.5,
0.0); 0.0);
gf_low_motion_minq[i] = calculate_minq_index(maxq, gf_low_motion_minq[i] = calculate_minq_index(maxq,
0.0000015, 0.0000015,
-0.0009, -0.0009,
...@@ -2757,31 +2758,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2757,31 +2758,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
q = cpi->active_worst_quality; q = cpi->active_worst_quality;
if (cm->frame_type == KEY_FRAME) { if (cm->frame_type == KEY_FRAME) {
#if CONFIG_MULTIPLE_ARF #if !CONFIG_MULTIPLE_ARF
double current_q;
#endif
int high = 2000;
int low = 400;
if (cpi->kf_boost > high) {
cpi->active_best_quality = kf_low_motion_minq[q];
} else if (cpi->kf_boost < low) {
cpi->active_best_quality = kf_high_motion_minq[q];
} else {
const int gap = high - low;
const int offset = high - cpi->kf_boost;
const int qdiff = kf_high_motion_minq[q] - kf_low_motion_minq[q];
const int adjustment = ((offset * qdiff) + (gap >> 1)) / gap;
cpi->active_best_quality = kf_low_motion_minq[q] + adjustment;
}
// Make an adjustment based on the % static
// The main impact of this is at lower Q to prevent overly large key
// frames unless a lot of the image is static.
if (cpi->kf_zeromotion_pct < 64)
cpi->active_best_quality += 4 - (cpi->kf_zeromotion_pct >> 4);
// Special case for key frames forced because we have reached // Special case for key frames forced because we have reached
// the maximum key frame interval. Here force the Q to a range // the maximum key frame interval. Here force the Q to a range
// based on the ambient Q to reduce the risk of popping // based on the ambient Q to reduce the risk of popping
...@@ -2794,8 +2771,43 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2794,8 +2771,43 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
(last_boosted_q * 0.75)); (last_boosted_q * 0.75));
cpi->active_best_quality = MAX(qindex + delta_qindex, cpi->best_quality); cpi->active_best_quality = MAX(qindex + delta_qindex, cpi->best_quality);
} else {
int high = 5000;
int low = 400;
double q_adj_factor = 1.0;
double q_val;
// Baseline value derived from cpi->active_worst_quality and kf boost
if (cpi->kf_boost > high) {
cpi->active_best_quality = kf_low_motion_minq[q];
} else if (cpi->kf_boost < low) {
cpi->active_best_quality = kf_high_motion_minq[q];
} else {
const int gap = high - low;
const int offset = high - cpi->kf_boost;
const int qdiff = kf_high_motion_minq[q] - kf_low_motion_minq[q];
const int adjustment = ((offset * qdiff) + (gap >> 1)) / gap;
cpi->active_best_quality = kf_low_motion_minq[q] + adjustment;
}
// Allow somewhat lower kf minq with small image formats.
if ((cm->width * cm->height) <= (352 * 288)) {
q_adj_factor -= 0.25;
}
// Make a further adjustment based on the kf zero motion measure.
q_adj_factor += 0.05 - (0.001 * (double)cpi->kf_zeromotion_pct);
// Convert the adjustment factor to a qindex delta on active_best_quality.
q_val = vp9_convert_qindex_to_q(cpi->active_best_quality);
cpi->active_best_quality +=
compute_qdelta(cpi, q_val, (q_val * q_adj_factor));
} }
#if CONFIG_MULTIPLE_ARF #else
double current_q;
// Force the KF quantizer to be 30% of the active_worst_quality. // Force the KF quantizer to be 30% of the active_worst_quality.
current_q = vp9_convert_qindex_to_q(cpi->active_worst_quality); current_q = vp9_convert_qindex_to_q(cpi->active_worst_quality);
cpi->active_best_quality = cpi->active_worst_quality cpi->active_best_quality = cpi->active_worst_quality
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment