diff options
-rw-r--r-- | test/vp9_ext_ratectrl_test.cc | 6 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.c | 35 | ||||
-rw-r--r-- | vp9/encoder/vp9_ext_ratectrl.c | 3 | ||||
-rw-r--r-- | vp9/encoder/vp9_ext_ratectrl.h | 2 | ||||
-rw-r--r-- | vpx/vpx_ext_ratectrl.h | 9 |
5 files changed, 49 insertions, 6 deletions
diff --git a/test/vp9_ext_ratectrl_test.cc b/test/vp9_ext_ratectrl_test.cc index 4b3693a34..b6b5b2eae 100644 --- a/test/vp9_ext_ratectrl_test.cc +++ b/test/vp9_ext_ratectrl_test.cc @@ -128,6 +128,7 @@ vpx_rc_status_t rc_get_encodeframe_decision( } else { frame_decision->q_index = 100; } + frame_decision->max_frame_size = 0; return VPX_RC_OK; } @@ -143,6 +144,11 @@ vpx_rc_status_t rc_update_encodeframe_result( 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; } diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 6a21a1c18..2757bc428 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -4402,6 +4402,17 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest 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 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest 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 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest "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 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest } 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 @@ static void encode_frame_to_data_rate( 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"); diff --git a/vp9/encoder/vp9_ext_ratectrl.c b/vp9/encoder/vp9_ext_ratectrl.c index a27eb653b..9f0098ab5 100644 --- a/vp9/encoder/vp9_ext_ratectrl.c +++ b/vp9/encoder/vp9_ext_ratectrl.c @@ -168,7 +168,7 @@ vpx_codec_err_t vp9_extrc_update_encodeframe_result( 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 @@ vpx_codec_err_t vp9_extrc_update_encodeframe_result( 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); diff --git a/vp9/encoder/vp9_ext_ratectrl.h b/vp9/encoder/vp9_ext_ratectrl.h index 11e9102a6..214236308 100644 --- a/vp9/encoder/vp9_ext_ratectrl.h +++ b/vp9/encoder/vp9_ext_ratectrl.h @@ -43,6 +43,6 @@ vpx_codec_err_t vp9_extrc_update_encodeframe_result( 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_ diff --git a/vpx/vpx_ext_ratectrl.h b/vpx/vpx_ext_ratectrl.h index dc4d856a8..a193e5595 100644 --- a/vpx/vpx_ext_ratectrl.h +++ b/vpx/vpx_ext_ratectrl.h @@ -38,9 +38,15 @@ typedef void *vpx_rc_model_t; * * 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 @@ typedef struct vpx_rc_encodeframe_result { 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. |