From 745979bc2913b4f26847084699d9fddd68b60410 Mon Sep 17 00:00:00 2001 From: Jerome Jiang Date: Tue, 24 Mar 2020 15:13:59 -0700 Subject: vp9: add rate control interface for RTC Add vp9 RTC rate control without creating encoder, to allow external codecs to use vp9 rate control. A new library (libvp9rc.a) will be built. Applications using this interface must be linked with the library. BUG=1060775 Change-Id: Ib3e597256725a37d2d104e1e1a1733c469991b03 --- vp9/encoder/vp9_encoder.c | 55 +++++++------- vp9/encoder/vp9_encoder.h | 8 +++ vp9/encoder/vp9_ratectrl.c | 22 +++--- vp9/encoder/vp9_ratectrl.h | 3 + vp9/ratectrl_rtc.cc | 173 +++++++++++++++++++++++++++++++++++++++++++++ vp9/ratectrl_rtc.h | 116 ++++++++++++++++++++++++++++++ 6 files changed, 341 insertions(+), 36 deletions(-) create mode 100644 vp9/ratectrl_rtc.cc create mode 100644 vp9/ratectrl_rtc.h (limited to 'vp9') diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index b15d5f59c..f90aee072 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -1523,8 +1523,29 @@ static void init_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) { vp9_noise_estimate_init(&cpi->noise_estimate, cm->width, cm->height); } -static void set_rc_buffer_sizes(RATE_CONTROL *rc, - const VP9EncoderConfig *oxcf) { +void vp9_check_reset_rc_flag(VP9_COMP *cpi) { + RATE_CONTROL *rc = &cpi->rc; + + if (cpi->common.current_video_frame > + (unsigned int)cpi->svc.number_spatial_layers) { + if (cpi->use_svc) { + vp9_svc_check_reset_layer_rc_flag(cpi); + } else { + if (rc->avg_frame_bandwidth > (3 * rc->last_avg_frame_bandwidth >> 1) || + rc->avg_frame_bandwidth < (rc->last_avg_frame_bandwidth >> 1)) { + rc->rc_1_frame = 0; + rc->rc_2_frame = 0; + rc->bits_off_target = rc->optimal_buffer_level; + rc->buffer_level = rc->optimal_buffer_level; + } + } + } +} + +void vp9_set_rc_buffer_sizes(VP9_COMP *cpi) { + RATE_CONTROL *rc = &cpi->rc; + const VP9EncoderConfig *oxcf = &cpi->oxcf; + const int64_t bandwidth = oxcf->target_bandwidth; const int64_t starting = oxcf->starting_buffer_level_ms; const int64_t optimal = oxcf->optimal_buffer_level_ms; @@ -1535,6 +1556,11 @@ static void set_rc_buffer_sizes(RATE_CONTROL *rc, (optimal == 0) ? bandwidth / 8 : optimal * bandwidth / 1000; rc->maximum_buffer_size = (maximum == 0) ? bandwidth / 8 : maximum * bandwidth / 1000; + + // Under a configuration change, where maximum_buffer_size may change, + // keep buffer level clipped to the maximum allowed buffer size. + rc->bits_off_target = VPXMIN(rc->bits_off_target, rc->maximum_buffer_size); + rc->buffer_level = VPXMIN(rc->buffer_level, rc->maximum_buffer_size); } #if CONFIG_VP9_HIGHBITDEPTH @@ -1991,12 +2017,7 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) { } cpi->encode_breakout = cpi->oxcf.encode_breakout; - set_rc_buffer_sizes(rc, &cpi->oxcf); - - // Under a configuration change, where maximum_buffer_size may change, - // keep buffer level clipped to the maximum allowed buffer size. - rc->bits_off_target = VPXMIN(rc->bits_off_target, rc->maximum_buffer_size); - rc->buffer_level = VPXMIN(rc->buffer_level, rc->maximum_buffer_size); + vp9_set_rc_buffer_sizes(cpi); // Set up frame rate and related parameters rate control values. vp9_new_framerate(cpi, cpi->framerate); @@ -2057,23 +2078,7 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) { (int)cpi->oxcf.target_bandwidth); } - // Check for resetting the rc flags (rc_1_frame, rc_2_frame) if the - // configuration change has a large change in avg_frame_bandwidth. - // For SVC check for resetting based on spatial layer average bandwidth. - // Also reset buffer level to optimal level. - if (cm->current_video_frame > (unsigned int)cpi->svc.number_spatial_layers) { - if (cpi->use_svc) { - vp9_svc_check_reset_layer_rc_flag(cpi); - } else { - if (rc->avg_frame_bandwidth > (3 * rc->last_avg_frame_bandwidth >> 1) || - rc->avg_frame_bandwidth < (rc->last_avg_frame_bandwidth >> 1)) { - rc->rc_1_frame = 0; - rc->rc_2_frame = 0; - rc->bits_off_target = rc->optimal_buffer_level; - rc->buffer_level = rc->optimal_buffer_level; - } - } - } + vp9_check_reset_rc_flag(cpi); cpi->alt_ref_source = NULL; rc->is_src_frame_alt_ref = 0; diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index a237b74f9..1a25a496e 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -1000,6 +1000,14 @@ int vp9_set_size_literal(VP9_COMP *cpi, unsigned int width, void vp9_set_svc(VP9_COMP *cpi, int use_svc); +// Check for resetting the rc flags (rc_1_frame, rc_2_frame) if the +// configuration change has a large change in avg_frame_bandwidth. +// For SVC check for resetting based on spatial layer average bandwidth. +// Also reset buffer level to optimal level. +void vp9_check_reset_rc_flag(VP9_COMP *cpi); + +void vp9_set_rc_buffer_sizes(VP9_COMP *cpi); + static INLINE int stack_pop(int *stack, int stack_size) { int idx; const int r = stack[0]; diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index ef64cc6c5..5dd745f3a 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -249,7 +249,7 @@ int vp9_rc_clamp_iframe_target_size(const VP9_COMP *const cpi, int target) { // way for CBR mode, for the buffering updates below. Look into removing one // of these (i.e., bits_off_target). // Update the buffer level before encoding with the per-frame-bandwidth, -static void update_buffer_level_preencode(VP9_COMP *cpi) { +void vp9_update_buffer_level_preencode(VP9_COMP *cpi) { RATE_CONTROL *const rc = &cpi->rc; rc->bits_off_target += rc->avg_frame_bandwidth; // Clip the buffer level to the maximum specified buffer size. @@ -2098,7 +2098,7 @@ void vp9_rc_get_one_pass_vbr_params(VP9_COMP *cpi) { vp9_cyclic_refresh_update_parameters(cpi); } -static int calc_pframe_target_size_one_pass_cbr(const VP9_COMP *cpi) { +int vp9_calc_pframe_target_size_one_pass_cbr(const VP9_COMP *cpi) { const VP9EncoderConfig *oxcf = &cpi->oxcf; const RATE_CONTROL *rc = &cpi->rc; const SVC *const svc = &cpi->svc; @@ -2147,7 +2147,7 @@ static int calc_pframe_target_size_one_pass_cbr(const VP9_COMP *cpi) { return VPXMAX(min_frame_target, target); } -static int calc_iframe_target_size_one_pass_cbr(const VP9_COMP *cpi) { +int vp9_calc_iframe_target_size_one_pass_cbr(const VP9_COMP *cpi) { const RATE_CONTROL *rc = &cpi->rc; const VP9EncoderConfig *oxcf = &cpi->oxcf; const SVC *const svc = &cpi->svc; @@ -2253,7 +2253,7 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { cpi->ref_frame_flags &= (~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG); // Assumption here is that LAST_FRAME is being updated for a keyframe. // Thus no change in update flags. - target = calc_iframe_target_size_one_pass_cbr(cpi); + target = vp9_calc_iframe_target_size_one_pass_cbr(cpi); } } else { cm->frame_type = INTER_FRAME; @@ -2266,7 +2266,7 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { (svc->spatial_layer_id == 0 && cm->current_video_frame > 0) ? 0 : svc->layer_context[svc->temporal_layer_id].is_key_frame; - target = calc_pframe_target_size_one_pass_cbr(cpi); + target = vp9_calc_pframe_target_size_one_pass_cbr(cpi); } } @@ -2275,7 +2275,7 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { svc->layer_context[layer].is_key_frame == 1) { cm->frame_type = KEY_FRAME; cpi->ref_frame_flags &= (~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG); - target = calc_iframe_target_size_one_pass_cbr(cpi); + target = vp9_calc_iframe_target_size_one_pass_cbr(cpi); } // Set the buffer idx and refresh flags for key frames in simulcast mode. // Note the buffer slot for long-term reference is set below (line 2255), @@ -2360,7 +2360,7 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) { } if (svc->set_intra_only_frame) { set_intra_only_frame(cpi); - target = calc_iframe_target_size_one_pass_cbr(cpi); + target = vp9_calc_iframe_target_size_one_pass_cbr(cpi); } // Any update/change of global cyclic refresh parameters (amount/delta-qp) // should be done here, before the frame qp is selected. @@ -2433,13 +2433,13 @@ void vp9_rc_get_one_pass_cbr_params(VP9_COMP *cpi) { vp9_cyclic_refresh_update_parameters(cpi); if (frame_is_intra_only(cm)) - target = calc_iframe_target_size_one_pass_cbr(cpi); + target = vp9_calc_iframe_target_size_one_pass_cbr(cpi); else - target = calc_pframe_target_size_one_pass_cbr(cpi); + target = vp9_calc_pframe_target_size_one_pass_cbr(cpi); vp9_rc_set_frame_target(cpi, target); - if (cm->show_frame) update_buffer_level_preencode(cpi); + if (cm->show_frame) vp9_update_buffer_level_preencode(cpi); if (cpi->oxcf.resize_mode == RESIZE_DYNAMIC) cpi->resize_pending = vp9_resize_one_pass_cbr(cpi); @@ -2742,7 +2742,7 @@ int vp9_resize_one_pass_cbr(VP9_COMP *cpi) { // Reset buffer level to optimal, update target size. rc->buffer_level = rc->optimal_buffer_level; rc->bits_off_target = rc->optimal_buffer_level; - rc->this_frame_target = calc_pframe_target_size_one_pass_cbr(cpi); + rc->this_frame_target = vp9_calc_pframe_target_size_one_pass_cbr(cpi); // Get the projected qindex, based on the scaled target frame size (scaled // so target_bits_per_mb in vp9_rc_regulate_q will be correct target). target_bits_per_frame = (resize_action >= 0) diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h index fa070f9be..c5ffb153c 100644 --- a/vp9/encoder/vp9_ratectrl.h +++ b/vp9/encoder/vp9_ratectrl.h @@ -252,6 +252,9 @@ int vp9_rc_get_default_max_gf_interval(double framerate, int min_gf_interval); // encode_frame_to_data_rate() function. void vp9_rc_get_one_pass_vbr_params(struct VP9_COMP *cpi); void vp9_rc_get_one_pass_cbr_params(struct VP9_COMP *cpi); +int vp9_calc_pframe_target_size_one_pass_cbr(const struct VP9_COMP *cpi); +int vp9_calc_iframe_target_size_one_pass_cbr(const struct VP9_COMP *cpi); +void vp9_update_buffer_level_preencode(struct VP9_COMP *cpi); void vp9_rc_get_svc_params(struct VP9_COMP *cpi); // Post encode update of the rate control parameters based diff --git a/vp9/ratectrl_rtc.cc b/vp9/ratectrl_rtc.cc new file mode 100644 index 000000000..3d6afc5d0 --- /dev/null +++ b/vp9/ratectrl_rtc.cc @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2020 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "vp9/ratectrl_rtc.h" + +#include + +#include "vp9/encoder/vp9_encoder.h" +#include "vp9/encoder/vp9_picklpf.h" +#include "vpx/vp8cx.h" +#include "vpx/vpx_codec.h" + +namespace libvpx { + +std::unique_ptr VP9RateControlRTC::Create( + const VP9RateControlRtcConfig &cfg) { + std::unique_ptr rc_api(new (std::nothrow) + VP9RateControlRTC()); + if (!rc_api) return nullptr; + rc_api->cpi_ = static_cast(vpx_memalign(32, sizeof(*cpi_))); + if (rc_api->cpi_ == nullptr) { + return nullptr; + } + rc_api->InitRateControl(cfg); + return rc_api; +} + +void VP9RateControlRTC::InitRateControl(const VP9RateControlRtcConfig &rc_cfg) { + VP9_COMMON *cm = &cpi_->common; + VP9EncoderConfig *oxcf = &cpi_->oxcf; + RATE_CONTROL *const rc = &cpi_->rc; + cm->profile = PROFILE_0; + cm->bit_depth = VPX_BITS_8; + cm->show_frame = 1; + oxcf->rc_mode = VPX_CBR; + oxcf->pass = 0; + oxcf->aq_mode = NO_AQ; + oxcf->content = VP9E_CONTENT_DEFAULT; + oxcf->drop_frames_water_mark = 0; + + UpdateRateControl(rc_cfg); + + cpi_->use_svc = (cpi_->svc.number_spatial_layers > 1 || + cpi_->svc.number_temporal_layers > 1) + ? 1 + : 0; + + rc->rc_1_frame = 0; + rc->rc_2_frame = 0; + vp9_rc_init_minq_luts(); + vp9_rc_init(oxcf, 0, rc); + cpi_->sf.use_nonrd_pick_mode = 1; + cm->current_video_frame = 0; +} + +void VP9RateControlRTC::UpdateRateControl( + const VP9RateControlRtcConfig &rc_cfg) { + VP9_COMMON *cm = &cpi_->common; + VP9EncoderConfig *oxcf = &cpi_->oxcf; + RATE_CONTROL *const rc = &cpi_->rc; + + cm->width = rc_cfg.width; + cm->height = rc_cfg.height; + oxcf->width = rc_cfg.width; + oxcf->height = rc_cfg.height; + oxcf->worst_allowed_q = vp9_quantizer_to_qindex(rc_cfg.max_quantizer); + oxcf->best_allowed_q = vp9_quantizer_to_qindex(rc_cfg.min_quantizer); + rc->worst_quality = oxcf->worst_allowed_q; + rc->best_quality = oxcf->best_allowed_q; + oxcf->target_bandwidth = 1000 * rc_cfg.target_bandwidth; + oxcf->starting_buffer_level_ms = rc_cfg.buf_initial_sz; + oxcf->optimal_buffer_level_ms = rc_cfg.buf_optimal_sz; + oxcf->maximum_buffer_size_ms = rc_cfg.buf_sz; + oxcf->under_shoot_pct = rc_cfg.undershoot_pct; + oxcf->over_shoot_pct = rc_cfg.overshoot_pct; + oxcf->ss_number_layers = rc_cfg.ss_number_layers; + oxcf->ts_number_layers = rc_cfg.ts_number_layers; + oxcf->temporal_layering_mode = (VP9E_TEMPORAL_LAYERING_MODE)( + (rc_cfg.ts_number_layers > 1) ? rc_cfg.ts_number_layers : 0); + + cpi_->oxcf.rc_max_intra_bitrate_pct = rc_cfg.max_intra_bitrate_pct; + cpi_->framerate = rc_cfg.framerate; + cpi_->svc.number_spatial_layers = rc_cfg.ss_number_layers; + cpi_->svc.number_temporal_layers = rc_cfg.ts_number_layers; + + for (int sl = 0; sl < cpi_->svc.number_spatial_layers; ++sl) { + for (int tl = 0; tl < cpi_->svc.number_temporal_layers; ++tl) { + const int layer = + LAYER_IDS_TO_IDX(sl, tl, cpi_->svc.number_temporal_layers); + LAYER_CONTEXT *lc = &cpi_->svc.layer_context[layer]; + RATE_CONTROL *const lrc = &lc->rc; + oxcf->layer_target_bitrate[layer] = + 1000 * rc_cfg.layer_target_bitrate[layer]; + lrc->worst_quality = + vp9_quantizer_to_qindex(rc_cfg.max_quantizers[layer]); + lrc->best_quality = vp9_quantizer_to_qindex(rc_cfg.min_quantizers[layer]); + lc->scaling_factor_num = rc_cfg.scaling_factor_num[sl]; + lc->scaling_factor_den = rc_cfg.scaling_factor_den[sl]; + oxcf->ts_rate_decimator[tl] = rc_cfg.ts_rate_decimator[tl]; + } + } + vp9_set_rc_buffer_sizes(cpi_); + vp9_new_framerate(cpi_, cpi_->framerate); + if (cpi_->svc.number_temporal_layers > 1) { + if (cm->current_video_frame == 0) vp9_init_layer_context(cpi_); + vp9_update_layer_context_change_config(cpi_, + (int)cpi_->oxcf.target_bandwidth); + } + vp9_check_reset_rc_flag(cpi_); +} + +void VP9RateControlRTC::ComputeQP(const VP9FrameParamsQpRTC &frame_params) { + VP9_COMMON *const cm = &cpi_->common; + int width, height; + cpi_->svc.spatial_layer_id = frame_params.spatial_layer_id; + cpi_->svc.temporal_layer_id = frame_params.temporal_layer_id; + if (cpi_->svc.number_spatial_layers > 1) { + const int layer = LAYER_IDS_TO_IDX(cpi_->svc.spatial_layer_id, + cpi_->svc.temporal_layer_id, + cpi_->svc.number_temporal_layers); + LAYER_CONTEXT *lc = &cpi_->svc.layer_context[layer]; + get_layer_resolution(cpi_->oxcf.width, cpi_->oxcf.height, + lc->scaling_factor_num, lc->scaling_factor_den, &width, + &height); + cm->width = width; + cm->height = height; + } + vp9_set_mb_mi(cm, cm->width, cm->height); + cm->frame_type = frame_params.frame_type; + cpi_->refresh_golden_frame = (cm->frame_type == KEY_FRAME) ? 1 : 0; + cpi_->sf.use_nonrd_pick_mode = 1; + if (cpi_->svc.number_spatial_layers == 1 && + cpi_->svc.number_temporal_layers == 1) { + int target; + if (frame_is_intra_only(cm)) + target = vp9_calc_iframe_target_size_one_pass_cbr(cpi_); + else + target = vp9_calc_pframe_target_size_one_pass_cbr(cpi_); + vp9_rc_set_frame_target(cpi_, target); + vp9_update_buffer_level_preencode(cpi_); + } else { + vp9_update_temporal_layer_framerate(cpi_); + vp9_restore_layer_context(cpi_); + vp9_rc_get_svc_params(cpi_); + } + int bottom_index, top_index; + cpi_->common.base_qindex = + vp9_rc_pick_q_and_bounds(cpi_, &bottom_index, &top_index); +} + +int VP9RateControlRTC::GetQP() const { return cpi_->common.base_qindex; } + +int VP9RateControlRTC::GetLoopfilterLevel() const { + struct loopfilter *const lf = &cpi_->common.lf; + vp9_pick_filter_level(NULL, cpi_, LPF_PICK_FROM_Q); + return lf->filter_level; +} + +void VP9RateControlRTC::PostEncodeUpdate(uint64_t encoded_frame_size) { + vp9_rc_postencode_update(cpi_, encoded_frame_size); + if (cpi_->svc.number_spatial_layers > 1 || + cpi_->svc.number_temporal_layers > 1) + vp9_save_layer_context(cpi_); + cpi_->common.current_video_frame++; +} + +} // namespace libvpx diff --git a/vp9/ratectrl_rtc.h b/vp9/ratectrl_rtc.h new file mode 100644 index 000000000..72ea40fd6 --- /dev/null +++ b/vp9/ratectrl_rtc.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2020 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef VPX_VP9_RATECTRL_RTC_H_ +#define VPX_VP9_RATECTRL_RTC_H_ + +#include +#include + +#include "vp9/common/vp9_entropymode.h" +#include "vp9/common/vp9_enums.h" +#include "vp9/common/vp9_onyxc_int.h" +#include "vp9/vp9_iface_common.h" +#include "vp9/encoder/vp9_encoder.h" +#include "vp9/encoder/vp9_firstpass.h" +#include "vp9/vp9_cx_iface.h" +#include "vpx_mem/vpx_mem.h" + +namespace libvpx { + +struct VP9RateControlRtcConfig { + int width; + int height; + // 0-63 + int max_quantizer; + int min_quantizer; + int64_t target_bandwidth; + int64_t buf_initial_sz; + int64_t buf_optimal_sz; + int64_t buf_sz; + int undershoot_pct; + int overshoot_pct; + int max_intra_bitrate_pct; + double framerate; + // Number of spatial layers + int ss_number_layers; + // Number of temporal layers + int ts_number_layers; + int max_quantizers[VPX_MAX_LAYERS]; + int min_quantizers[VPX_MAX_LAYERS]; + int scaling_factor_num[VPX_SS_MAX_LAYERS]; + int scaling_factor_den[VPX_SS_MAX_LAYERS]; + int layer_target_bitrate[VPX_MAX_LAYERS]; + int ts_rate_decimator[VPX_TS_MAX_LAYERS]; +}; + +struct VP9FrameParamsQpRTC { + FRAME_TYPE frame_type; + int spatial_layer_id; + int temporal_layer_id; +}; + +// This interface allows using VP9 real-time rate control without initializing +// the encoder. To use this interface, you need to link with libvp9rc.a. +// +// #include "vp9/ratectrl_rtc.h" +// VP9RateControlRTC rc_api; +// VP9RateControlRtcConfig cfg; +// VP9FrameParamsQpRTC frame_params; +// +// YourFunctionToInitializeConfig(cfg); +// rc_api.InitRateControl(cfg); +// // start encoding +// while (frame_to_encode) { +// if (config_changed) +// rc_api.UpdateRateControl(cfg); +// YourFunctionToFillFrameParams(frame_params); +// rc_api.ComputeQP(frame_params); +// YourFunctionToUseQP(rc_api.GetQP()); +// YourFunctionToUseLoopfilter(rc_api.GetLoopfilterLevel()); +// // After encoding +// rc_api.PostEncode(encoded_frame_size); +// } +class VP9RateControlRTC { + public: + static std::unique_ptr Create( + const VP9RateControlRtcConfig &cfg); + ~VP9RateControlRTC() { + if (cpi_) { + for (int sl = 0; sl < cpi_->svc.number_spatial_layers; sl++) { + for (int tl = 0; tl < cpi_->svc.number_temporal_layers; tl++) { + int layer = LAYER_IDS_TO_IDX(sl, tl, cpi_->oxcf.ts_number_layers); + LAYER_CONTEXT *const lc = &cpi_->svc.layer_context[layer]; + vpx_free(lc->map); + vpx_free(lc->last_coded_q_map); + vpx_free(lc->consec_zero_mv); + } + } + vpx_free(cpi_); + } + } + + void UpdateRateControl(const VP9RateControlRtcConfig &rc_cfg); + // GetQP() needs to be called after ComputeQP() to get the latest QP + int GetQP() const; + int GetLoopfilterLevel() const; + void ComputeQP(const VP9FrameParamsQpRTC &frame_params); + // Feedback to rate control with the size of current encoded frame + void PostEncodeUpdate(uint64_t encoded_frame_size); + + private: + VP9RateControlRTC() {} + void InitRateControl(const VP9RateControlRtcConfig &cfg); + VP9_COMP *cpi_; +}; + +} // namespace libvpx + +#endif // VPX_VP9_RATECTRL_RTC_H_ -- cgit v1.2.3