summaryrefslogtreecommitdiff
path: root/test
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 /test
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 'test')
-rw-r--r--test/vp9_ext_ratectrl_test.cc147
1 files changed, 146 insertions, 1 deletions
diff --git a/test/vp9_ext_ratectrl_test.cc b/test/vp9_ext_ratectrl_test.cc
index f6ce77845..e3e7afbf4 100644
--- a/test/vp9_ext_ratectrl_test.cc
+++ b/test/vp9_ext_ratectrl_test.cc
@@ -17,24 +17,43 @@
#include "test/yuv_video_source.h"
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "vpx/vpx_ext_ratectrl.h"
+#include "vpx_dsp/vpx_dsp_common.h"
namespace {
constexpr int kModelMagicNumber = 51396;
constexpr uintptr_t PrivMagicNumber = 5566;
constexpr int kFrameNum = 5;
+constexpr int kFrameNumGOP = 30;
constexpr int kLosslessCodingIndex = 2;
+constexpr int kFixedGOPSize = 9;
+// The range check in vp9_cx_iface.c shows that the max
+// lag in buffer is MAX_LAG_BUFFERS (25):
+// RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_LAG_BUFFERS);
+constexpr int kMaxLagInFrames = 25;
+constexpr int kDefaultMinGfInterval = 4;
+constexpr int kDefaultMaxGfInterval = 16;
+// The two pass rate control does not respect the input
+// min_gf_interval and max_gf_interval.
+// See function "get_active_gf_inverval_range".
+// The numbers below are from manual inspection.
+constexpr int kReadMinGfInterval = 5;
+constexpr int kReadMaxGfInterval = 13;
struct ToyRateCtrl {
int magic_number;
int coding_index;
+
+ int gop_id;
+ int frames_since_key;
+ int show_index;
};
vpx_rc_status_t rc_create_model(void *priv,
const vpx_rc_config_t *ratectrl_config,
vpx_rc_model_t *rate_ctrl_model_pt) {
ToyRateCtrl *toy_rate_ctrl = new (std::nothrow) ToyRateCtrl;
- EXPECT_NE(toy_rate_ctrl, nullptr);
+ if (toy_rate_ctrl == nullptr) return VPX_RC_ERROR;
toy_rate_ctrl->magic_number = kModelMagicNumber;
toy_rate_ctrl->coding_index = -1;
*rate_ctrl_model_pt = toy_rate_ctrl;
@@ -48,6 +67,27 @@ vpx_rc_status_t rc_create_model(void *priv,
return VPX_RC_OK;
}
+vpx_rc_status_t rc_create_model_gop(void *priv,
+ const vpx_rc_config_t *ratectrl_config,
+ vpx_rc_model_t *rate_ctrl_model_pt) {
+ ToyRateCtrl *toy_rate_ctrl = new (std::nothrow) ToyRateCtrl;
+ if (toy_rate_ctrl == nullptr) return VPX_RC_ERROR;
+ toy_rate_ctrl->magic_number = kModelMagicNumber;
+ toy_rate_ctrl->gop_id = 0;
+ toy_rate_ctrl->frames_since_key = 0;
+ toy_rate_ctrl->show_index = 0;
+ toy_rate_ctrl->coding_index = 0;
+ *rate_ctrl_model_pt = toy_rate_ctrl;
+ EXPECT_EQ(priv, reinterpret_cast<void *>(PrivMagicNumber));
+ EXPECT_EQ(ratectrl_config->frame_width, 640);
+ EXPECT_EQ(ratectrl_config->frame_height, 360);
+ EXPECT_EQ(ratectrl_config->show_frame_count, kFrameNumGOP);
+ EXPECT_EQ(ratectrl_config->target_bitrate_kbps, 4000);
+ EXPECT_EQ(ratectrl_config->frame_rate_num, 30);
+ EXPECT_EQ(ratectrl_config->frame_rate_den, 1);
+ return VPX_RC_OK;
+}
+
vpx_rc_status_t rc_send_firstpass_stats(
vpx_rc_model_t rate_ctrl_model,
const vpx_rc_firstpass_stats_t *first_pass_stats) {
@@ -61,6 +101,19 @@ vpx_rc_status_t rc_send_firstpass_stats(
return VPX_RC_OK;
}
+vpx_rc_status_t rc_send_firstpass_stats_gop(
+ vpx_rc_model_t rate_ctrl_model,
+ const vpx_rc_firstpass_stats_t *first_pass_stats) {
+ const ToyRateCtrl *toy_rate_ctrl =
+ static_cast<ToyRateCtrl *>(rate_ctrl_model);
+ EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
+ EXPECT_EQ(first_pass_stats->num_frames, kFrameNumGOP);
+ for (int i = 0; i < first_pass_stats->num_frames; ++i) {
+ EXPECT_DOUBLE_EQ(first_pass_stats->frame_stats[i].frame, i);
+ }
+ return VPX_RC_OK;
+}
+
vpx_rc_status_t rc_get_encodeframe_decision(
vpx_rc_model_t rate_ctrl_model,
const vpx_rc_encodeframe_info_t *encode_frame_info,
@@ -133,6 +186,41 @@ vpx_rc_status_t rc_get_encodeframe_decision(
return VPX_RC_OK;
}
+vpx_rc_status_t rc_get_gop_decision(vpx_rc_model_t rate_ctrl_model,
+ const vpx_rc_gop_info_t *gop_info,
+ vpx_rc_gop_decision_t *gop_decision) {
+ ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
+ EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
+ EXPECT_EQ(gop_info->lag_in_frames, kMaxLagInFrames);
+ EXPECT_EQ(gop_info->min_gf_interval, kReadMinGfInterval);
+ EXPECT_EQ(gop_info->max_gf_interval, kReadMaxGfInterval);
+ EXPECT_EQ(gop_info->allow_alt_ref, 1);
+ if (gop_info->is_key_frame) {
+ EXPECT_EQ(gop_info->last_gop_use_alt_ref, 0);
+ EXPECT_EQ(gop_info->frames_since_key, 0);
+ EXPECT_EQ(gop_info->gop_id, 0);
+ toy_rate_ctrl->gop_id = 0;
+ toy_rate_ctrl->frames_since_key = 0;
+ } else {
+ EXPECT_EQ(gop_info->last_gop_use_alt_ref, 1);
+ }
+ EXPECT_EQ(gop_info->gop_id, toy_rate_ctrl->gop_id);
+ EXPECT_EQ(gop_info->frames_since_key, toy_rate_ctrl->frames_since_key);
+ EXPECT_EQ(gop_info->show_index, toy_rate_ctrl->show_index);
+ EXPECT_EQ(gop_info->coding_index, toy_rate_ctrl->coding_index);
+
+ gop_decision->gop_coding_frames =
+ VPXMIN(kFixedGOPSize, gop_info->frames_to_key);
+ gop_decision->use_alt_ref = gop_decision->gop_coding_frames == kFixedGOPSize;
+ toy_rate_ctrl->frames_since_key +=
+ gop_decision->gop_coding_frames - gop_decision->use_alt_ref;
+ toy_rate_ctrl->show_index +=
+ gop_decision->gop_coding_frames - gop_decision->use_alt_ref;
+ toy_rate_ctrl->coding_index += gop_decision->gop_coding_frames;
+ ++toy_rate_ctrl->gop_id;
+ return VPX_RC_OK;
+}
+
vpx_rc_status_t rc_update_encodeframe_result(
vpx_rc_model_t rate_ctrl_model,
const vpx_rc_encodeframe_result_t *encode_frame_result) {
@@ -153,6 +241,18 @@ vpx_rc_status_t rc_update_encodeframe_result(
return VPX_RC_OK;
}
+vpx_rc_status_t rc_update_encodeframe_result_gop(
+ vpx_rc_model_t rate_ctrl_model,
+ const vpx_rc_encodeframe_result_t *encode_frame_result) {
+ const ToyRateCtrl *toy_rate_ctrl =
+ static_cast<ToyRateCtrl *>(rate_ctrl_model);
+ EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
+
+ const int64_t ref_pixel_count = 640 * 360 * 3 / 2;
+ EXPECT_EQ(encode_frame_result->pixel_count, ref_pixel_count);
+ return VPX_RC_OK;
+}
+
vpx_rc_status_t rc_delete_model(vpx_rc_model_t rate_ctrl_model) {
ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
@@ -200,4 +300,49 @@ TEST_F(ExtRateCtrlTest, EncodeTest) {
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
}
+class ExtRateCtrlTestGOP : public ::libvpx_test::EncoderTest,
+ public ::libvpx_test::CodecTestWithParam<int> {
+ protected:
+ ExtRateCtrlTestGOP() : EncoderTest(&::libvpx_test::kVP9) {}
+
+ ~ExtRateCtrlTestGOP() override = default;
+
+ void SetUp() override {
+ InitializeConfig();
+ SetMode(::libvpx_test::kTwoPassGood);
+ }
+
+ void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
+ ::libvpx_test::Encoder *encoder) override {
+ if (video->frame() == 0) {
+ encoder->Control(VP9E_SET_MIN_GF_INTERVAL, kDefaultMinGfInterval);
+ encoder->Control(VP9E_SET_MAX_GF_INTERVAL, kDefaultMaxGfInterval);
+
+ vpx_rc_funcs_t rc_funcs;
+ rc_funcs.rc_type = VPX_RC_GOP;
+ rc_funcs.create_model = rc_create_model_gop;
+ rc_funcs.send_firstpass_stats = rc_send_firstpass_stats_gop;
+ rc_funcs.get_gop_decision = rc_get_gop_decision;
+ rc_funcs.update_encodeframe_result = rc_update_encodeframe_result_gop;
+ rc_funcs.delete_model = rc_delete_model;
+ rc_funcs.priv = reinterpret_cast<void *>(PrivMagicNumber);
+ encoder->Control(VP9E_SET_EXTERNAL_RATE_CONTROL, &rc_funcs);
+ }
+ }
+};
+
+TEST_F(ExtRateCtrlTestGOP, EncodeTest) {
+ cfg_.rc_target_bitrate = 4000;
+ cfg_.g_lag_in_frames = kMaxLagInFrames;
+ cfg_.rc_end_usage = VPX_VBR;
+
+ std::unique_ptr<libvpx_test::VideoSource> video;
+ video.reset(new (std::nothrow) libvpx_test::YUVVideoSource(
+ "noisy_clip_640_360.y4m", VPX_IMG_FMT_I420, 640, 360, 30, 1, 0,
+ kFrameNumGOP));
+
+ ASSERT_NE(video.get(), nullptr);
+ ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
+}
+
} // namespace