Commit e0846c9c authored by Paul Wilkins's avatar Paul Wilkins

CQ Mode

The merge includes hooks to for CQ mode and other code
changes merged from the test branch.

CQ mode attempts to maintain a more stable quantizer within a clip
whilst also trying to adhere to a guidline maximum bitrate.

The existing target data rate parameter is used to specify the
guideline maximum bitrate.

A new parameter allows the user to specify a target CQ level.

For normal (non kf/gf/arf) frames, the quantizer will not drop BELOW the
user specified value (0-63). However, in some cases the encoder may
choose to impose a target CQ that is above that specified by the user,
if it estimates that consistent use of the target value is not compatible
with guideline maximum bitrate.

Change-Id: I2221f9eecae8cc3c431d36caf83503941b25e4c1
parent 3af3593c
...@@ -46,7 +46,8 @@ extern "C" ...@@ -46,7 +46,8 @@ extern "C"
typedef enum typedef enum
{ {
USAGE_STREAM_FROM_SERVER = 0x0, USAGE_STREAM_FROM_SERVER = 0x0,
USAGE_LOCAL_FILE_PLAYBACK = 0x1 USAGE_LOCAL_FILE_PLAYBACK = 0x1,
USAGE_CONSTRAINED_QUALITY = 0x2
} END_USAGE; } END_USAGE;
...@@ -150,6 +151,7 @@ extern "C" ...@@ -150,6 +151,7 @@ extern "C"
int fixed_q; int fixed_q;
int worst_allowed_q; int worst_allowed_q;
int best_allowed_q; int best_allowed_q;
int cq_level;
// allow internal resizing ( currently disabled in the build !!!!!) // allow internal resizing ( currently disabled in the build !!!!!)
int allow_spatial_resampling; int allow_spatial_resampling;
...@@ -187,7 +189,6 @@ extern "C" ...@@ -187,7 +189,6 @@ extern "C"
int arnr_strength ; int arnr_strength ;
int arnr_type ; int arnr_type ;
struct vpx_fixed_buf two_pass_stats_in; struct vpx_fixed_buf two_pass_stats_in;
struct vpx_codec_pkt_list *output_pkt_list; struct vpx_codec_pkt_list *output_pkt_list;
......
...@@ -58,6 +58,7 @@ extern const int vp8_gf_boost_qadjustment[QINDEX_RANGE]; ...@@ -58,6 +58,7 @@ extern const int vp8_gf_boost_qadjustment[QINDEX_RANGE];
#define KF_MB_INTRA_MIN 300 #define KF_MB_INTRA_MIN 300
#define GF_MB_INTRA_MIN 200 #define GF_MB_INTRA_MIN 200
#define DOUBLE_DIVIDE_CHECK(X) ((X)<0?(X)-.000001:(X)+.000001) #define DOUBLE_DIVIDE_CHECK(X) ((X)<0?(X)-.000001:(X)+.000001)
#define POW1 (double)cpi->oxcf.two_pass_vbrbias/100.0 #define POW1 (double)cpi->oxcf.two_pass_vbrbias/100.0
...@@ -66,6 +67,19 @@ extern const int vp8_gf_boost_qadjustment[QINDEX_RANGE]; ...@@ -66,6 +67,19 @@ extern const int vp8_gf_boost_qadjustment[QINDEX_RANGE];
static int vscale_lookup[7] = {0, 1, 1, 2, 2, 3, 3}; static int vscale_lookup[7] = {0, 1, 1, 2, 2, 3, 3};
static int hscale_lookup[7] = {0, 0, 1, 1, 2, 2, 3}; static int hscale_lookup[7] = {0, 0, 1, 1, 2, 2, 3};
const int cq_level[QINDEX_RANGE] =
{
0,0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,
9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,20,
20,21,22,22,23,24,24,25,26,27,27,28,29,30,30,31,
32,33,33,34,35,36,36,37,38,39,39,40,41,42,42,43,
44,45,46,46,47,48,49,50,50,51,52,53,54,55,55,56,
57,58,59,60,60,61,62,63,64,65,66,67,67,68,69,70,
71,72,73,74,75,75,76,77,78,79,80,81,82,83,84,85,
86,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100
};
void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame); void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame);
int vp8_input_stats(VP8_COMP *cpi, FIRSTPASS_STATS *fps); int vp8_input_stats(VP8_COMP *cpi, FIRSTPASS_STATS *fps);
...@@ -889,7 +903,7 @@ void vp8_first_pass(VP8_COMP *cpi) ...@@ -889,7 +903,7 @@ void vp8_first_pass(VP8_COMP *cpi)
} }
extern const int vp8_bits_per_mb[2][QINDEX_RANGE]; extern const int vp8_bits_per_mb[2][QINDEX_RANGE];
#define BASE_ERRPERMB 150 #define BASE_ERRPERMB 100
static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh, int Height, int Width) static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh, int Height, int Width)
{ {
int Q; int Q;
...@@ -945,7 +959,7 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_ ...@@ -945,7 +959,7 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_
corr_high = (corr_high < 0.05) corr_high = (corr_high < 0.05)
? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high;
// Try and pick a Q that should be high enough to encode the // Try and pick a max Q that will be high enough to encode the
// content at the given rate. // content at the given rate.
for (Q = cpi->maxq_min_limit; Q < cpi->maxq_max_limit; Q++) for (Q = cpi->maxq_min_limit; Q < cpi->maxq_max_limit; Q++)
{ {
...@@ -966,6 +980,15 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_ ...@@ -966,6 +980,15 @@ static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_
break; break;
} }
// Restriction on active max q for constrained quality mode.
if ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) &&
(Q < cpi->cq_target_quality) )
//(Q < cpi->oxcf.cq_target_quality) )
{
Q = cpi->cq_target_quality;
//Q = cpi->oxcf.cq_target_quality;
}
return Q; return Q;
} }
static int estimate_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh, int Height, int Width) static int estimate_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh, int Height, int Width)
...@@ -1114,6 +1137,79 @@ static int estimate_kf_group_q(VP8_COMP *cpi, double section_err, int section_ta ...@@ -1114,6 +1137,79 @@ static int estimate_kf_group_q(VP8_COMP *cpi, double section_err, int section_ta
return Q; return Q;
} }
// For cq mode estimate a cq level that matches the observed
// complexity and data rate.
static int estimate_cq(VP8_COMP *cpi, double section_err,
int section_target_bandwitdh, int Height, int Width)
{
int Q;
int num_mbs = ((Height * Width) / (16 * 16));
int target_norm_bits_per_mb;
double err_per_mb = section_err / num_mbs;
double correction_factor;
double corr_high;
double speed_correction = 1.0;
double pow_highq = 0.90;
double pow_lowq = 0.40;
double clip_iiratio;
double clip_iifactor;
target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20))
? (512 * section_target_bandwitdh) / num_mbs
: 512 * (section_target_bandwitdh / num_mbs);
// Corrections for higher compression speed settings
// (reduced compression expected)
if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1))
{
if (cpi->oxcf.cpu_used <= 5)
speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04);
else
speed_correction = 1.25;
}
// II ratio correction factor for clip as a whole
clip_iiratio = cpi->total_stats->intra_error /
DOUBLE_DIVIDE_CHECK(cpi->total_stats->coded_error);
clip_iifactor = 1.0 - ((clip_iiratio - 10.0) * 0.025);
if (clip_iifactor < 0.80)
clip_iifactor = 0.80;
// Correction factor used for Q values >= 20
corr_high = pow(err_per_mb / BASE_ERRPERMB, pow_highq);
corr_high = (corr_high < 0.05) ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high;
// Try and pick a Q that can encode the content at the given rate.
for (Q = 0; Q < MAXQ; Q++)
{
int bits_per_mb_at_this_q;
if (Q < 50)
{
correction_factor =
pow( err_per_mb / BASE_ERRPERMB, (pow_lowq + Q * 0.01));
correction_factor = (correction_factor < 0.05) ? 0.05
: (correction_factor > 5.0) ? 5.0
: correction_factor;
}
else
correction_factor = corr_high;
bits_per_mb_at_this_q =
(int)( .5 + correction_factor *
speed_correction *
clip_iifactor *
(double)vp8_bits_per_mb[INTER_FRAME][Q] / 1.0);
if (bits_per_mb_at_this_q <= target_norm_bits_per_mb)
break;
}
return cq_level[Q];
}
extern void vp8_new_frame_rate(VP8_COMP *cpi, double framerate); extern void vp8_new_frame_rate(VP8_COMP *cpi, double framerate);
void vp8_init_second_pass(VP8_COMP *cpi) void vp8_init_second_pass(VP8_COMP *cpi)
...@@ -1767,7 +1863,9 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) ...@@ -1767,7 +1863,9 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
vp8_avg_stats(&sectionstats); vp8_avg_stats(&sectionstats);
cpi->section_intra_rating = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); cpi->section_intra_rating =
sectionstats.intra_error /
DOUBLE_DIVIDE_CHECK(sectionstats.coded_error);
Ratio = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); Ratio = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error);
//if( (Ratio > 11) ) //&& (sectionstats.pcnt_second_ref < .20) ) //if( (Ratio > 11) ) //&& (sectionstats.pcnt_second_ref < .20) )
...@@ -1994,9 +2092,26 @@ void vp8_second_pass(VP8_COMP *cpi) ...@@ -1994,9 +2092,26 @@ void vp8_second_pass(VP8_COMP *cpi)
if (cpi->common.current_video_frame == 0) if (cpi->common.current_video_frame == 0)
{ {
// guess at 2nd pass max q
cpi->est_max_qcorrection_factor = 1.0; cpi->est_max_qcorrection_factor = 1.0;
// Experimental code to try and set a cq_level in constrained
// quality mode.
if ( cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY )
{
int est_cq;
est_cq =
estimate_cq( cpi,
(cpi->total_coded_error_left / frames_left),
(int)(cpi->bits_left / frames_left),
cpi->common.Height, cpi->common.Width);
cpi->cq_target_quality = cpi->oxcf.cq_level;
if ( est_cq > cpi->cq_target_quality )
cpi->cq_target_quality = est_cq;
}
// guess at maxq needed in 2nd pass
cpi->maxq_max_limit = cpi->worst_quality; cpi->maxq_max_limit = cpi->worst_quality;
cpi->maxq_min_limit = cpi->best_quality; cpi->maxq_min_limit = cpi->best_quality;
tmp_q = estimate_max_q( cpi, tmp_q = estimate_max_q( cpi,
...@@ -2005,7 +2120,7 @@ void vp8_second_pass(VP8_COMP *cpi) ...@@ -2005,7 +2120,7 @@ void vp8_second_pass(VP8_COMP *cpi)
cpi->common.Height, cpi->common.Height,
cpi->common.Width); cpi->common.Width);
// Limit the maxq value retuned subsequently. // Limit the maxq value returned subsequently.
// This increases the risk of overspend if the initial // This increases the risk of overspend if the initial
// estimate for the clip is bad, but helps prevent excessive // estimate for the clip is bad, but helps prevent excessive
// variation in Q, especially near the end of a clip // variation in Q, especially near the end of a clip
...@@ -2018,6 +2133,7 @@ void vp8_second_pass(VP8_COMP *cpi) ...@@ -2018,6 +2133,7 @@ void vp8_second_pass(VP8_COMP *cpi)
cpi->active_worst_quality = tmp_q; cpi->active_worst_quality = tmp_q;
cpi->ni_av_qi = tmp_q; cpi->ni_av_qi = tmp_q;
} }
// The last few frames of a clip almost always have to few or too many // The last few frames of a clip almost always have to few or too many
// bits and for the sake of over exact rate control we dont want to make // bits and for the sake of over exact rate control we dont want to make
// radical adjustments to the allowed quantizer range just to use up a // radical adjustments to the allowed quantizer range just to use up a
......
...@@ -155,25 +155,25 @@ extern const int vp8cx_base_skip_false_prob[128]; ...@@ -155,25 +155,25 @@ extern const int vp8cx_base_skip_false_prob[128];
// Tables relating active max Q to active min Q // Tables relating active max Q to active min Q
static const int kf_low_motion_minq[QINDEX_RANGE] = static const int kf_low_motion_minq[QINDEX_RANGE] =
{ {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,
5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 10,10, 3,3,3,3,3,3,4,4,4,5,5,5,5,5,6,6,
11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18, 6,6,7,7,8,8,8,8,9,9,10,10,10,10,11,11,
19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26, 11,11,12,12,13,13,13,13,14,14,15,15,15,15,16,16,
27,27,28,28,29,29,30,30,31,32,33,34,35,36,37,38, 16,16,17,17,18,18,18,18,19,20,20,21,21,22,23,23
}; };
static const int kf_high_motion_minq[QINDEX_RANGE] = static const int kf_high_motion_minq[QINDEX_RANGE] =
{ {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,
6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,10, 3,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6,
11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18, 6,6,7,7,8,8,8,8,9,9,10,10,10,10,11,11,
19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26, 11,11,12,12,13,13,13,13,14,14,15,15,15,15,16,16,
27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34, 16,16,17,17,18,18,18,18,19,19,20,20,20,20,21,21,
35,35,36,36,37,38,39,40,41,42,43,44,45,46,47,48, 21,21,22,22,23,23,24,25,25,26,26,27,28,28,29,30
}; };
static const int gf_low_motion_minq[QINDEX_RANGE] = static const int gf_low_motion_minq[QINDEX_RANGE] =
{ {
...@@ -195,7 +195,7 @@ static const int gf_mid_motion_minq[QINDEX_RANGE] = ...@@ -195,7 +195,7 @@ static const int gf_mid_motion_minq[QINDEX_RANGE] =
22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29, 22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,
30,30,31,31,32,32,33,33,34,34,35,35,36,36,37,37, 30,30,31,31,32,32,33,33,34,34,35,35,36,36,37,37,
38,39,39,40,40,41,41,42,42,43,43,44,45,46,47,48, 38,39,39,40,40,41,41,42,42,43,43,44,45,46,47,48,
49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64
}; };
static const int gf_high_motion_minq[QINDEX_RANGE] = static const int gf_high_motion_minq[QINDEX_RANGE] =
{ {
...@@ -206,7 +206,7 @@ static const int gf_high_motion_minq[QINDEX_RANGE] = ...@@ -206,7 +206,7 @@ static const int gf_high_motion_minq[QINDEX_RANGE] =
25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32, 25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,
33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40, 33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40,
41,41,42,42,43,44,45,46,47,48,49,50,51,52,53,54, 41,41,42,42,43,44,45,46,47,48,49,50,51,52,53,54,
55,56,57,58,59,60,62,64,66,68,70,72,74,76,78,80, 55,56,57,58,59,60,62,64,66,68,70,72,74,76,78,80
}; };
static const int inter_minq[QINDEX_RANGE] = static const int inter_minq[QINDEX_RANGE] =
{ {
...@@ -2026,6 +2026,9 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) ...@@ -2026,6 +2026,9 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf)
cpi->active_best_quality = cpi->oxcf.best_allowed_q; cpi->active_best_quality = cpi->oxcf.best_allowed_q;
cpi->buffered_mode = (cpi->oxcf.optimal_buffer_level > 0) ? TRUE : FALSE; cpi->buffered_mode = (cpi->oxcf.optimal_buffer_level > 0) ? TRUE : FALSE;
// Experimental cq target value
cpi->cq_target_quality = oxcf->cq_level;
cpi->rolling_target_bits = cpi->av_per_frame_bandwidth; cpi->rolling_target_bits = cpi->av_per_frame_bandwidth;
cpi->rolling_actual_bits = cpi->av_per_frame_bandwidth; cpi->rolling_actual_bits = cpi->av_per_frame_bandwidth;
cpi->long_rolling_target_bits = cpi->av_per_frame_bandwidth; cpi->long_rolling_target_bits = cpi->av_per_frame_bandwidth;
...@@ -3515,12 +3518,14 @@ static BOOL recode_loop_test( VP8_COMP *cpi, ...@@ -3515,12 +3518,14 @@ static BOOL recode_loop_test( VP8_COMP *cpi,
{ {
// General over and under shoot tests // General over and under shoot tests
if ( ((cpi->projected_frame_size > high_limit) && (q < maxq)) || if ( ((cpi->projected_frame_size > high_limit) && (q < maxq)) ||
((cpi->projected_frame_size < low_limit) && (q > minq)) ) ((cpi->projected_frame_size < low_limit) && (q > minq)) ||
((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) &&
(q > cpi->cq_target_quality) &&
(cpi->projected_frame_size <
((cpi->this_frame_target * 7) >> 3))) )
{ {
force_recode = TRUE; force_recode = TRUE;
} }
// Specific rate control mode related tests
// TBD
} }
return force_recode; return force_recode;
...@@ -3811,15 +3816,7 @@ static void encode_frame_to_data_rate ...@@ -3811,15 +3816,7 @@ static void encode_frame_to_data_rate
cpi->active_best_quality = gf_high_motion_minq[Q]; cpi->active_best_quality = gf_high_motion_minq[Q];
else else
cpi->active_best_quality = gf_mid_motion_minq[Q]; cpi->active_best_quality = gf_mid_motion_minq[Q];
}
/*cpi->active_best_quality = gf_arf_minq[Q];
tmp = (cpi->gfu_boost > 1000) ? 600 : cpi->gfu_boost - 400;
//tmp = (cpi->gfu_boost > 1000) ? 600 :
//(cpi->gfu_boost < 400) ? 0 : cpi->gfu_boost - 400;
tmp = 128 - (tmp >> 4);
cpi->active_best_quality = (cpi->active_best_quality * tmp)>>7;*/
}
// KEY FRAMES // KEY FRAMES
else else
{ {
...@@ -3832,6 +3829,14 @@ static void encode_frame_to_data_rate ...@@ -3832,6 +3829,14 @@ static void encode_frame_to_data_rate
else else
{ {
cpi->active_best_quality = inter_minq[Q]; cpi->active_best_quality = inter_minq[Q];
// For the constant/constrained quality mode we dont want
// the quality to rise above the cq level.
if ((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) &&
(cpi->active_best_quality < cpi->cq_target_quality) )
{
cpi->active_best_quality = cpi->cq_target_quality;
}
} }
// If CBR and the buffer is as full then it is reasonable to allow higher quality on the frames // If CBR and the buffer is as full then it is reasonable to allow higher quality on the frames
...@@ -4566,7 +4571,8 @@ static void encode_frame_to_data_rate ...@@ -4566,7 +4571,8 @@ static void encode_frame_to_data_rate
(cpi->oxcf.starting_buffer_level-cpi->bits_off_target), (cpi->oxcf.starting_buffer_level-cpi->bits_off_target),
(int)cpi->total_actual_bits, cm->base_qindex, (int)cpi->total_actual_bits, cm->base_qindex,
cpi->active_best_quality, cpi->active_worst_quality, cpi->active_best_quality, cpi->active_worst_quality,
cpi->avg_frame_qindex, cpi->zbin_over_quant, cpi->cq_target_quality, cpi->zbin_over_quant,
//cpi->avg_frame_qindex, cpi->zbin_over_quant,
cm->refresh_golden_frame, cm->refresh_alt_ref_frame, cm->refresh_golden_frame, cm->refresh_alt_ref_frame,
cm->frame_type, cpi->gfu_boost, cm->frame_type, cpi->gfu_boost,
cpi->est_max_qcorrection_factor, (int)cpi->bits_left, cpi->est_max_qcorrection_factor, (int)cpi->bits_left,
...@@ -4584,7 +4590,8 @@ static void encode_frame_to_data_rate ...@@ -4584,7 +4590,8 @@ static void encode_frame_to_data_rate
(cpi->oxcf.starting_buffer_level-cpi->bits_off_target), (cpi->oxcf.starting_buffer_level-cpi->bits_off_target),
(int)cpi->total_actual_bits, cm->base_qindex, (int)cpi->total_actual_bits, cm->base_qindex,
cpi->active_best_quality, cpi->active_worst_quality, cpi->active_best_quality, cpi->active_worst_quality,
cpi->avg_frame_qindex, cpi->zbin_over_quant, cpi->cq_target_quality, cpi->zbin_over_quant,
//cpi->avg_frame_qindex, cpi->zbin_over_quant,
cm->refresh_golden_frame, cm->refresh_alt_ref_frame, cm->refresh_golden_frame, cm->refresh_alt_ref_frame,
cm->frame_type, cpi->gfu_boost, cm->frame_type, cpi->gfu_boost,
cpi->est_max_qcorrection_factor, (int)cpi->bits_left, cpi->est_max_qcorrection_factor, (int)cpi->bits_left,
......
...@@ -447,6 +447,7 @@ typedef struct ...@@ -447,6 +447,7 @@ typedef struct
int best_quality; int best_quality;
int active_best_quality; int active_best_quality;
int cq_target_quality;
int maxq_max_limit; int maxq_max_limit;
int maxq_min_limit; int maxq_min_limit;
......
...@@ -1550,12 +1550,21 @@ void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit, ...@@ -1550,12 +1550,21 @@ void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit,
*frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8;
} }
} }
// VBR // VBR and CQ mode
// Note that tighter restrictions here can help quality but hurt encode speed // Note that tighter restrictions here can help quality but hurt encode speed
else else
{ {
*frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; // Stron overshoot limit for constrained quality
*frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY)
{
*frame_over_shoot_limit = cpi->this_frame_target * 11 / 8;
*frame_under_shoot_limit = cpi->this_frame_target * 2 / 8;
}
else
{
*frame_over_shoot_limit = cpi->this_frame_target * 11 / 8;
*frame_under_shoot_limit = cpi->this_frame_target * 5 / 8;
}
} }
} }
} }
......
...@@ -38,6 +38,7 @@ struct vp8_extracfg ...@@ -38,6 +38,7 @@ struct vp8_extracfg
unsigned int arnr_strength; /* alt_ref Noise Reduction Strength */ unsigned int arnr_strength; /* alt_ref Noise Reduction Strength */
unsigned int arnr_type; /* alt_ref filter type */ unsigned int arnr_type; /* alt_ref filter type */
vp8e_tuning tuning; vp8e_tuning tuning;
unsigned int cq_level; /* constrained quality level */
}; };
...@@ -69,6 +70,7 @@ static const struct extraconfig_map extracfg_map[] = ...@@ -69,6 +70,7 @@ static const struct extraconfig_map extracfg_map[] =
3, /* arnr_strength */ 3, /* arnr_strength */
3, /* arnr_type*/ 3, /* arnr_type*/
0, /* tuning*/ 0, /* tuning*/
10, /* cq_level */
} }
} }
}; };
...@@ -148,7 +150,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, ...@@ -148,7 +150,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
#else #else
RANGE_CHECK_HI(cfg, g_lag_in_frames, 0); RANGE_CHECK_HI(cfg, g_lag_in_frames, 0);
#endif #endif
RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_CBR); RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_CQ);
RANGE_CHECK_HI(cfg, rc_undershoot_pct, 100); RANGE_CHECK_HI(cfg, rc_undershoot_pct, 100);
RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100); RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100);
RANGE_CHECK(cfg, kf_mode, VPX_KF_DISABLED, VPX_KF_AUTO); RANGE_CHECK(cfg, kf_mode, VPX_KF_DISABLED, VPX_KF_AUTO);
...@@ -190,6 +192,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, ...@@ -190,6 +192,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
RANGE_CHECK(vp8_cfg, arnr_max_frames, 0, 15); RANGE_CHECK(vp8_cfg, arnr_max_frames, 0, 15);
RANGE_CHECK_HI(vp8_cfg, arnr_strength, 6); RANGE_CHECK_HI(vp8_cfg, arnr_strength, 6);
RANGE_CHECK(vp8_cfg, arnr_type, 1, 3); RANGE_CHECK(vp8_cfg, arnr_type, 1, 3);
RANGE_CHECK(vp8_cfg, cq_level, 0, 63);
if (cfg->g_pass == VPX_RC_LAST_PASS) if (cfg->g_pass == VPX_RC_LAST_PASS)
{ {
...@@ -298,6 +301,10 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, ...@@ -298,6 +301,10 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf,
{ {
oxcf->end_usage = USAGE_STREAM_FROM_SERVER; oxcf->end_usage = USAGE_STREAM_FROM_SERVER;
} }
else if (cfg.rc_end_usage == VPX_CQ)
{
oxcf->end_usage = USAGE_CONSTRAINED_QUALITY;
}
oxcf->target_bandwidth = cfg.rc_target_bitrate; oxcf->target_bandwidth = cfg.rc_target_bitrate;
...@@ -339,6 +346,7 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, ...@@ -339,6 +346,7 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf,
oxcf->arnr_type = vp8_cfg.arnr_type; oxcf->arnr_type = vp8_cfg.arnr_type;
oxcf->tuning = vp8_cfg.tuning; oxcf->tuning = vp8_cfg.tuning;
oxcf->cq_level = vp8_cfg.cq_level;