Merge "Step towards making the 2-pass cq mode perceptual"
This commit is contained in:
@@ -115,7 +115,7 @@ static void output_stats(FIRSTPASS_STATS *stats,
|
|||||||
|
|
||||||
fprintf(fpfile, "%12.0lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf %12.4lf"
|
fprintf(fpfile, "%12.0lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf %12.4lf"
|
||||||
"%12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf"
|
"%12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf"
|
||||||
"%12.4lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf\n",
|
"%12.4lf %12.4lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf\n",
|
||||||
stats->frame,
|
stats->frame,
|
||||||
stats->weight,
|
stats->weight,
|
||||||
stats->intra_error,
|
stats->intra_error,
|
||||||
@@ -126,6 +126,7 @@ static void output_stats(FIRSTPASS_STATS *stats,
|
|||||||
stats->pcnt_second_ref,
|
stats->pcnt_second_ref,
|
||||||
stats->pcnt_neutral,
|
stats->pcnt_neutral,
|
||||||
stats->intra_skip_pct,
|
stats->intra_skip_pct,
|
||||||
|
stats->intra_smooth_pct,
|
||||||
stats->inactive_zone_rows,
|
stats->inactive_zone_rows,
|
||||||
stats->inactive_zone_cols,
|
stats->inactive_zone_cols,
|
||||||
stats->MVr,
|
stats->MVr,
|
||||||
@@ -165,6 +166,7 @@ static void zero_stats(FIRSTPASS_STATS *section) {
|
|||||||
section->pcnt_second_ref = 0.0;
|
section->pcnt_second_ref = 0.0;
|
||||||
section->pcnt_neutral = 0.0;
|
section->pcnt_neutral = 0.0;
|
||||||
section->intra_skip_pct = 0.0;
|
section->intra_skip_pct = 0.0;
|
||||||
|
section->intra_smooth_pct = 0.0;
|
||||||
section->inactive_zone_rows = 0.0;
|
section->inactive_zone_rows = 0.0;
|
||||||
section->inactive_zone_cols = 0.0;
|
section->inactive_zone_cols = 0.0;
|
||||||
section->MVr = 0.0;
|
section->MVr = 0.0;
|
||||||
@@ -193,6 +195,7 @@ static void accumulate_stats(FIRSTPASS_STATS *section,
|
|||||||
section->pcnt_second_ref += frame->pcnt_second_ref;
|
section->pcnt_second_ref += frame->pcnt_second_ref;
|
||||||
section->pcnt_neutral += frame->pcnt_neutral;
|
section->pcnt_neutral += frame->pcnt_neutral;
|
||||||
section->intra_skip_pct += frame->intra_skip_pct;
|
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_rows += frame->inactive_zone_rows;
|
||||||
section->inactive_zone_cols += frame->inactive_zone_cols;
|
section->inactive_zone_cols += frame->inactive_zone_cols;
|
||||||
section->MVr += frame->MVr;
|
section->MVr += frame->MVr;
|
||||||
@@ -219,6 +222,7 @@ static void subtract_stats(FIRSTPASS_STATS *section,
|
|||||||
section->pcnt_second_ref -= frame->pcnt_second_ref;
|
section->pcnt_second_ref -= frame->pcnt_second_ref;
|
||||||
section->pcnt_neutral -= frame->pcnt_neutral;
|
section->pcnt_neutral -= frame->pcnt_neutral;
|
||||||
section->intra_skip_pct -= frame->intra_skip_pct;
|
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_rows -= frame->inactive_zone_rows;
|
||||||
section->inactive_zone_cols -= frame->inactive_zone_cols;
|
section->inactive_zone_cols -= frame->inactive_zone_cols;
|
||||||
section->MVr -= frame->MVr;
|
section->MVr -= frame->MVr;
|
||||||
@@ -493,12 +497,12 @@ static void set_first_pass_params(VP9_COMP *cpi) {
|
|||||||
// This threshold is used to track blocks where to all intents and purposes
|
// This threshold is used to track blocks where to all intents and purposes
|
||||||
// the intra prediction error 0. Though the metric we test against
|
// the intra prediction error 0. Though the metric we test against
|
||||||
// is technically a sse we are mainly interested in blocks where all the pixels
|
// is technically a sse we are mainly interested in blocks where all the pixels
|
||||||
// int he 8 bit domain have an error of <= 1 (where error = sse) so a
|
// in the 8 bit domain have an error of <= 1 (where error = sse) so a
|
||||||
// linear scaling for 10 and 12 bit gives similar results.
|
// linear scaling for 10 and 12 bit gives similar results.
|
||||||
#define UL_INTRA_THRESH 50
|
#define UL_INTRA_THRESH 50
|
||||||
#if CONFIG_VP9_HIGHBITDEPTH
|
|
||||||
static int get_ul_intra_threshold(VP9_COMMON *cm) {
|
static int get_ul_intra_threshold(VP9_COMMON *cm) {
|
||||||
int ret_val = UL_INTRA_THRESH;
|
int ret_val = UL_INTRA_THRESH;
|
||||||
|
#if CONFIG_VP9_HIGHBITDEPTH
|
||||||
if (cm->use_highbitdepth) {
|
if (cm->use_highbitdepth) {
|
||||||
switch (cm->bit_depth) {
|
switch (cm->bit_depth) {
|
||||||
case VPX_BITS_8:
|
case VPX_BITS_8:
|
||||||
@@ -515,9 +519,37 @@ static int get_ul_intra_threshold(VP9_COMMON *cm) {
|
|||||||
"VPX_BITS_10 or VPX_BITS_12");
|
"VPX_BITS_10 or VPX_BITS_12");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
(void) cm;
|
||||||
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SMOOTH_INTRA_THRESH 4000
|
||||||
|
static int get_smooth_intra_threshold(VP9_COMMON *cm) {
|
||||||
|
int ret_val = SMOOTH_INTRA_THRESH;
|
||||||
|
#if CONFIG_VP9_HIGHBITDEPTH
|
||||||
|
if (cm->use_highbitdepth) {
|
||||||
|
switch (cm->bit_depth) {
|
||||||
|
case VPX_BITS_8:
|
||||||
|
ret_val = SMOOTH_INTRA_THRESH;
|
||||||
|
break;
|
||||||
|
case VPX_BITS_10:
|
||||||
|
ret_val = SMOOTH_INTRA_THRESH >> 2;
|
||||||
|
break;
|
||||||
|
case VPX_BITS_12:
|
||||||
|
ret_val = SMOOTH_INTRA_THRESH >> 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0 && "cm->bit_depth should be VPX_BITS_8, "
|
||||||
|
"VPX_BITS_10 or VPX_BITS_12");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void) cm;
|
||||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
#define INVALID_ROW -1
|
#define INVALID_ROW -1
|
||||||
void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) {
|
void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) {
|
||||||
@@ -545,6 +577,7 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) {
|
|||||||
const int intrapenalty = INTRA_MODE_PENALTY;
|
const int intrapenalty = INTRA_MODE_PENALTY;
|
||||||
double neutral_count;
|
double neutral_count;
|
||||||
int intra_skip_count = 0;
|
int intra_skip_count = 0;
|
||||||
|
int intra_smooth_count = 0;
|
||||||
int image_data_start_row = INVALID_ROW;
|
int image_data_start_row = INVALID_ROW;
|
||||||
int new_mv_count = 0;
|
int new_mv_count = 0;
|
||||||
int sum_in_vectors = 0;
|
int sum_in_vectors = 0;
|
||||||
@@ -716,15 +749,14 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) {
|
|||||||
// domain). In natural videos this is uncommon, but it is much more
|
// domain). In natural videos this is uncommon, but it is much more
|
||||||
// common in animations, graphics and screen content, so may be used
|
// common in animations, graphics and screen content, so may be used
|
||||||
// as a signal to detect these types of content.
|
// as a signal to detect these types of content.
|
||||||
#if CONFIG_VP9_HIGHBITDEPTH
|
|
||||||
if (this_error < get_ul_intra_threshold(cm)) {
|
if (this_error < get_ul_intra_threshold(cm)) {
|
||||||
#else
|
|
||||||
if (this_error < UL_INTRA_THRESH) {
|
|
||||||
#endif
|
|
||||||
++intra_skip_count;
|
++intra_skip_count;
|
||||||
} else if ((mb_col > 0) && (image_data_start_row == INVALID_ROW)) {
|
} else if ((mb_col > 0) && (image_data_start_row == INVALID_ROW)) {
|
||||||
image_data_start_row = mb_row;
|
image_data_start_row = mb_row;
|
||||||
}
|
}
|
||||||
|
if (this_error < get_smooth_intra_threshold(cm)) {
|
||||||
|
++intra_smooth_count;
|
||||||
|
}
|
||||||
|
|
||||||
#if CONFIG_VP9_HIGHBITDEPTH
|
#if CONFIG_VP9_HIGHBITDEPTH
|
||||||
if (cm->use_highbitdepth) {
|
if (cm->use_highbitdepth) {
|
||||||
@@ -1090,6 +1122,7 @@ void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) {
|
|||||||
fps.pcnt_second_ref = (double)second_ref_count / num_mbs;
|
fps.pcnt_second_ref = (double)second_ref_count / num_mbs;
|
||||||
fps.pcnt_neutral = (double)neutral_count / num_mbs;
|
fps.pcnt_neutral = (double)neutral_count / num_mbs;
|
||||||
fps.intra_skip_pct = (double)intra_skip_count / 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_rows = (double)image_data_start_row;
|
||||||
fps.inactive_zone_cols = (double)0; // TODO(paulwilkins): fix
|
fps.inactive_zone_cols = (double)0; // TODO(paulwilkins): fix
|
||||||
|
|
||||||
@@ -2800,6 +2833,7 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
|
|||||||
// applied when combining MB error values for the frame.
|
// applied when combining MB error values for the frame.
|
||||||
twopass->mb_av_energy =
|
twopass->mb_av_energy =
|
||||||
log(((this_frame.intra_error * 256.0) / num_mbs) + 1.0);
|
log(((this_frame.intra_error * 256.0) / num_mbs) + 1.0);
|
||||||
|
twopass->mb_smooth_pct = this_frame.intra_smooth_pct;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the total stats remaining structure.
|
// Update the total stats remaining structure.
|
||||||
|
@@ -52,6 +52,7 @@ typedef struct {
|
|||||||
double pcnt_second_ref;
|
double pcnt_second_ref;
|
||||||
double pcnt_neutral;
|
double pcnt_neutral;
|
||||||
double intra_skip_pct;
|
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_rows; // Image mask rows top and bottom.
|
||||||
double inactive_zone_cols; // Image mask columns at left and right edges.
|
double inactive_zone_cols; // Image mask columns at left and right edges.
|
||||||
double MVr;
|
double MVr;
|
||||||
@@ -107,6 +108,7 @@ typedef struct {
|
|||||||
double modified_error_max;
|
double modified_error_max;
|
||||||
double modified_error_left;
|
double modified_error_left;
|
||||||
double mb_av_energy;
|
double mb_av_energy;
|
||||||
|
double mb_smooth_pct;
|
||||||
|
|
||||||
#if CONFIG_FP_MB_STATS
|
#if CONFIG_FP_MB_STATS
|
||||||
uint8_t *frame_mb_stats_buf;
|
uint8_t *frame_mb_stats_buf;
|
||||||
|
@@ -812,8 +812,8 @@ static int rc_pick_q_and_bounds_one_pass_cbr(const VP9_COMP *cpi,
|
|||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_active_cq_level(const RATE_CONTROL *rc,
|
static int get_active_cq_level_one_pass(
|
||||||
const VP9EncoderConfig *const oxcf) {
|
const RATE_CONTROL *rc, const VP9EncoderConfig *const oxcf) {
|
||||||
static const double cq_adjust_threshold = 0.1;
|
static const double cq_adjust_threshold = 0.1;
|
||||||
int active_cq_level = oxcf->cq_level;
|
int active_cq_level = oxcf->cq_level;
|
||||||
if (oxcf->rc_mode == VPX_CQ &&
|
if (oxcf->rc_mode == VPX_CQ &&
|
||||||
@@ -826,13 +826,36 @@ static int get_active_cq_level(const RATE_CONTROL *rc,
|
|||||||
return active_cq_level;
|
return active_cq_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SMOOTH_PCT_MIN 0.1
|
||||||
|
#define SMOOTH_PCT_DIV 0.05
|
||||||
|
static int get_active_cq_level_two_pass(
|
||||||
|
const TWO_PASS *twopass, const RATE_CONTROL *rc,
|
||||||
|
const VP9EncoderConfig *const oxcf) {
|
||||||
|
static const double cq_adjust_threshold = 0.1;
|
||||||
|
int active_cq_level = oxcf->cq_level;
|
||||||
|
if (oxcf->rc_mode == VPX_CQ) {
|
||||||
|
if (twopass->mb_smooth_pct > SMOOTH_PCT_MIN) {
|
||||||
|
active_cq_level -= (twopass->mb_smooth_pct - SMOOTH_PCT_MIN) /
|
||||||
|
SMOOTH_PCT_DIV;
|
||||||
|
active_cq_level = VPXMAX(active_cq_level, 0);
|
||||||
|
}
|
||||||
|
if (rc->total_target_bits > 0) {
|
||||||
|
const double x = (double)rc->total_actual_bits / rc->total_target_bits;
|
||||||
|
if (x < cq_adjust_threshold) {
|
||||||
|
active_cq_level = (int)(active_cq_level * x / cq_adjust_threshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return active_cq_level;
|
||||||
|
}
|
||||||
|
|
||||||
static int rc_pick_q_and_bounds_one_pass_vbr(const VP9_COMP *cpi,
|
static int rc_pick_q_and_bounds_one_pass_vbr(const VP9_COMP *cpi,
|
||||||
int *bottom_index,
|
int *bottom_index,
|
||||||
int *top_index) {
|
int *top_index) {
|
||||||
const VP9_COMMON *const cm = &cpi->common;
|
const VP9_COMMON *const cm = &cpi->common;
|
||||||
const RATE_CONTROL *const rc = &cpi->rc;
|
const RATE_CONTROL *const rc = &cpi->rc;
|
||||||
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
|
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
|
||||||
const int cq_level = get_active_cq_level(rc, oxcf);
|
const int cq_level = get_active_cq_level_one_pass(rc, oxcf);
|
||||||
int active_best_quality;
|
int active_best_quality;
|
||||||
int active_worst_quality = calc_active_worst_quality_one_pass_vbr(cpi);
|
int active_worst_quality = calc_active_worst_quality_one_pass_vbr(cpi);
|
||||||
int q;
|
int q;
|
||||||
@@ -1018,7 +1041,7 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi,
|
|||||||
const RATE_CONTROL *const rc = &cpi->rc;
|
const RATE_CONTROL *const rc = &cpi->rc;
|
||||||
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
|
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
|
||||||
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
|
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
|
||||||
const int cq_level = get_active_cq_level(rc, oxcf);
|
const int cq_level = get_active_cq_level_two_pass(&cpi->twopass, rc, oxcf);
|
||||||
int active_best_quality;
|
int active_best_quality;
|
||||||
int active_worst_quality = cpi->twopass.active_worst_quality;
|
int active_worst_quality = cpi->twopass.active_worst_quality;
|
||||||
int q;
|
int q;
|
||||||
|
Reference in New Issue
Block a user