1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker * Copyright (c) 2020, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker *
4*77c1e3ccSAndroid Build Coastguard Worker * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker */
11*77c1e3ccSAndroid Build Coastguard Worker
12*77c1e3ccSAndroid Build Coastguard Worker #ifndef AOM_AV1_ENCODER_RC_UTILS_H_
13*77c1e3ccSAndroid Build Coastguard Worker #define AOM_AV1_ENCODER_RC_UTILS_H_
14*77c1e3ccSAndroid Build Coastguard Worker
15*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encoder.h"
16*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/psnr.h"
17*77c1e3ccSAndroid Build Coastguard Worker
18*77c1e3ccSAndroid Build Coastguard Worker #ifdef __cplusplus
19*77c1e3ccSAndroid Build Coastguard Worker extern "C" {
20*77c1e3ccSAndroid Build Coastguard Worker #endif
21*77c1e3ccSAndroid Build Coastguard Worker
check_reset_rc_flag(AV1_COMP * cpi)22*77c1e3ccSAndroid Build Coastguard Worker static inline void check_reset_rc_flag(AV1_COMP *cpi) {
23*77c1e3ccSAndroid Build Coastguard Worker RATE_CONTROL *rc = &cpi->rc;
24*77c1e3ccSAndroid Build Coastguard Worker PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
25*77c1e3ccSAndroid Build Coastguard Worker if (cpi->common.current_frame.frame_number >
26*77c1e3ccSAndroid Build Coastguard Worker (unsigned int)cpi->svc.number_spatial_layers) {
27*77c1e3ccSAndroid Build Coastguard Worker if (cpi->ppi->use_svc) {
28*77c1e3ccSAndroid Build Coastguard Worker av1_svc_check_reset_layer_rc_flag(cpi);
29*77c1e3ccSAndroid Build Coastguard Worker } else {
30*77c1e3ccSAndroid Build Coastguard Worker if (rc->avg_frame_bandwidth / 3 > (rc->prev_avg_frame_bandwidth >> 1) ||
31*77c1e3ccSAndroid Build Coastguard Worker rc->avg_frame_bandwidth < (rc->prev_avg_frame_bandwidth >> 1)) {
32*77c1e3ccSAndroid Build Coastguard Worker rc->rc_1_frame = 0;
33*77c1e3ccSAndroid Build Coastguard Worker rc->rc_2_frame = 0;
34*77c1e3ccSAndroid Build Coastguard Worker p_rc->bits_off_target = p_rc->optimal_buffer_level;
35*77c1e3ccSAndroid Build Coastguard Worker p_rc->buffer_level = p_rc->optimal_buffer_level;
36*77c1e3ccSAndroid Build Coastguard Worker }
37*77c1e3ccSAndroid Build Coastguard Worker }
38*77c1e3ccSAndroid Build Coastguard Worker }
39*77c1e3ccSAndroid Build Coastguard Worker }
40*77c1e3ccSAndroid Build Coastguard Worker
set_primary_rc_buffer_sizes(const AV1EncoderConfig * oxcf,AV1_PRIMARY * ppi)41*77c1e3ccSAndroid Build Coastguard Worker static inline void set_primary_rc_buffer_sizes(const AV1EncoderConfig *oxcf,
42*77c1e3ccSAndroid Build Coastguard Worker AV1_PRIMARY *ppi) {
43*77c1e3ccSAndroid Build Coastguard Worker PRIMARY_RATE_CONTROL *p_rc = &ppi->p_rc;
44*77c1e3ccSAndroid Build Coastguard Worker const RateControlCfg *const rc_cfg = &oxcf->rc_cfg;
45*77c1e3ccSAndroid Build Coastguard Worker
46*77c1e3ccSAndroid Build Coastguard Worker const int64_t bandwidth = rc_cfg->target_bandwidth;
47*77c1e3ccSAndroid Build Coastguard Worker const int64_t starting = rc_cfg->starting_buffer_level_ms;
48*77c1e3ccSAndroid Build Coastguard Worker const int64_t optimal = rc_cfg->optimal_buffer_level_ms;
49*77c1e3ccSAndroid Build Coastguard Worker const int64_t maximum = rc_cfg->maximum_buffer_size_ms;
50*77c1e3ccSAndroid Build Coastguard Worker
51*77c1e3ccSAndroid Build Coastguard Worker p_rc->starting_buffer_level = starting * bandwidth / 1000;
52*77c1e3ccSAndroid Build Coastguard Worker p_rc->optimal_buffer_level =
53*77c1e3ccSAndroid Build Coastguard Worker (optimal == 0) ? bandwidth / 8 : optimal * bandwidth / 1000;
54*77c1e3ccSAndroid Build Coastguard Worker p_rc->maximum_buffer_size =
55*77c1e3ccSAndroid Build Coastguard Worker (maximum == 0) ? bandwidth / 8 : maximum * bandwidth / 1000;
56*77c1e3ccSAndroid Build Coastguard Worker
57*77c1e3ccSAndroid Build Coastguard Worker // Under a configuration change, where maximum_buffer_size may change,
58*77c1e3ccSAndroid Build Coastguard Worker // keep buffer level clipped to the maximum allowed buffer size.
59*77c1e3ccSAndroid Build Coastguard Worker p_rc->bits_off_target =
60*77c1e3ccSAndroid Build Coastguard Worker AOMMIN(p_rc->bits_off_target, p_rc->maximum_buffer_size);
61*77c1e3ccSAndroid Build Coastguard Worker p_rc->buffer_level = AOMMIN(p_rc->buffer_level, p_rc->maximum_buffer_size);
62*77c1e3ccSAndroid Build Coastguard Worker }
63*77c1e3ccSAndroid Build Coastguard Worker
config_target_level(AV1_COMP * const cpi,AV1_LEVEL target_level,int tier)64*77c1e3ccSAndroid Build Coastguard Worker static inline void config_target_level(AV1_COMP *const cpi,
65*77c1e3ccSAndroid Build Coastguard Worker AV1_LEVEL target_level, int tier) {
66*77c1e3ccSAndroid Build Coastguard Worker AV1EncoderConfig *const oxcf = &cpi->oxcf;
67*77c1e3ccSAndroid Build Coastguard Worker SequenceHeader *const seq_params = cpi->common.seq_params;
68*77c1e3ccSAndroid Build Coastguard Worker TileConfig *const tile_cfg = &oxcf->tile_cfg;
69*77c1e3ccSAndroid Build Coastguard Worker RateControlCfg *const rc_cfg = &oxcf->rc_cfg;
70*77c1e3ccSAndroid Build Coastguard Worker
71*77c1e3ccSAndroid Build Coastguard Worker // Adjust target bitrate to be no larger than 70% of level limit.
72*77c1e3ccSAndroid Build Coastguard Worker const BITSTREAM_PROFILE profile = seq_params->profile;
73*77c1e3ccSAndroid Build Coastguard Worker const double level_bitrate_limit =
74*77c1e3ccSAndroid Build Coastguard Worker av1_get_max_bitrate_for_level(target_level, tier, profile);
75*77c1e3ccSAndroid Build Coastguard Worker const int64_t max_bitrate = (int64_t)(level_bitrate_limit * 0.70);
76*77c1e3ccSAndroid Build Coastguard Worker rc_cfg->target_bandwidth = AOMMIN(rc_cfg->target_bandwidth, max_bitrate);
77*77c1e3ccSAndroid Build Coastguard Worker // Also need to update cpi->ppi->twopass.bits_left.
78*77c1e3ccSAndroid Build Coastguard Worker TWO_PASS *const twopass = &cpi->ppi->twopass;
79*77c1e3ccSAndroid Build Coastguard Worker FIRSTPASS_STATS *stats = twopass->stats_buf_ctx->total_stats;
80*77c1e3ccSAndroid Build Coastguard Worker if (stats != NULL)
81*77c1e3ccSAndroid Build Coastguard Worker cpi->ppi->twopass.bits_left =
82*77c1e3ccSAndroid Build Coastguard Worker (int64_t)(stats->duration * rc_cfg->target_bandwidth / 10000000.0);
83*77c1e3ccSAndroid Build Coastguard Worker
84*77c1e3ccSAndroid Build Coastguard Worker // Adjust max over-shoot percentage.
85*77c1e3ccSAndroid Build Coastguard Worker rc_cfg->over_shoot_pct = 0;
86*77c1e3ccSAndroid Build Coastguard Worker
87*77c1e3ccSAndroid Build Coastguard Worker // Adjust max quantizer.
88*77c1e3ccSAndroid Build Coastguard Worker rc_cfg->worst_allowed_q = 255;
89*77c1e3ccSAndroid Build Coastguard Worker
90*77c1e3ccSAndroid Build Coastguard Worker // Adjust number of tiles and tile columns to be under level limit.
91*77c1e3ccSAndroid Build Coastguard Worker int max_tiles, max_tile_cols;
92*77c1e3ccSAndroid Build Coastguard Worker av1_get_max_tiles_for_level(target_level, &max_tiles, &max_tile_cols);
93*77c1e3ccSAndroid Build Coastguard Worker while (tile_cfg->tile_columns > 0 &&
94*77c1e3ccSAndroid Build Coastguard Worker (1 << tile_cfg->tile_columns) > max_tile_cols) {
95*77c1e3ccSAndroid Build Coastguard Worker --tile_cfg->tile_columns;
96*77c1e3ccSAndroid Build Coastguard Worker }
97*77c1e3ccSAndroid Build Coastguard Worker const int tile_cols = (1 << tile_cfg->tile_columns);
98*77c1e3ccSAndroid Build Coastguard Worker while (tile_cfg->tile_rows > 0 &&
99*77c1e3ccSAndroid Build Coastguard Worker tile_cols * (1 << tile_cfg->tile_rows) > max_tiles) {
100*77c1e3ccSAndroid Build Coastguard Worker --tile_cfg->tile_rows;
101*77c1e3ccSAndroid Build Coastguard Worker }
102*77c1e3ccSAndroid Build Coastguard Worker
103*77c1e3ccSAndroid Build Coastguard Worker // Adjust min compression ratio.
104*77c1e3ccSAndroid Build Coastguard Worker const int still_picture = seq_params->still_picture;
105*77c1e3ccSAndroid Build Coastguard Worker const double min_cr =
106*77c1e3ccSAndroid Build Coastguard Worker av1_get_min_cr_for_level(target_level, tier, still_picture);
107*77c1e3ccSAndroid Build Coastguard Worker rc_cfg->min_cr = AOMMAX(rc_cfg->min_cr, (unsigned int)(min_cr * 100));
108*77c1e3ccSAndroid Build Coastguard Worker }
109*77c1e3ccSAndroid Build Coastguard Worker
110*77c1e3ccSAndroid Build Coastguard Worker #if !CONFIG_REALTIME_ONLY
111*77c1e3ccSAndroid Build Coastguard Worker
112*77c1e3ccSAndroid Build Coastguard Worker /*!\brief Function to test for conditions that indicate we should loop
113*77c1e3ccSAndroid Build Coastguard Worker * back and recode a frame.
114*77c1e3ccSAndroid Build Coastguard Worker *
115*77c1e3ccSAndroid Build Coastguard Worker * \ingroup rate_control
116*77c1e3ccSAndroid Build Coastguard Worker *
117*77c1e3ccSAndroid Build Coastguard Worker * \param[in] cpi Top-level encoder structure
118*77c1e3ccSAndroid Build Coastguard Worker * \param[in] high_limit Upper rate threshold
119*77c1e3ccSAndroid Build Coastguard Worker * \param[in] low_limit Lower rate threshold
120*77c1e3ccSAndroid Build Coastguard Worker * \param[in] q Current q index
121*77c1e3ccSAndroid Build Coastguard Worker * \param[in] maxq Maximum allowed q index
122*77c1e3ccSAndroid Build Coastguard Worker * \param[in] minq Minimum allowed q index
123*77c1e3ccSAndroid Build Coastguard Worker *
124*77c1e3ccSAndroid Build Coastguard Worker * \return Indicates if a recode is required.
125*77c1e3ccSAndroid Build Coastguard Worker * \retval 1 Recode Required
126*77c1e3ccSAndroid Build Coastguard Worker * \retval 0 No Recode required
127*77c1e3ccSAndroid Build Coastguard Worker */
recode_loop_test(AV1_COMP * cpi,int high_limit,int low_limit,int q,int maxq,int minq)128*77c1e3ccSAndroid Build Coastguard Worker static inline int recode_loop_test(AV1_COMP *cpi, int high_limit, int low_limit,
129*77c1e3ccSAndroid Build Coastguard Worker int q, int maxq, int minq) {
130*77c1e3ccSAndroid Build Coastguard Worker const RATE_CONTROL *const rc = &cpi->rc;
131*77c1e3ccSAndroid Build Coastguard Worker const AV1EncoderConfig *const oxcf = &cpi->oxcf;
132*77c1e3ccSAndroid Build Coastguard Worker const int frame_is_kfgfarf = frame_is_kf_gf_arf(cpi);
133*77c1e3ccSAndroid Build Coastguard Worker int force_recode = 0;
134*77c1e3ccSAndroid Build Coastguard Worker
135*77c1e3ccSAndroid Build Coastguard Worker if ((rc->projected_frame_size >= rc->max_frame_bandwidth) ||
136*77c1e3ccSAndroid Build Coastguard Worker (cpi->sf.hl_sf.recode_loop == ALLOW_RECODE) ||
137*77c1e3ccSAndroid Build Coastguard Worker (frame_is_kfgfarf &&
138*77c1e3ccSAndroid Build Coastguard Worker (cpi->sf.hl_sf.recode_loop == ALLOW_RECODE_KFARFGF))) {
139*77c1e3ccSAndroid Build Coastguard Worker // TODO(agrange) high_limit could be greater than the scale-down threshold.
140*77c1e3ccSAndroid Build Coastguard Worker if ((rc->projected_frame_size > high_limit && q < maxq) ||
141*77c1e3ccSAndroid Build Coastguard Worker (rc->projected_frame_size < low_limit && q > minq)) {
142*77c1e3ccSAndroid Build Coastguard Worker force_recode = 1;
143*77c1e3ccSAndroid Build Coastguard Worker } else if (cpi->oxcf.rc_cfg.mode == AOM_CQ) {
144*77c1e3ccSAndroid Build Coastguard Worker // Deal with frame undershoot and whether or not we are
145*77c1e3ccSAndroid Build Coastguard Worker // below the automatically set cq level.
146*77c1e3ccSAndroid Build Coastguard Worker if (q > oxcf->rc_cfg.cq_level &&
147*77c1e3ccSAndroid Build Coastguard Worker rc->projected_frame_size <
148*77c1e3ccSAndroid Build Coastguard Worker (((int64_t)rc->this_frame_target * 7) >> 3)) {
149*77c1e3ccSAndroid Build Coastguard Worker force_recode = 1;
150*77c1e3ccSAndroid Build Coastguard Worker }
151*77c1e3ccSAndroid Build Coastguard Worker }
152*77c1e3ccSAndroid Build Coastguard Worker }
153*77c1e3ccSAndroid Build Coastguard Worker return force_recode;
154*77c1e3ccSAndroid Build Coastguard Worker }
155*77c1e3ccSAndroid Build Coastguard Worker
av1_get_gfu_boost_projection_factor(double min_factor,double max_factor,int frame_count)156*77c1e3ccSAndroid Build Coastguard Worker static inline double av1_get_gfu_boost_projection_factor(double min_factor,
157*77c1e3ccSAndroid Build Coastguard Worker double max_factor,
158*77c1e3ccSAndroid Build Coastguard Worker int frame_count) {
159*77c1e3ccSAndroid Build Coastguard Worker double factor = sqrt((double)frame_count);
160*77c1e3ccSAndroid Build Coastguard Worker factor = AOMMIN(factor, max_factor);
161*77c1e3ccSAndroid Build Coastguard Worker factor = AOMMAX(factor, min_factor);
162*77c1e3ccSAndroid Build Coastguard Worker factor = (200.0 + 10.0 * factor);
163*77c1e3ccSAndroid Build Coastguard Worker return factor;
164*77c1e3ccSAndroid Build Coastguard Worker }
165*77c1e3ccSAndroid Build Coastguard Worker
get_gfu_boost_from_r0_lap(double min_factor,double max_factor,double r0,int frames_to_key)166*77c1e3ccSAndroid Build Coastguard Worker static inline int get_gfu_boost_from_r0_lap(double min_factor,
167*77c1e3ccSAndroid Build Coastguard Worker double max_factor, double r0,
168*77c1e3ccSAndroid Build Coastguard Worker int frames_to_key) {
169*77c1e3ccSAndroid Build Coastguard Worker double factor = av1_get_gfu_boost_projection_factor(min_factor, max_factor,
170*77c1e3ccSAndroid Build Coastguard Worker frames_to_key);
171*77c1e3ccSAndroid Build Coastguard Worker const int boost = (int)rint(factor / r0);
172*77c1e3ccSAndroid Build Coastguard Worker return boost;
173*77c1e3ccSAndroid Build Coastguard Worker }
174*77c1e3ccSAndroid Build Coastguard Worker
av1_get_kf_boost_projection_factor(int frame_count)175*77c1e3ccSAndroid Build Coastguard Worker static inline double av1_get_kf_boost_projection_factor(int frame_count) {
176*77c1e3ccSAndroid Build Coastguard Worker double factor = sqrt((double)frame_count);
177*77c1e3ccSAndroid Build Coastguard Worker factor = AOMMIN(factor, 10.0);
178*77c1e3ccSAndroid Build Coastguard Worker factor = AOMMAX(factor, 4.0);
179*77c1e3ccSAndroid Build Coastguard Worker factor = (75.0 + 14.0 * factor);
180*77c1e3ccSAndroid Build Coastguard Worker return factor;
181*77c1e3ccSAndroid Build Coastguard Worker }
182*77c1e3ccSAndroid Build Coastguard Worker
get_regulated_q_overshoot(AV1_COMP * const cpi,int is_encode_stage,int q_low,int q_high,int top_index,int bottom_index)183*77c1e3ccSAndroid Build Coastguard Worker static inline int get_regulated_q_overshoot(AV1_COMP *const cpi,
184*77c1e3ccSAndroid Build Coastguard Worker int is_encode_stage, int q_low,
185*77c1e3ccSAndroid Build Coastguard Worker int q_high, int top_index,
186*77c1e3ccSAndroid Build Coastguard Worker int bottom_index) {
187*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
188*77c1e3ccSAndroid Build Coastguard Worker const RATE_CONTROL *const rc = &cpi->rc;
189*77c1e3ccSAndroid Build Coastguard Worker
190*77c1e3ccSAndroid Build Coastguard Worker av1_rc_update_rate_correction_factors(cpi, is_encode_stage, cm->width,
191*77c1e3ccSAndroid Build Coastguard Worker cm->height);
192*77c1e3ccSAndroid Build Coastguard Worker
193*77c1e3ccSAndroid Build Coastguard Worker int q_regulated =
194*77c1e3ccSAndroid Build Coastguard Worker av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index,
195*77c1e3ccSAndroid Build Coastguard Worker AOMMAX(q_high, top_index), cm->width, cm->height);
196*77c1e3ccSAndroid Build Coastguard Worker
197*77c1e3ccSAndroid Build Coastguard Worker int retries = 0;
198*77c1e3ccSAndroid Build Coastguard Worker while (q_regulated < q_low && retries < 10) {
199*77c1e3ccSAndroid Build Coastguard Worker av1_rc_update_rate_correction_factors(cpi, is_encode_stage, cm->width,
200*77c1e3ccSAndroid Build Coastguard Worker cm->height);
201*77c1e3ccSAndroid Build Coastguard Worker q_regulated =
202*77c1e3ccSAndroid Build Coastguard Worker av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index,
203*77c1e3ccSAndroid Build Coastguard Worker AOMMAX(q_high, top_index), cm->width, cm->height);
204*77c1e3ccSAndroid Build Coastguard Worker retries++;
205*77c1e3ccSAndroid Build Coastguard Worker }
206*77c1e3ccSAndroid Build Coastguard Worker return q_regulated;
207*77c1e3ccSAndroid Build Coastguard Worker }
208*77c1e3ccSAndroid Build Coastguard Worker
get_regulated_q_undershoot(AV1_COMP * const cpi,int is_encode_stage,int q_high,int top_index,int bottom_index)209*77c1e3ccSAndroid Build Coastguard Worker static inline int get_regulated_q_undershoot(AV1_COMP *const cpi,
210*77c1e3ccSAndroid Build Coastguard Worker int is_encode_stage, int q_high,
211*77c1e3ccSAndroid Build Coastguard Worker int top_index, int bottom_index) {
212*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
213*77c1e3ccSAndroid Build Coastguard Worker const RATE_CONTROL *const rc = &cpi->rc;
214*77c1e3ccSAndroid Build Coastguard Worker
215*77c1e3ccSAndroid Build Coastguard Worker av1_rc_update_rate_correction_factors(cpi, is_encode_stage, cm->width,
216*77c1e3ccSAndroid Build Coastguard Worker cm->height);
217*77c1e3ccSAndroid Build Coastguard Worker int q_regulated = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index,
218*77c1e3ccSAndroid Build Coastguard Worker top_index, cm->width, cm->height);
219*77c1e3ccSAndroid Build Coastguard Worker
220*77c1e3ccSAndroid Build Coastguard Worker int retries = 0;
221*77c1e3ccSAndroid Build Coastguard Worker while (q_regulated > q_high && retries < 10) {
222*77c1e3ccSAndroid Build Coastguard Worker av1_rc_update_rate_correction_factors(cpi, is_encode_stage, cm->width,
223*77c1e3ccSAndroid Build Coastguard Worker cm->height);
224*77c1e3ccSAndroid Build Coastguard Worker q_regulated = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index,
225*77c1e3ccSAndroid Build Coastguard Worker top_index, cm->width, cm->height);
226*77c1e3ccSAndroid Build Coastguard Worker retries++;
227*77c1e3ccSAndroid Build Coastguard Worker }
228*77c1e3ccSAndroid Build Coastguard Worker return q_regulated;
229*77c1e3ccSAndroid Build Coastguard Worker }
230*77c1e3ccSAndroid Build Coastguard Worker
231*77c1e3ccSAndroid Build Coastguard Worker /*!\brief Called after encode_with_recode_loop() has just encoded a frame.
232*77c1e3ccSAndroid Build Coastguard Worker * This function works out whether we undershot or overshot our bitrate
233*77c1e3ccSAndroid Build Coastguard Worker * target and adjusts q as appropriate. It also decides whether or not
234*77c1e3ccSAndroid Build Coastguard Worker * we need to recode the frame to get closer to the target rate.
235*77c1e3ccSAndroid Build Coastguard Worker *
236*77c1e3ccSAndroid Build Coastguard Worker * \ingroup rate_control
237*77c1e3ccSAndroid Build Coastguard Worker *
238*77c1e3ccSAndroid Build Coastguard Worker * \param[in] cpi Top-level encoder structure
239*77c1e3ccSAndroid Build Coastguard Worker * \param[out] loop Should we go around the recode loop again
240*77c1e3ccSAndroid Build Coastguard Worker * \param[in,out] q New q index value
241*77c1e3ccSAndroid Build Coastguard Worker * \param[in,out] q_low Low q index limit for this loop itteration
242*77c1e3ccSAndroid Build Coastguard Worker * \param[in,out] q_high High q index limit for this loop itteration
243*77c1e3ccSAndroid Build Coastguard Worker * \param[in] top_index Max permited new value for q index
244*77c1e3ccSAndroid Build Coastguard Worker * \param[in] bottom_index Min permited new value for q index
245*77c1e3ccSAndroid Build Coastguard Worker * \param[in,out] undershoot_seen Have we seen undershoot on this frame
246*77c1e3ccSAndroid Build Coastguard Worker * \param[in,out] overshoot_seen Have we seen overshoot on this frame
247*77c1e3ccSAndroid Build Coastguard Worker * \param[in,out] low_cr_seen Have we previously trriggered recode
248*77c1e3ccSAndroid Build Coastguard Worker * because the compression ration was less
249*77c1e3ccSAndroid Build Coastguard Worker * than a given minimum threshold.
250*77c1e3ccSAndroid Build Coastguard Worker * \param[in] loop_count Loop itterations so far.
251*77c1e3ccSAndroid Build Coastguard Worker *
252*77c1e3ccSAndroid Build Coastguard Worker */
recode_loop_update_q(AV1_COMP * const cpi,int * const loop,int * const q,int * const q_low,int * const q_high,const int top_index,const int bottom_index,int * const undershoot_seen,int * const overshoot_seen,int * const low_cr_seen,const int loop_count)253*77c1e3ccSAndroid Build Coastguard Worker static inline void recode_loop_update_q(
254*77c1e3ccSAndroid Build Coastguard Worker AV1_COMP *const cpi, int *const loop, int *const q, int *const q_low,
255*77c1e3ccSAndroid Build Coastguard Worker int *const q_high, const int top_index, const int bottom_index,
256*77c1e3ccSAndroid Build Coastguard Worker int *const undershoot_seen, int *const overshoot_seen,
257*77c1e3ccSAndroid Build Coastguard Worker int *const low_cr_seen, const int loop_count) {
258*77c1e3ccSAndroid Build Coastguard Worker AV1_COMMON *const cm = &cpi->common;
259*77c1e3ccSAndroid Build Coastguard Worker RATE_CONTROL *const rc = &cpi->rc;
260*77c1e3ccSAndroid Build Coastguard Worker PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
261*77c1e3ccSAndroid Build Coastguard Worker const RateControlCfg *const rc_cfg = &cpi->oxcf.rc_cfg;
262*77c1e3ccSAndroid Build Coastguard Worker *loop = 0;
263*77c1e3ccSAndroid Build Coastguard Worker
264*77c1e3ccSAndroid Build Coastguard Worker // Special case for overlay frame.
265*77c1e3ccSAndroid Build Coastguard Worker if (rc->is_src_frame_alt_ref &&
266*77c1e3ccSAndroid Build Coastguard Worker rc->projected_frame_size < rc->max_frame_bandwidth)
267*77c1e3ccSAndroid Build Coastguard Worker return;
268*77c1e3ccSAndroid Build Coastguard Worker
269*77c1e3ccSAndroid Build Coastguard Worker const int min_cr = rc_cfg->min_cr;
270*77c1e3ccSAndroid Build Coastguard Worker if (min_cr > 0) {
271*77c1e3ccSAndroid Build Coastguard Worker const double compression_ratio =
272*77c1e3ccSAndroid Build Coastguard Worker av1_get_compression_ratio(cm, rc->projected_frame_size >> 3);
273*77c1e3ccSAndroid Build Coastguard Worker const double target_cr = min_cr / 100.0;
274*77c1e3ccSAndroid Build Coastguard Worker if (compression_ratio < target_cr) {
275*77c1e3ccSAndroid Build Coastguard Worker *low_cr_seen = 1;
276*77c1e3ccSAndroid Build Coastguard Worker if (*q < rc->worst_quality) {
277*77c1e3ccSAndroid Build Coastguard Worker const double cr_ratio = target_cr / compression_ratio;
278*77c1e3ccSAndroid Build Coastguard Worker const int projected_q = AOMMAX(*q + 1, (int)(*q * cr_ratio * cr_ratio));
279*77c1e3ccSAndroid Build Coastguard Worker *q = AOMMIN(AOMMIN(projected_q, *q + 32), rc->worst_quality);
280*77c1e3ccSAndroid Build Coastguard Worker *q_low = AOMMAX(*q, *q_low);
281*77c1e3ccSAndroid Build Coastguard Worker *q_high = AOMMAX(*q, *q_high);
282*77c1e3ccSAndroid Build Coastguard Worker *loop = 1;
283*77c1e3ccSAndroid Build Coastguard Worker }
284*77c1e3ccSAndroid Build Coastguard Worker }
285*77c1e3ccSAndroid Build Coastguard Worker if (*low_cr_seen) return;
286*77c1e3ccSAndroid Build Coastguard Worker }
287*77c1e3ccSAndroid Build Coastguard Worker
288*77c1e3ccSAndroid Build Coastguard Worker if (cpi->ppi->level_params.keep_level_stats &&
289*77c1e3ccSAndroid Build Coastguard Worker !is_stat_generation_stage(cpi)) {
290*77c1e3ccSAndroid Build Coastguard Worker // Initialize level info. at the beginning of each sequence.
291*77c1e3ccSAndroid Build Coastguard Worker if (cm->current_frame.frame_type == KEY_FRAME &&
292*77c1e3ccSAndroid Build Coastguard Worker cpi->ppi->gf_group.refbuf_state[cpi->gf_frame_index] == REFBUF_RESET) {
293*77c1e3ccSAndroid Build Coastguard Worker av1_init_level_info(cpi);
294*77c1e3ccSAndroid Build Coastguard Worker }
295*77c1e3ccSAndroid Build Coastguard Worker const AV1LevelParams *const level_params = &cpi->ppi->level_params;
296*77c1e3ccSAndroid Build Coastguard Worker // TODO(any): currently only checking operating point 0
297*77c1e3ccSAndroid Build Coastguard Worker const AV1LevelInfo *const level_info = level_params->level_info[0];
298*77c1e3ccSAndroid Build Coastguard Worker const DECODER_MODEL *const decoder_models = level_info->decoder_models;
299*77c1e3ccSAndroid Build Coastguard Worker const AV1_LEVEL target_level = level_params->target_seq_level_idx[0];
300*77c1e3ccSAndroid Build Coastguard Worker
301*77c1e3ccSAndroid Build Coastguard Worker if (target_level < SEQ_LEVELS &&
302*77c1e3ccSAndroid Build Coastguard Worker decoder_models[target_level].status == DECODER_MODEL_OK) {
303*77c1e3ccSAndroid Build Coastguard Worker DECODER_MODEL_STATUS status = av1_decoder_model_try_smooth_buf(
304*77c1e3ccSAndroid Build Coastguard Worker cpi, rc->projected_frame_size, &decoder_models[target_level]);
305*77c1e3ccSAndroid Build Coastguard Worker
306*77c1e3ccSAndroid Build Coastguard Worker if ((status == SMOOTHING_BUFFER_UNDERFLOW ||
307*77c1e3ccSAndroid Build Coastguard Worker status == SMOOTHING_BUFFER_OVERFLOW) &&
308*77c1e3ccSAndroid Build Coastguard Worker *q < rc->worst_quality) {
309*77c1e3ccSAndroid Build Coastguard Worker *q = AOMMIN(*q + 10, rc->worst_quality);
310*77c1e3ccSAndroid Build Coastguard Worker *q_low = AOMMAX(*q, *q_low);
311*77c1e3ccSAndroid Build Coastguard Worker *q_high = AOMMAX(*q, *q_high);
312*77c1e3ccSAndroid Build Coastguard Worker *loop = 1;
313*77c1e3ccSAndroid Build Coastguard Worker return;
314*77c1e3ccSAndroid Build Coastguard Worker }
315*77c1e3ccSAndroid Build Coastguard Worker }
316*77c1e3ccSAndroid Build Coastguard Worker }
317*77c1e3ccSAndroid Build Coastguard Worker
318*77c1e3ccSAndroid Build Coastguard Worker if (rc_cfg->mode == AOM_Q) return;
319*77c1e3ccSAndroid Build Coastguard Worker
320*77c1e3ccSAndroid Build Coastguard Worker const int last_q = *q;
321*77c1e3ccSAndroid Build Coastguard Worker int frame_over_shoot_limit = 0, frame_under_shoot_limit = 0;
322*77c1e3ccSAndroid Build Coastguard Worker av1_rc_compute_frame_size_bounds(cpi, rc->this_frame_target,
323*77c1e3ccSAndroid Build Coastguard Worker &frame_under_shoot_limit,
324*77c1e3ccSAndroid Build Coastguard Worker &frame_over_shoot_limit);
325*77c1e3ccSAndroid Build Coastguard Worker if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1;
326*77c1e3ccSAndroid Build Coastguard Worker
327*77c1e3ccSAndroid Build Coastguard Worker if (cm->current_frame.frame_type == KEY_FRAME &&
328*77c1e3ccSAndroid Build Coastguard Worker p_rc->this_key_frame_forced &&
329*77c1e3ccSAndroid Build Coastguard Worker rc->projected_frame_size < rc->max_frame_bandwidth) {
330*77c1e3ccSAndroid Build Coastguard Worker int64_t kf_err;
331*77c1e3ccSAndroid Build Coastguard Worker const int64_t high_err_target = cpi->ambient_err;
332*77c1e3ccSAndroid Build Coastguard Worker const int64_t low_err_target = cpi->ambient_err >> 1;
333*77c1e3ccSAndroid Build Coastguard Worker
334*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_AV1_HIGHBITDEPTH
335*77c1e3ccSAndroid Build Coastguard Worker if (cm->seq_params->use_highbitdepth) {
336*77c1e3ccSAndroid Build Coastguard Worker kf_err = aom_highbd_get_y_sse(cpi->source, &cm->cur_frame->buf);
337*77c1e3ccSAndroid Build Coastguard Worker } else {
338*77c1e3ccSAndroid Build Coastguard Worker kf_err = aom_get_y_sse(cpi->source, &cm->cur_frame->buf);
339*77c1e3ccSAndroid Build Coastguard Worker }
340*77c1e3ccSAndroid Build Coastguard Worker #else
341*77c1e3ccSAndroid Build Coastguard Worker kf_err = aom_get_y_sse(cpi->source, &cm->cur_frame->buf);
342*77c1e3ccSAndroid Build Coastguard Worker #endif
343*77c1e3ccSAndroid Build Coastguard Worker // Prevent possible divide by zero error below for perfect KF
344*77c1e3ccSAndroid Build Coastguard Worker kf_err += !kf_err;
345*77c1e3ccSAndroid Build Coastguard Worker
346*77c1e3ccSAndroid Build Coastguard Worker // The key frame is not good enough or we can afford
347*77c1e3ccSAndroid Build Coastguard Worker // to make it better without undue risk of popping.
348*77c1e3ccSAndroid Build Coastguard Worker if ((kf_err > high_err_target &&
349*77c1e3ccSAndroid Build Coastguard Worker rc->projected_frame_size <= frame_over_shoot_limit) ||
350*77c1e3ccSAndroid Build Coastguard Worker (kf_err > low_err_target &&
351*77c1e3ccSAndroid Build Coastguard Worker rc->projected_frame_size <= frame_under_shoot_limit)) {
352*77c1e3ccSAndroid Build Coastguard Worker // Lower q_high
353*77c1e3ccSAndroid Build Coastguard Worker *q_high = AOMMAX(*q - 1, *q_low);
354*77c1e3ccSAndroid Build Coastguard Worker
355*77c1e3ccSAndroid Build Coastguard Worker // Adjust Q
356*77c1e3ccSAndroid Build Coastguard Worker *q = (int)((*q * high_err_target) / kf_err);
357*77c1e3ccSAndroid Build Coastguard Worker *q = AOMMIN(*q, (*q_high + *q_low) >> 1);
358*77c1e3ccSAndroid Build Coastguard Worker } else if (kf_err < low_err_target &&
359*77c1e3ccSAndroid Build Coastguard Worker rc->projected_frame_size >= frame_under_shoot_limit) {
360*77c1e3ccSAndroid Build Coastguard Worker // The key frame is much better than the previous frame
361*77c1e3ccSAndroid Build Coastguard Worker // Raise q_low
362*77c1e3ccSAndroid Build Coastguard Worker *q_low = AOMMIN(*q + 1, *q_high);
363*77c1e3ccSAndroid Build Coastguard Worker
364*77c1e3ccSAndroid Build Coastguard Worker // Adjust Q
365*77c1e3ccSAndroid Build Coastguard Worker *q = (int)((*q * low_err_target) / kf_err);
366*77c1e3ccSAndroid Build Coastguard Worker *q = AOMMIN(*q, (*q_high + *q_low + 1) >> 1);
367*77c1e3ccSAndroid Build Coastguard Worker }
368*77c1e3ccSAndroid Build Coastguard Worker
369*77c1e3ccSAndroid Build Coastguard Worker // Clamp Q to upper and lower limits:
370*77c1e3ccSAndroid Build Coastguard Worker *q = clamp(*q, *q_low, *q_high);
371*77c1e3ccSAndroid Build Coastguard Worker *loop = (*q != last_q);
372*77c1e3ccSAndroid Build Coastguard Worker return;
373*77c1e3ccSAndroid Build Coastguard Worker }
374*77c1e3ccSAndroid Build Coastguard Worker
375*77c1e3ccSAndroid Build Coastguard Worker if (recode_loop_test(cpi, frame_over_shoot_limit, frame_under_shoot_limit, *q,
376*77c1e3ccSAndroid Build Coastguard Worker AOMMAX(*q_high, top_index), bottom_index)) {
377*77c1e3ccSAndroid Build Coastguard Worker // Is the projected frame size out of range and are we allowed
378*77c1e3ccSAndroid Build Coastguard Worker // to attempt to recode.
379*77c1e3ccSAndroid Build Coastguard Worker
380*77c1e3ccSAndroid Build Coastguard Worker // Frame size out of permitted range:
381*77c1e3ccSAndroid Build Coastguard Worker // Update correction factor & compute new Q to try...
382*77c1e3ccSAndroid Build Coastguard Worker // Frame is too large
383*77c1e3ccSAndroid Build Coastguard Worker if (rc->projected_frame_size > rc->this_frame_target) {
384*77c1e3ccSAndroid Build Coastguard Worker // Special case if the projected size is > the max allowed.
385*77c1e3ccSAndroid Build Coastguard Worker if (*q == *q_high &&
386*77c1e3ccSAndroid Build Coastguard Worker rc->projected_frame_size >= rc->max_frame_bandwidth) {
387*77c1e3ccSAndroid Build Coastguard Worker const double q_val_high_current =
388*77c1e3ccSAndroid Build Coastguard Worker av1_convert_qindex_to_q(*q_high, cm->seq_params->bit_depth);
389*77c1e3ccSAndroid Build Coastguard Worker const double q_val_high_new =
390*77c1e3ccSAndroid Build Coastguard Worker q_val_high_current *
391*77c1e3ccSAndroid Build Coastguard Worker ((double)rc->projected_frame_size / rc->max_frame_bandwidth);
392*77c1e3ccSAndroid Build Coastguard Worker *q_high = av1_find_qindex(q_val_high_new, cm->seq_params->bit_depth,
393*77c1e3ccSAndroid Build Coastguard Worker rc->best_quality, rc->worst_quality);
394*77c1e3ccSAndroid Build Coastguard Worker }
395*77c1e3ccSAndroid Build Coastguard Worker
396*77c1e3ccSAndroid Build Coastguard Worker // Raise Qlow as to at least the current value
397*77c1e3ccSAndroid Build Coastguard Worker *q_low = AOMMIN(*q + 1, *q_high);
398*77c1e3ccSAndroid Build Coastguard Worker
399*77c1e3ccSAndroid Build Coastguard Worker if (*undershoot_seen || loop_count > 2 ||
400*77c1e3ccSAndroid Build Coastguard Worker (loop_count == 2 && !frame_is_intra_only(cm))) {
401*77c1e3ccSAndroid Build Coastguard Worker av1_rc_update_rate_correction_factors(cpi, 1, cm->width, cm->height);
402*77c1e3ccSAndroid Build Coastguard Worker
403*77c1e3ccSAndroid Build Coastguard Worker *q = (*q_high + *q_low + 1) / 2;
404*77c1e3ccSAndroid Build Coastguard Worker } else if (loop_count == 2 && frame_is_intra_only(cm)) {
405*77c1e3ccSAndroid Build Coastguard Worker const int q_mid = (*q_high + *q_low + 1) / 2;
406*77c1e3ccSAndroid Build Coastguard Worker const int q_regulated = get_regulated_q_overshoot(
407*77c1e3ccSAndroid Build Coastguard Worker cpi, 1, *q_low, *q_high, top_index, bottom_index);
408*77c1e3ccSAndroid Build Coastguard Worker // Get 'q' in-between 'q_mid' and 'q_regulated' for a smooth
409*77c1e3ccSAndroid Build Coastguard Worker // transition between loop_count < 2 and loop_count > 2.
410*77c1e3ccSAndroid Build Coastguard Worker *q = (q_mid + q_regulated + 1) / 2;
411*77c1e3ccSAndroid Build Coastguard Worker } else {
412*77c1e3ccSAndroid Build Coastguard Worker *q = get_regulated_q_overshoot(cpi, 1, *q_low, *q_high, top_index,
413*77c1e3ccSAndroid Build Coastguard Worker bottom_index);
414*77c1e3ccSAndroid Build Coastguard Worker }
415*77c1e3ccSAndroid Build Coastguard Worker
416*77c1e3ccSAndroid Build Coastguard Worker *overshoot_seen = 1;
417*77c1e3ccSAndroid Build Coastguard Worker } else {
418*77c1e3ccSAndroid Build Coastguard Worker // Frame is too small
419*77c1e3ccSAndroid Build Coastguard Worker *q_high = AOMMAX(*q - 1, *q_low);
420*77c1e3ccSAndroid Build Coastguard Worker
421*77c1e3ccSAndroid Build Coastguard Worker if (*overshoot_seen || loop_count > 2 ||
422*77c1e3ccSAndroid Build Coastguard Worker (loop_count == 2 && !frame_is_intra_only(cm))) {
423*77c1e3ccSAndroid Build Coastguard Worker av1_rc_update_rate_correction_factors(cpi, 1, cm->width, cm->height);
424*77c1e3ccSAndroid Build Coastguard Worker *q = (*q_high + *q_low) / 2;
425*77c1e3ccSAndroid Build Coastguard Worker } else if (loop_count == 2 && frame_is_intra_only(cm)) {
426*77c1e3ccSAndroid Build Coastguard Worker const int q_mid = (*q_high + *q_low) / 2;
427*77c1e3ccSAndroid Build Coastguard Worker const int q_regulated = get_regulated_q_undershoot(
428*77c1e3ccSAndroid Build Coastguard Worker cpi, 1, *q_high, top_index, bottom_index);
429*77c1e3ccSAndroid Build Coastguard Worker // Get 'q' in-between 'q_mid' and 'q_regulated' for a smooth
430*77c1e3ccSAndroid Build Coastguard Worker // transition between loop_count < 2 and loop_count > 2.
431*77c1e3ccSAndroid Build Coastguard Worker *q = (q_mid + q_regulated) / 2;
432*77c1e3ccSAndroid Build Coastguard Worker
433*77c1e3ccSAndroid Build Coastguard Worker // Special case reset for qlow for constrained quality.
434*77c1e3ccSAndroid Build Coastguard Worker // This should only trigger where there is very substantial
435*77c1e3ccSAndroid Build Coastguard Worker // undershoot on a frame and the auto cq level is above
436*77c1e3ccSAndroid Build Coastguard Worker // the user passsed in value.
437*77c1e3ccSAndroid Build Coastguard Worker if (rc_cfg->mode == AOM_CQ && q_regulated < *q_low) {
438*77c1e3ccSAndroid Build Coastguard Worker *q_low = *q;
439*77c1e3ccSAndroid Build Coastguard Worker }
440*77c1e3ccSAndroid Build Coastguard Worker } else {
441*77c1e3ccSAndroid Build Coastguard Worker *q = get_regulated_q_undershoot(cpi, 1, *q_high, top_index,
442*77c1e3ccSAndroid Build Coastguard Worker bottom_index);
443*77c1e3ccSAndroid Build Coastguard Worker
444*77c1e3ccSAndroid Build Coastguard Worker // Special case reset for qlow for constrained quality.
445*77c1e3ccSAndroid Build Coastguard Worker // This should only trigger where there is very substantial
446*77c1e3ccSAndroid Build Coastguard Worker // undershoot on a frame and the auto cq level is above
447*77c1e3ccSAndroid Build Coastguard Worker // the user passsed in value.
448*77c1e3ccSAndroid Build Coastguard Worker if (rc_cfg->mode == AOM_CQ && *q < *q_low) {
449*77c1e3ccSAndroid Build Coastguard Worker *q_low = *q;
450*77c1e3ccSAndroid Build Coastguard Worker }
451*77c1e3ccSAndroid Build Coastguard Worker }
452*77c1e3ccSAndroid Build Coastguard Worker
453*77c1e3ccSAndroid Build Coastguard Worker *undershoot_seen = 1;
454*77c1e3ccSAndroid Build Coastguard Worker }
455*77c1e3ccSAndroid Build Coastguard Worker
456*77c1e3ccSAndroid Build Coastguard Worker // Clamp Q to upper and lower limits:
457*77c1e3ccSAndroid Build Coastguard Worker *q = clamp(*q, *q_low, *q_high);
458*77c1e3ccSAndroid Build Coastguard Worker }
459*77c1e3ccSAndroid Build Coastguard Worker
460*77c1e3ccSAndroid Build Coastguard Worker *loop = (*q != last_q);
461*77c1e3ccSAndroid Build Coastguard Worker }
462*77c1e3ccSAndroid Build Coastguard Worker #endif
463*77c1e3ccSAndroid Build Coastguard Worker
464*77c1e3ccSAndroid Build Coastguard Worker #ifdef __cplusplus
465*77c1e3ccSAndroid Build Coastguard Worker } // extern "C"
466*77c1e3ccSAndroid Build Coastguard Worker #endif
467*77c1e3ccSAndroid Build Coastguard Worker
468*77c1e3ccSAndroid Build Coastguard Worker #endif // AOM_AV1_ENCODER_RC_UTILS_H_
469