summaryrefslogtreecommitdiff
path: root/vp9
diff options
context:
space:
mode:
authorCheng Chen <chengchen@google.com>2022-05-13 13:42:28 -0700
committerCheng Chen <chengchen@google.com>2022-05-27 15:02:32 -0700
commit3e7685cf621af3e876274f7be9fef83e3d35de3d (patch)
treed9633825c49e5cd84a7886b780a83a2f9000f128 /vp9
parent4832bcff20d34ed25a771f3704cfe0a046dbd0f9 (diff)
downloadlibvpx-3e7685cf621af3e876274f7be9fef83e3d35de3d.tar
libvpx-3e7685cf621af3e876274f7be9fef83e3d35de3d.tar.gz
libvpx-3e7685cf621af3e876274f7be9fef83e3d35de3d.tar.bz2
libvpx-3e7685cf621af3e876274f7be9fef83e3d35de3d.zip
L2E: Add vp9 GOP decision helper function
Add a helper function to call the external rate control model. The helper function is placed in the function where vp9 determines GOP decisions. The helper function passes frame information, including current frame show index, coding index, etc to the external rate control model, and then receives GOP decisions. The received GOP decisions overwrites the default GOP decision, only when the external rate control model is set to be active via the codec control. The decision should satisfy a few constraints, for example, larger than min_gf_interval; smaller than max_gf_interval. Otherwise, return error. Unit tests are added to test the new functionality. Change-Id: Id129b4e1a91c844ee5c356a7801c862b1130a3d8
Diffstat (limited to 'vp9')
-rw-r--r--vp9/encoder/vp9_encoder.c8
-rw-r--r--vp9/encoder/vp9_ext_ratectrl.c33
-rw-r--r--vp9/encoder/vp9_ext_ratectrl.h4
-rw-r--r--vp9/encoder/vp9_firstpass.c32
-rw-r--r--vp9/encoder/vp9_ratectrl.h4
5 files changed, 77 insertions, 4 deletions
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index 89b7c8e24..6d807b8ab 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -4488,7 +4488,8 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest
}
}
#endif // CONFIG_RATE_CTRL
- if (cpi->ext_ratectrl.ready && !ext_rc_recode) {
+ if (cpi->ext_ratectrl.ready && !ext_rc_recode &&
+ cpi->ext_ratectrl.funcs.rc_type == VPX_RC_QP) {
vpx_codec_err_t codec_status;
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
vpx_rc_encodeframe_decision_t encode_frame_decision;
@@ -4548,7 +4549,8 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest
if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1;
}
- if (cpi->ext_ratectrl.ready) {
+ if (cpi->ext_ratectrl.ready &&
+ cpi->ext_ratectrl.funcs.rc_type == VPX_RC_QP) {
last_q_attempt = q;
// In general, for the external rate control, we take the qindex provided
// as input and encode the frame with this qindex faithfully. However,
@@ -5590,7 +5592,7 @@ static void encode_frame_to_data_rate(
// build the bitstream
vp9_pack_bitstream(cpi, dest, size);
- {
+ if (cpi->ext_ratectrl.ready) {
const RefCntBuffer *coded_frame_buf =
get_ref_cnt_buffer(cm, cm->new_fb_idx);
vpx_codec_err_t codec_status = vp9_extrc_update_encodeframe_result(
diff --git a/vp9/encoder/vp9_ext_ratectrl.c b/vp9/encoder/vp9_ext_ratectrl.c
index 67f58329c..48c90913e 100644
--- a/vp9/encoder/vp9_ext_ratectrl.c
+++ b/vp9/encoder/vp9_ext_ratectrl.c
@@ -172,7 +172,7 @@ vpx_codec_err_t vp9_extrc_update_encodeframe_result(
if (ext_ratectrl == NULL) {
return VPX_CODEC_INVALID_PARAM;
}
- if (ext_ratectrl->ready && ext_ratectrl->funcs.rc_type == VPX_RC_QP) {
+ if (ext_ratectrl->ready) {
PSNR_STATS psnr;
vpx_rc_status_t rc_status;
vpx_rc_encodeframe_result_t encode_frame_result;
@@ -198,3 +198,34 @@ vpx_codec_err_t vp9_extrc_update_encodeframe_result(
}
return VPX_CODEC_OK;
}
+
+vpx_codec_err_t vp9_extrc_get_gop_decision(
+ EXT_RATECTRL *ext_ratectrl, const vpx_rc_gop_info_t *const gop_info,
+ vpx_rc_gop_decision_t *gop_decision) {
+ if (ext_ratectrl == NULL) {
+ return VPX_CODEC_INVALID_PARAM;
+ }
+ if (ext_ratectrl->ready && ext_ratectrl->funcs.rc_type == VPX_RC_GOP) {
+ vpx_rc_status_t rc_status;
+ rc_status = ext_ratectrl->funcs.get_gop_decision(ext_ratectrl->model,
+ gop_info, gop_decision);
+ if (gop_decision->use_alt_ref) {
+ const int arf_constraint =
+ gop_decision->gop_coding_frames >= gop_info->min_gf_interval &&
+ gop_decision->gop_coding_frames < gop_info->lag_in_frames;
+ if (!arf_constraint || !gop_info->allow_alt_ref) return VPX_CODEC_ERROR;
+ }
+ // TODO(chengchen): Take min and max gf interval from the model
+ // and overwrite libvpx's decision so that we can get rid
+ // of one of the checks here.
+ if (gop_decision->gop_coding_frames > gop_info->frames_to_key ||
+ gop_decision->gop_coding_frames - gop_decision->use_alt_ref >
+ gop_info->max_gf_interval) {
+ return VPX_CODEC_ERROR;
+ }
+ if (rc_status == VPX_RC_ERROR) {
+ return VPX_CODEC_ERROR;
+ }
+ }
+ return VPX_CODEC_OK;
+}
diff --git a/vp9/encoder/vp9_ext_ratectrl.h b/vp9/encoder/vp9_ext_ratectrl.h
index 74fd68b96..b46b776b9 100644
--- a/vp9/encoder/vp9_ext_ratectrl.h
+++ b/vp9/encoder/vp9_ext_ratectrl.h
@@ -45,4 +45,8 @@ vpx_codec_err_t vp9_extrc_update_encodeframe_result(
const YV12_BUFFER_CONFIG *coded_frame, uint32_t bit_depth,
uint32_t input_bit_depth, const int actual_encoding_qindex);
+vpx_codec_err_t vp9_extrc_get_gop_decision(
+ EXT_RATECTRL *ext_ratectrl, const vpx_rc_gop_info_t *const gop_info,
+ vpx_rc_gop_decision_t *gop_decision);
+
#endif // VPX_VP9_ENCODER_VP9_EXT_RATECTRL_H_
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index 67302ed03..6e1f797f4 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -2714,6 +2714,9 @@ static void define_gf_group(VP9_COMP *cpi, int gf_start_show_idx) {
// frame in which case it will already have been done.
if (is_key_frame == 0) {
vp9_zero(twopass->gf_group);
+ ++rc->gop_id;
+ } else {
+ rc->gop_id = 0;
}
vpx_clear_system_state();
@@ -2751,6 +2754,35 @@ static void define_gf_group(VP9_COMP *cpi, int gf_start_show_idx) {
}
}
#endif
+ // If the external rate control model for GOP is used, the gop decisions
+ // are overwritten. Specifically, |gop_coding_frames| and |use_alt_ref|
+ // will be overwritten.
+ if (cpi->ext_ratectrl.ready &&
+ cpi->ext_ratectrl.funcs.rc_type == VPX_RC_GOP) {
+ vpx_codec_err_t codec_status;
+ vpx_rc_gop_decision_t gop_decision;
+ vpx_rc_gop_info_t gop_info;
+ gop_info.min_gf_interval = active_gf_interval.min;
+ gop_info.max_gf_interval = active_gf_interval.max;
+ gop_info.allow_alt_ref = allow_alt_ref;
+ gop_info.is_key_frame = is_key_frame;
+ gop_info.last_gop_use_alt_ref = rc->source_alt_ref_active;
+ gop_info.frames_since_key = rc->frames_since_key;
+ gop_info.frames_to_key = rc->frames_to_key;
+ gop_info.lag_in_frames = cpi->oxcf.lag_in_frames;
+ gop_info.show_index = cm->current_video_frame;
+ gop_info.coding_index = cm->current_frame_coding_index;
+ gop_info.gop_id = rc->gop_id;
+
+ codec_status = vp9_extrc_get_gop_decision(&cpi->ext_ratectrl, &gop_info,
+ &gop_decision);
+ if (codec_status != VPX_CODEC_OK) {
+ vpx_internal_error(&cm->error, codec_status,
+ "vp9_extrc_get_gop_decision() failed");
+ }
+ gop_coding_frames = gop_decision.gop_coding_frames;
+ use_alt_ref = gop_decision.use_alt_ref;
+ }
// Was the group length constrained by the requirement for a new KF?
rc->constrained_gf_group = (gop_coding_frames >= rc->frames_to_key) ? 1 : 0;
diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h
index 83a12cde7..42547d1a6 100644
--- a/vp9/encoder/vp9_ratectrl.h
+++ b/vp9/encoder/vp9_ratectrl.h
@@ -211,6 +211,10 @@ typedef struct {
// Flag to constrain golden frame interval on key frame frequency for 1 pass
// VBR.
int constrain_gf_key_freq_onepass_vbr;
+
+ // The id of the current GOP. Start from zero.
+ // When a key frame is inserted, it resets to zero.
+ int gop_id;
} RATE_CONTROL;
struct VP9_COMP;