summaryrefslogtreecommitdiff
path: root/vp9
diff options
context:
space:
mode:
Diffstat (limited to 'vp9')
-rw-r--r--vp9/encoder/vp9_encoder.c55
-rw-r--r--vp9/encoder/vp9_encoder.h8
-rw-r--r--vp9/encoder/vp9_ratectrl.c22
-rw-r--r--vp9/encoder/vp9_ratectrl.h3
-rw-r--r--vp9/ratectrl_rtc.cc173
-rw-r--r--vp9/ratectrl_rtc.h116
6 files changed, 341 insertions, 36 deletions
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 <new>
+
+#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> VP9RateControlRTC::Create(
+ const VP9RateControlRtcConfig &cfg) {
+ std::unique_ptr<VP9RateControlRTC> rc_api(new (std::nothrow)
+ VP9RateControlRTC());
+ if (!rc_api) return nullptr;
+ rc_api->cpi_ = static_cast<VP9_COMP *>(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 <cstdint>
+#include <memory>
+
+#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<VP9RateControlRTC> 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_