Commit 002e7b7a authored by Rostislav Pehlivanov's avatar Rostislav Pehlivanov

Implement a new rate control system

This commit implements a new rate control system which was ported from
Daala's rate control system (which was based off of Theora's rate
control system) to the encoder. Its aim is to address the weaknesses of
the current rate control system and eventually serve as its replacement.

This is still work in progress. So far this commit only implements
support for single pass encoding for constant quality and bitrate
targeting.
Additional commits which implement two-pass support and the rest to
match the feature set of the current rate control system are coming
soon.

The rate control system hasn't been fully tuned (and will likely need
additional tuning as the encoder's development progresses) and does
contain some "hacks", to convert the quality to a quantizer value
(empirical) and to tweak the quantizer in between golden frames (which
uses some code from the current rate control system as well as code
which attempts to model what that code does), the latter of which is
only in the constant quality codepath.

Bitrate targeting works much better than the current rate control
system's targeting and will actually closely match the rate specified by
the user without the current rate control system's bursty behaviour.

Change-Id: I588fbfd2e80a3d21ce7176903115d6a96ef1700a
parent ed8e2d2a
......@@ -61,6 +61,9 @@ AV1_CX_SRCS-yes += encoder/lookahead.h
AV1_CX_SRCS-yes += encoder/mcomp.h
AV1_CX_SRCS-yes += encoder/encoder.h
AV1_CX_SRCS-yes += encoder/ratectrl.h
ifeq ($(CONFIG_XIPHRC),yes)
AV1_CX_SRCS-yes += encoder/ratectrl_xiph.h
endif
AV1_CX_SRCS-yes += encoder/rd.h
AV1_CX_SRCS-yes += encoder/rdopt.h
AV1_CX_SRCS-yes += encoder/tokenize.h
......@@ -76,6 +79,9 @@ AV1_CX_SRCS-yes += encoder/picklpf.h
AV1_CX_SRCS-$(CONFIG_LOOP_RESTORATION) += encoder/pickrst.c
AV1_CX_SRCS-$(CONFIG_LOOP_RESTORATION) += encoder/pickrst.h
AV1_CX_SRCS-yes += encoder/ratectrl.c
ifeq ($(CONFIG_XIPHRC),yes)
AV1_CX_SRCS-yes += encoder/ratectrl_xiph.c
endif
AV1_CX_SRCS-yes += encoder/rd.c
AV1_CX_SRCS-yes += encoder/rdopt.c
AV1_CX_SRCS-yes += encoder/segmentation.c
......
......@@ -123,7 +123,7 @@ static struct av1_extracfg default_extra_cfg = {
#endif
1, // frame_parallel_decoding_mode
NO_AQ, // aq_mode
0, // frame_periodic_delta_q
CONFIG_XIPHRC, // frame_periodic_delta_q
AOM_BITS_8, // Bit depth
AOM_CONTENT_DEFAULT, // content
AOM_CS_UNKNOWN, // color space
......
......@@ -104,7 +104,7 @@ extern uint32_t OD_DIVU_SMALL_CONSTS[OD_DIVU_DMAX][2];
#define OD_MINI AOMMIN
#define OD_MAXI AOMMAX
#define OD_CLAMPI(min, val, max) clamp((val), (min), (max))
#define OD_CLAMPI(min, val, max) (OD_MAXI(min, OD_MINI(val, max)))
#define OD_CLZ0 (1)
#define OD_CLZ(x) (-get_msb(x))
......
......@@ -301,6 +301,34 @@ int16_t av1_ac_quant(int qindex, int delta, aom_bit_depth_t bit_depth) {
#endif
}
int16_t av1_qindex_from_ac(int ac, aom_bit_depth_t bit_depth) {
int i;
const int16_t *tab = ac_qlookup;
ac *= 4;
#if CONFIG_AOM_HIGHBITDEPTH
switch (bit_depth) {
case AOM_BITS_10: {
tab = ac_qlookup_10;
ac *= 4;
break;
}
case AOM_BITS_12: {
tab = ac_qlookup_12;
ac *= 16;
break;
}
default:
assert(0 && "bit_depth should be AOM_BITS_8, AOM_BITS_10 or AOM_BITS_12");
return -1;
}
#endif
(void)bit_depth;
for (i = 0; i < QINDEX_RANGE; i++) {
if (ac <= tab[i]) return i;
}
return QINDEX_RANGE - 1;
}
int av1_get_qindex(const struct segmentation *seg, int segment_id,
int base_qindex) {
if (segfeature_active(seg, segment_id, SEG_LVL_ALT_Q)) {
......
......@@ -40,6 +40,7 @@ struct AV1Common;
int16_t av1_dc_quant(int qindex, int delta, aom_bit_depth_t bit_depth);
int16_t av1_ac_quant(int qindex, int delta, aom_bit_depth_t bit_depth);
int16_t av1_qindex_from_ac(int ac, aom_bit_depth_t bit_depth);
int av1_get_qindex(const struct segmentation *seg, int segment_id,
int base_qindex);
......
......@@ -402,7 +402,9 @@ void av1_initialize_enc(void) {
aom_scale_rtcd();
av1_init_intra_predictors();
av1_init_me_luts();
#if !CONFIG_XIPHRC
av1_rc_init_minq_luts();
#endif
av1_entropy_mv_init();
av1_encode_token_init();
#if CONFIG_EXT_INTER
......@@ -815,7 +817,13 @@ void av1_alloc_compressor_data(AV1_COMP *cpi) {
void av1_new_framerate(AV1_COMP *cpi, double framerate) {
cpi->framerate = framerate < 0.1 ? 30 : framerate;
#if CONFIG_XIPHRC
if (!cpi->od_rc.cur_frame) return;
cpi->od_rc.framerate = cpi->framerate;
od_enc_rc_resize(&cpi->od_rc);
#else
av1_rc_update_framerate(cpi);
#endif
}
static void set_tile_info(AV1_COMP *cpi) {
......@@ -2143,7 +2151,25 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf,
cpi->common.buffer_pool = pool;
init_config(cpi, oxcf);
#if CONFIG_XIPHRC
cpi->od_rc.framerate = cpi->framerate;
cpi->od_rc.frame_width = cm->render_width;
cpi->od_rc.frame_height = cm->render_height;
cpi->od_rc.keyframe_rate = oxcf->key_freq;
cpi->od_rc.goldenframe_rate = FIXED_GF_INTERVAL;
cpi->od_rc.altref_rate = 25;
cpi->od_rc.bit_depth = cm->bit_depth;
cpi->od_rc.minq = oxcf->best_allowed_q;
cpi->od_rc.maxq = oxcf->worst_allowed_q;
if (cpi->oxcf.rc_mode == AOM_CQ) cpi->od_rc.minq = cpi->od_rc.quality;
cpi->od_rc.quality = cpi->oxcf.rc_mode == AOM_Q ? oxcf->cq_level : -1;
cpi->od_rc.periodic_boosts = oxcf->frame_periodic_boost;
od_enc_rc_init(&cpi->od_rc,
cpi->oxcf.rc_mode == AOM_Q ? -1 : oxcf->target_bandwidth,
oxcf->maximum_buffer_size_ms);
#else
av1_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc);
#endif
cm->current_video_frame = 0;
cpi->partition_search_skippable_frame = 0;
......@@ -3841,8 +3867,15 @@ static void set_size_dependent_vars(AV1_COMP *cpi, int *q, int *bottom_index,
// Setup variables that depend on the dimensions of the frame.
av1_set_speed_features_framesize_dependent(cpi);
// Decide q and q bounds.
// Decide q and q bounds.
#if CONFIG_XIPHRC
int frame_type = cm->frame_type == KEY_FRAME ? OD_I_FRAME : OD_P_FRAME;
*q = od_enc_rc_select_quantizers_and_lambdas(
&cpi->od_rc, cpi->refresh_golden_frame, cpi->refresh_alt_ref_frame,
frame_type, bottom_index, top_index);
#else
*q = av1_rc_pick_q_and_bounds(cpi, bottom_index, top_index);
#endif
if (!frame_is_intra_only(cm)) {
av1_set_high_precision_mv(cpi, (*q) < HIGH_PRECISION_MV_QTHRESH);
......@@ -4061,8 +4094,10 @@ static void encode_with_recode_loop(AV1_COMP *cpi, size_t *size,
int loop_count = 0;
int loop_at_this_size = 0;
int loop = 0;
#if !CONFIG_XIPHRC
int overshoot_seen = 0;
int undershoot_seen = 0;
#endif
int frame_over_shoot_limit;
int frame_under_shoot_limit;
int q = 0, q_low = 0, q_high = 0;
......@@ -4090,9 +4125,11 @@ static void encode_with_recode_loop(AV1_COMP *cpi, size_t *size,
// TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed.
set_mv_search_params(cpi);
#if !CONFIG_XIPHRC
// Reset the loop state for new frame size.
overshoot_seen = 0;
undershoot_seen = 0;
#endif
// Reconfiguration for change in frame size has concluded.
cpi->resize_pending = 0;
......@@ -4249,7 +4286,9 @@ static void encode_with_recode_loop(AV1_COMP *cpi, size_t *size,
// Is the projected frame size out of range and are we allowed
// to attempt to recode.
int last_q = q;
#if !CONFIG_XIPHRC
int retries = 0;
#endif
if (cpi->resize_pending == 1) {
// Change in frame size so go back around the recode loop.
......@@ -4265,9 +4304,9 @@ static void encode_with_recode_loop(AV1_COMP *cpi, size_t *size,
continue;
}
#if !CONFIG_XIPHRC
// Frame size out of permitted range:
// Update correction factor & compute new Q to try...
// Frame is too large
if (rc->projected_frame_size > rc->this_frame_target) {
// Special case if the projected size is > the max allowed.
......@@ -4327,6 +4366,7 @@ static void encode_with_recode_loop(AV1_COMP *cpi, size_t *size,
undershoot_seen = 1;
}
#endif
// Clamp Q to upper and lower limits:
q = clamp(q, q_low, q_high);
......@@ -4615,6 +4655,10 @@ static void encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
struct segmentation *const seg = &cm->seg;
TX_SIZE t;
#if CONFIG_XIPHRC
int frame_type;
int drop_this_frame = 0;
#endif
set_ext_overrides(cpi);
aom_clear_system_state();
......@@ -4684,7 +4728,14 @@ static void encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
// to do post-encoding update accordingly.
if (cpi->rc.is_src_frame_alt_ref) {
av1_set_target_rate(cpi);
#if CONFIG_XIPHRC
int frame_type = cm->frame_type == INTER_FRAME ? OD_P_FRAME : OD_I_FRAME;
drop_this_frame = od_enc_rc_update_state(
&cpi->od_rc, *size << 3, cpi->refresh_golden_frame,
cpi->refresh_alt_ref_frame, frame_type, cpi->droppable);
#else
av1_rc_postencode_update(cpi, *size);
#endif
}
cm->last_width = cm->width;
......@@ -4737,6 +4788,13 @@ static void encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
}
#endif
#if CONFIG_XIPHRC
if (drop_this_frame) {
av1_rc_postencode_update_drop_frame(cpi);
++cm->current_video_frame;
return;
}
#else
// For 1 pass CBR, check if we are dropping this frame.
// Never drop on key frame.
if (oxcf->pass == 0 && oxcf->rc_mode == AOM_CBR &&
......@@ -4747,6 +4805,7 @@ static void encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
return;
}
}
#endif
aom_clear_system_state();
......@@ -4907,7 +4966,20 @@ static void encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
cm->last_frame_type = cm->frame_type;
#if CONFIG_XIPHRC
frame_type = cm->frame_type == KEY_FRAME ? OD_I_FRAME : OD_P_FRAME;
drop_this_frame =
od_enc_rc_update_state(&cpi->od_rc, *size << 3, cpi->refresh_golden_frame,
cpi->refresh_alt_ref_frame, frame_type, 0);
if (drop_this_frame) {
av1_rc_postencode_update_drop_frame(cpi);
++cm->current_video_frame;
return;
}
#else
av1_rc_postencode_update(cpi, *size);
#endif
#if 0
output_frame_level_debug_stats(cpi);
......@@ -4953,11 +5025,38 @@ static void encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
static void Pass0Encode(AV1_COMP *cpi, size_t *size, uint8_t *dest,
unsigned int *frame_flags) {
#if CONFIG_XIPHRC
int64_t ip_count;
int frame_type, is_golden, is_altref;
/* Not updated during init so update it here */
if (cpi->oxcf.rc_mode == AOM_Q) cpi->od_rc.quality = cpi->oxcf.cq_level;
frame_type = od_frame_type(&cpi->od_rc, cpi->od_rc.cur_frame, &is_golden,
&is_altref, &ip_count);
if (frame_type == OD_I_FRAME) {
frame_type = KEY_FRAME;
cpi->frame_flags &= FRAMEFLAGS_KEY;
} else if (frame_type == OD_P_FRAME) {
frame_type = INTER_FRAME;
}
if (is_altref) {
cpi->refresh_alt_ref_frame = 1;
cpi->rc.source_alt_ref_active = 1;
}
cpi->refresh_golden_frame = is_golden;
cpi->common.frame_type = frame_type;
if (is_golden) cpi->frame_flags &= FRAMEFLAGS_GOLDEN;
#else
if (cpi->oxcf.rc_mode == AOM_CBR) {
av1_rc_get_one_pass_cbr_params(cpi);
} else {
av1_rc_get_one_pass_vbr_params(cpi);
}
#endif
encode_frame_to_data_rate(cpi, size, dest, frame_flags);
}
......@@ -5315,6 +5414,10 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
#endif // CONFIG_EXT_REFS
int i;
#if CONFIG_XIPHRC
cpi->od_rc.end_of_input = flush;
#endif
#if CONFIG_BITSTREAM_DEBUG
assert(cpi->oxcf.max_threads == 0 &&
"bitstream debug tool does not support multithreading");
......@@ -5383,7 +5486,9 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
// We need to update the gf_group for show_existing overlay frame
if (cpi->rc.is_src_frame_alt_ref) {
#if !CONFIG_XIPHRC
av1_rc_get_second_pass_params(cpi);
#endif
}
Pass2Encode(cpi, size, dest, frame_flags);
......@@ -5493,7 +5598,9 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
} else {
*size = 0;
if (flush && oxcf->pass == 1 && !cpi->twopass.first_pass_done) {
#if !CONFIG_XIPHRC
av1_end_first_pass(cpi); /* get last stats packet */
#endif
cpi->twopass.first_pass_done = 1;
}
return -1;
......@@ -5543,7 +5650,9 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
cpi->frame_flags = *frame_flags;
if (oxcf->pass == 2) {
#if !CONFIG_XIPHRC
av1_rc_get_second_pass_params(cpi);
#endif
} else if (oxcf->pass == 1) {
set_frame_size(cpi);
}
......@@ -5600,6 +5709,10 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
}
#endif // CONFIG_INTERNAL_STATS
#if CONFIG_XIPHRC
cpi->od_rc.cur_frame++;
#endif
aom_clear_system_state();
return 0;
......
......@@ -38,6 +38,9 @@
#include "av1/encoder/speed_features.h"
#include "av1/encoder/tokenize.h"
#include "av1/encoder/variance_tree.h"
#if CONFIG_XIPHRC
#include "av1/encoder/ratectrl_xiph.h"
#endif
#if CONFIG_INTERNAL_STATS
#include "aom_dsp/ssim.h"
......@@ -443,6 +446,9 @@ typedef struct AV1_COMP {
int64_t first_time_stamp_ever;
RATE_CONTROL rc;
#if CONFIG_XIPHRC
od_rc_state od_rc;
#endif
double framerate;
// NOTE(zoeliu): Any inter frame allows maximum of REF_FRAMES inter
......
This diff is collapsed.
/*
* Copyright (c) 2001-2017, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#if !defined(_ratectrl_xiph_H)
#define _ratectrl_xiph_H (1)
#include "av1/common/quant_common.h"
#include "av1/encoder/encint.h"
#include "av1/encoder/ratectrl.h"
/*Frame types.*/
#define OD_I_FRAME (0)
#define OD_P_FRAME (1)
#define OD_GOLDEN_P_FRAME (2)
#define OD_ALTREF_P_FRAME (3)
#define OD_FRAME_NSUBTYPES (OD_ALTREF_P_FRAME + 1)
/* Periodic boost (in between golden frames) strength - lower is more */
#define OD_PERIODIC_BOOST_DIV (10)
/* Constants for frame QP modulation <- tweak these
* Adjusts how the rate control system decides the quantizers per frame
* (sub)type */
#define OD_MQP_I (0.98)
#define OD_MQP_P (1.06)
#define OD_MQP_GP (0.99)
#define OD_MQP_AP (0.92)
#define OD_DQP_I (-2)
#define OD_DQP_P (0)
#define OD_DQP_GP (-2)
#define OD_DQP_AP (-2)
/*Fractional_coded_quantizer ~=
log2(quantizer / (1 << OD_COEFF_SHIFT))*6.307 + 6.235*/
/*Base/scale factor for linear quantizer to fractional coded quantizer
conversion (6.307 * 2^12) */
#define OD_LOG_QUANTIZER_BASE_Q12 (0x0064EB)
/*Inverse of above scale factor.*/
#define OD_LOG_QUANTIZER_EXP_Q12 (0x000289)
/*Offset for linear quantizer to fractional coded quantizer
conversion (6.235 * 2^45) */
#define OD_LOG_QUANTIZER_OFFSET_Q45 (0x0000C7851EB851ECLL)
/*A 2nd order low-pass Bessel follower.
We use this for rate control because it has fast reaction time, but is
critically damped.*/
typedef struct od_iir_bessel2 {
int32_t c[2];
int64_t g;
int32_t x[2];
int32_t y[2];
} od_iir_bessel2;
/*Rate control setup and working state information.*/
typedef struct od_rc_state {
/* Image format */
int frame_width;
int frame_height;
int bit_depth;
/* Framerate */
double framerate;
/* Keyframe rate */
int keyframe_rate;
/* Golden frame period */
int goldenframe_rate;
/* Altref frame period */
int altref_rate;
/*The target bit-rate in bits per second.*/
int64_t target_bitrate;
/* Quality level for non-bitrate-targeting */
int quality;
/* Copied from oxcf->frame_periodic_boost */
int periodic_boosts;
/* Max Q */
int maxq;
/* Min Q */
int minq;
/* Actual returned quantizer */
int target_quantizer;
/*The full-precision, unmodulated quantizer upon which
our modulated quantizers are based.*/
int base_quantizer;
/* Increments by 1 for each frame. */
int64_t cur_frame;
/* End of input flag */
int end_of_input;
/* Closed GOP flag */
int closed_gop;
/*The number of frames over which to distribute the reservoir usage.*/
int reservoir_frame_delay;
/*Will we drop frames to meet bitrate target?*/
unsigned char drop_frames;
/*Do we respect the maximum reservoir fullness?*/
unsigned char cap_overflow;
/*Can the reservoir go negative?*/
unsigned char cap_underflow;
/*Two-pass mode state.
0 => 1-pass encoding.
1 => 1st pass of 2-pass encoding.
2 => 2nd pass of 2-pass encoding.*/
int twopass_state;
/*The log of the number of pixels in a frame in Q57 format.*/
int64_t log_npixels;
/*The target average bits per frame.*/
int64_t bits_per_frame;
/*The current bit reservoir fullness (bits available to be used).*/
int64_t reservoir_fullness;
/*The target buffer fullness.
This is where we'd like to be by the last keyframe the appears in the next
buf_delay frames.*/
int64_t reservoir_target;
/*The maximum buffer fullness (total size of the buffer).*/
int64_t reservoir_max;
/*The log of estimated scale factor for the rate model in Q57 format.*/
int64_t log_scale[OD_FRAME_NSUBTYPES];
/*The exponent used in the rate model in Q8 format.*/
unsigned exp[OD_FRAME_NSUBTYPES];
/*The log of an estimated scale factor used to obtain the real framerate, for
VFR sources or, e.g., 12 fps content doubled to 24 fps, etc.*/
int64_t log_drop_scale[OD_FRAME_NSUBTYPES];
/*The total drop count from the previous frame.*/
uint32_t prev_drop_count[OD_FRAME_NSUBTYPES];
/*Second-order lowpass filters to track scale and VFR/drops.*/
od_iir_bessel2 scalefilter[OD_FRAME_NSUBTYPES];
od_iir_bessel2 vfrfilter[OD_FRAME_NSUBTYPES];
int frame_count[OD_FRAME_NSUBTYPES];
int inter_p_delay;
int inter_delay_target;
/*The total accumulated estimation bias.*/
int64_t rate_bias;
} od_rc_state;
int od_enc_rc_init(od_rc_state *rc, int64_t bitrate, int delay_ms);
int od_enc_rc_select_quantizers_and_lambdas(od_rc_state *rc,
int is_golden_frame,
int is_altref_frame, int frame_type,
int *bottom_idx, int *top_idx);
/* Returns 1 if the frame should be dropped */
int od_enc_rc_update_state(od_rc_state *rc, int64_t bits, int is_golden_frame,
int is_altref_frame, int frame_type, int droppable);
int od_frame_type(od_rc_state *rc, int64_t coding_frame_count, int *is_golden,
int *is_altref, int64_t *ip_count);
int od_enc_rc_resize(od_rc_state *rc);
#endif
......@@ -287,6 +287,7 @@ EXPERIMENT_LIST="
daala_ec
rawbits
pvq
xiphrc
cb4x4
frame_size
delta_q
......
Markdown is supported
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