ref: 5a4cfa95630ee3ebb5d74cd6c21336492e8707a4
parent: 7cbe65b6f4d616bfe27436b8882510e88f9fb9b0
parent: 557368a8fa9f839afd7a6ded6a95f18829ff3365
author: Cheng Chen <chengchen@google.com>
date: Wed Feb 3 18:57:00 EST 2021
Merge "L2E: let external rate control pass in a max frame size"
--- a/test/vp9_ext_ratectrl_test.cc
+++ b/test/vp9_ext_ratectrl_test.cc
@@ -128,6 +128,7 @@
} else {
frame_decision->q_index = 100;
}
+ frame_decision->max_frame_size = 0;
return VPX_RC_OK;
}
@@ -142,6 +143,11 @@
EXPECT_EQ(encode_frame_result->pixel_count, ref_pixel_count);
if (toy_rate_ctrl->coding_index == kLosslessCodingIndex) {
EXPECT_EQ(encode_frame_result->sse, 0);
+ }
+ if (toy_rate_ctrl->coding_index == kLosslessCodingIndex) {
+ EXPECT_EQ(encode_frame_result->actual_encoding_qindex, 0);
+ } else {
+ EXPECT_EQ(encode_frame_result->actual_encoding_qindex, 100);
}
return VPX_RC_OK;
}
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -4402,6 +4402,17 @@
int qrange_adj = 1;
#endif
+ // A flag which indicates whether we are recoding the current frame
+ // when the current frame size is larger than the max frame size in the
+ // external rate control model.
+ // This flag doesn't have any impact when external rate control is not used.
+ int ext_rc_recode = 0;
+ // Maximal frame size allowed by the external rate control.
+ // case: 0, we ignore the max frame size limit, and encode with the qindex
+ // passed in by the external rate control model.
+ // case: -1, we take VP9's decision for the max frame size.
+ int ext_rc_max_frame_size = 0;
+
#if CONFIG_RATE_CTRL
const FRAME_UPDATE_TYPE update_type =
cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index];
@@ -4507,7 +4518,7 @@
q = cpi->encode_command.external_quantize_index;
}
#endif
- if (cpi->ext_ratectrl.ready) {
+ if (cpi->ext_ratectrl.ready && !ext_rc_recode) {
vpx_codec_err_t codec_status;
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
vpx_rc_encodeframe_decision_t encode_frame_decision;
@@ -4526,6 +4537,7 @@
"vp9_extrc_get_encodeframe_decision() failed");
}
q = encode_frame_decision.q_index;
+ ext_rc_max_frame_size = encode_frame_decision.max_frame_size;
}
vp9_set_quantizer(cpi, q);
@@ -4567,7 +4579,24 @@
}
if (cpi->ext_ratectrl.ready) {
- break;
+ // In general, for the external rate control, we take the qindex provided
+ // as input and encode the frame with this qindex faithfully. However,
+ // in some extreme scenarios, the provided qindex leads to a massive
+ // overshoot of frame size. In this case, we fall back to VP9's decision
+ // to pick a new qindex and recode the frame. We return the new qindex
+ // through the API to the external model.
+ if (ext_rc_max_frame_size == 0) {
+ break;
+ } else if (ext_rc_max_frame_size == -1) {
+ if (rc->projected_frame_size < rc->max_frame_bandwidth) {
+ break;
+ }
+ } else {
+ if (rc->projected_frame_size < ext_rc_max_frame_size) {
+ break;
+ }
+ }
+ ext_rc_recode = 1;
}
#if CONFIG_RATE_CTRL
// This part needs to be after save_coding_context() because
@@ -5501,7 +5530,7 @@
get_ref_cnt_buffer(cm, cm->new_fb_idx);
vpx_codec_err_t codec_status = vp9_extrc_update_encodeframe_result(
&cpi->ext_ratectrl, (*size) << 3, cpi->Source, &coded_frame_buf->buf,
- cm->bit_depth, cpi->oxcf.input_bit_depth);
+ cm->bit_depth, cpi->oxcf.input_bit_depth, cm->base_qindex);
if (codec_status != VPX_CODEC_OK) {
vpx_internal_error(&cm->error, codec_status,
"vp9_extrc_update_encodeframe_result() failed");
--- a/vp9/encoder/vp9_ext_ratectrl.c
+++ b/vp9/encoder/vp9_ext_ratectrl.c
@@ -168,7 +168,7 @@
EXT_RATECTRL *ext_ratectrl, int64_t bit_count,
const YV12_BUFFER_CONFIG *source_frame,
const YV12_BUFFER_CONFIG *coded_frame, uint32_t bit_depth,
- uint32_t input_bit_depth) {
+ uint32_t input_bit_depth, const int actual_encoding_qindex) {
if (ext_ratectrl == NULL) {
return VPX_CODEC_INVALID_PARAM;
}
@@ -180,6 +180,7 @@
encode_frame_result.pixel_count =
source_frame->y_crop_width * source_frame->y_crop_height +
2 * source_frame->uv_crop_width * source_frame->uv_crop_height;
+ encode_frame_result.actual_encoding_qindex = actual_encoding_qindex;
#if CONFIG_VP9_HIGHBITDEPTH
vpx_calc_highbd_psnr(source_frame, coded_frame, &psnr, bit_depth,
input_bit_depth);
--- a/vp9/encoder/vp9_ext_ratectrl.h
+++ b/vp9/encoder/vp9_ext_ratectrl.h
@@ -43,6 +43,6 @@
EXT_RATECTRL *ext_ratectrl, int64_t bit_count,
const YV12_BUFFER_CONFIG *source_frame,
const YV12_BUFFER_CONFIG *coded_frame, uint32_t bit_depth,
- uint32_t input_bit_depth);
+ uint32_t input_bit_depth, int actual_encoding_qindex);
#endif // VPX_VP9_ENCODER_VP9_EXT_RATECTRL_H_
--- a/vpx/vpx_ext_ratectrl.h
+++ b/vpx/vpx_ext_ratectrl.h
@@ -38,9 +38,15 @@
*
* The encoder will receive the decision from the external rate control model
* through get_encodeframe_decision() defined in vpx_rc_funcs_t.
+ *
+ * If max_frame_size = 0, the encoding ignores max frame size limit.
+ * If max_frame_size = -1, the encoding uses VP9's max frame size as the limit.
+ * If the encoded frame size is larger than max_frame_size, the frame is
+ * recoded to meet the size limit, following VP9's recoding principles.
*/
typedef struct vpx_rc_encodeframe_decision {
- int q_index; /**< Quantizer step index [0..255]*/
+ int q_index; /**< Quantizer step index [0..255]*/
+ int max_frame_size; /**< Maximal frame size allowed to encode a frame*/
} vpx_rc_encodeframe_decision_t;
/*!\brief Information for the frame to be encoded.
@@ -82,6 +88,7 @@
int64_t sse; /**< sum of squared error of the reconstructed frame */
int64_t bit_count; /**< number of bits spent on coding the frame*/
int64_t pixel_count; /**< number of pixels in YUV planes of the frame*/
+ int actual_encoding_qindex; /**< the actual qindex used to encode the frame*/
} vpx_rc_encodeframe_result_t;
/*!\brief Status returned by rate control callback functions.