965 lines
39 KiB
C++
965 lines
39 KiB
C++
/*
|
|
* 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 <cstdint>
|
|
#include <new>
|
|
|
|
#include "test/codec_factory.h"
|
|
#include "test/encode_test_driver.h"
|
|
#include "test/util.h"
|
|
#include "test/yuv_video_source.h"
|
|
#include "third_party/googletest/src/include/gtest/gtest.h"
|
|
#include "vp9/simple_encode.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 kFrameNumGOPShort = 4;
|
|
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 active gf interval might change for each GOP
|
|
// See function "get_active_gf_inverval_range".
|
|
// The numbers below are from manual inspection.
|
|
constexpr int kReadMinGfInterval = 5;
|
|
constexpr int kReadMaxGfInterval = 13;
|
|
const char kTestFileName[] = "bus_352x288_420_f20_b8.yuv";
|
|
const double kPsnrThreshold = 30.50;
|
|
|
|
struct ToyRateCtrl {
|
|
int magic_number;
|
|
int coding_index;
|
|
|
|
int gop_global_index;
|
|
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_ptr) {
|
|
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->coding_index = -1;
|
|
*rate_ctrl_model_ptr = toy_rate_ctrl;
|
|
EXPECT_EQ(priv, reinterpret_cast<void *>(PrivMagicNumber));
|
|
EXPECT_EQ(ratectrl_config->frame_width, 352);
|
|
EXPECT_EQ(ratectrl_config->frame_height, 288);
|
|
EXPECT_EQ(ratectrl_config->show_frame_count, kFrameNum);
|
|
EXPECT_EQ(ratectrl_config->target_bitrate_kbps, 24000);
|
|
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_create_model_gop(void *priv,
|
|
const vpx_rc_config_t *ratectrl_config,
|
|
vpx_rc_model_t *rate_ctrl_model_ptr) {
|
|
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_global_index = 0;
|
|
toy_rate_ctrl->frames_since_key = 0;
|
|
toy_rate_ctrl->show_index = 0;
|
|
toy_rate_ctrl->coding_index = 0;
|
|
*rate_ctrl_model_ptr = 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_create_model_gop_short(
|
|
void *priv, const vpx_rc_config_t *ratectrl_config,
|
|
vpx_rc_model_t *rate_ctrl_model_ptr) {
|
|
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_global_index = 0;
|
|
toy_rate_ctrl->frames_since_key = 0;
|
|
toy_rate_ctrl->show_index = 0;
|
|
toy_rate_ctrl->coding_index = 0;
|
|
*rate_ctrl_model_ptr = toy_rate_ctrl;
|
|
EXPECT_EQ(priv, reinterpret_cast<void *>(PrivMagicNumber));
|
|
EXPECT_EQ(ratectrl_config->frame_width, 352);
|
|
EXPECT_EQ(ratectrl_config->frame_height, 288);
|
|
EXPECT_EQ(ratectrl_config->show_frame_count, kFrameNumGOPShort);
|
|
EXPECT_EQ(ratectrl_config->target_bitrate_kbps, 500);
|
|
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) {
|
|
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, kFrameNum);
|
|
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_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_send_firstpass_stats_gop_short(
|
|
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, kFrameNumGOPShort);
|
|
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,
|
|
vpx_rc_encodeframe_decision_t *frame_decision) {
|
|
ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
|
|
toy_rate_ctrl->coding_index += 1;
|
|
|
|
EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
|
|
|
|
EXPECT_LT(encode_frame_info->show_index, kFrameNum);
|
|
EXPECT_EQ(encode_frame_info->coding_index, toy_rate_ctrl->coding_index);
|
|
|
|
if (encode_frame_info->coding_index == 0) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 0);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 0);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeKey);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
0); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
} else if (encode_frame_info->coding_index == 1) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 4);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 1);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeAltRef);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
1); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[0],
|
|
0); // kRefFrameTypeLast
|
|
} else if (encode_frame_info->coding_index >= 2 &&
|
|
encode_frame_info->coding_index < 5) {
|
|
// In the first group of pictures, coding_index and gop_index are equal.
|
|
EXPECT_EQ(encode_frame_info->gop_index, encode_frame_info->coding_index);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeInter);
|
|
} else if (encode_frame_info->coding_index == 5) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 4);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 0);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeOverlay);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
1); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
1); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
1); // kRefFrameTypeFuture
|
|
EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[0],
|
|
4); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[2],
|
|
1); // kRefFrameTypeFuture
|
|
}
|
|
if (encode_frame_info->coding_index == kLosslessCodingIndex) {
|
|
// We should get sse == 0 at rc_update_encodeframe_result()
|
|
frame_decision->q_index = 0;
|
|
} else {
|
|
frame_decision->q_index = 100;
|
|
}
|
|
frame_decision->max_frame_size = 0;
|
|
return VPX_RC_OK;
|
|
}
|
|
|
|
vpx_rc_status_t rc_get_encodeframe_decision_gop(
|
|
vpx_rc_model_t rate_ctrl_model,
|
|
const vpx_rc_encodeframe_info_t *encode_frame_info,
|
|
vpx_rc_encodeframe_decision_t *frame_decision) {
|
|
ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
|
|
EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
|
|
EXPECT_LT(encode_frame_info->show_index, kFrameNumGOP);
|
|
EXPECT_EQ(encode_frame_info->coding_index, toy_rate_ctrl->coding_index);
|
|
|
|
if (encode_frame_info->coding_index == 0) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 0);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 0);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeKey);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
0); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
} else if (encode_frame_info->coding_index == 1) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 1);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 1);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeInter);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
1); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[0],
|
|
0); // kRefFrameTypeLast
|
|
} else if (encode_frame_info->coding_index == 2) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 2);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 0);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeKey);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
0); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
} else if (encode_frame_info->coding_index == 3 ||
|
|
encode_frame_info->coding_index == 12 ||
|
|
encode_frame_info->coding_index == 21) {
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeAltRef);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 1);
|
|
} else if (encode_frame_info->coding_index == 11 ||
|
|
encode_frame_info->coding_index == 20 ||
|
|
encode_frame_info->coding_index == 29) {
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeOverlay);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 0);
|
|
} else if (encode_frame_info->coding_index >= 30) {
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeInter);
|
|
}
|
|
|
|
// When the model recommends an invalid q, valid range [0, 255],
|
|
// the encoder will ignore it and use the default q selected
|
|
// by libvpx rate control strategy.
|
|
frame_decision->q_index = VPX_DEFAULT_Q;
|
|
frame_decision->max_frame_size = 0;
|
|
|
|
toy_rate_ctrl->coding_index += 1;
|
|
return VPX_RC_OK;
|
|
}
|
|
|
|
vpx_rc_status_t rc_get_encodeframe_decision_gop_short(
|
|
vpx_rc_model_t rate_ctrl_model,
|
|
const vpx_rc_encodeframe_info_t *encode_frame_info,
|
|
vpx_rc_encodeframe_decision_t *frame_decision) {
|
|
ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
|
|
EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
|
|
EXPECT_LT(encode_frame_info->show_index, kFrameNumGOPShort);
|
|
EXPECT_EQ(encode_frame_info->coding_index, toy_rate_ctrl->coding_index);
|
|
|
|
if (encode_frame_info->coding_index == 0) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 0);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 0);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeKey);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
0); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
} else if (encode_frame_info->coding_index == 1) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 1);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 1);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeInter);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
1); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[0],
|
|
0); // kRefFrameTypeLast
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
} else if (encode_frame_info->coding_index == 2) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 2);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 2);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeInter);
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
} else if (encode_frame_info->coding_index == 3) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 3);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 0);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeGolden);
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 2);
|
|
}
|
|
|
|
// When the model recommends an invalid q, valid range [0, 255],
|
|
// the encoder will ignore it and use the default q selected
|
|
// by libvpx rate control strategy.
|
|
frame_decision->q_index = VPX_DEFAULT_Q;
|
|
frame_decision->max_frame_size = 0;
|
|
|
|
toy_rate_ctrl->coding_index += 1;
|
|
return VPX_RC_OK;
|
|
}
|
|
|
|
vpx_rc_status_t rc_get_encodeframe_decision_gop_short_overlay(
|
|
vpx_rc_model_t rate_ctrl_model,
|
|
const vpx_rc_encodeframe_info_t *encode_frame_info,
|
|
vpx_rc_encodeframe_decision_t *frame_decision) {
|
|
ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
|
|
EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
|
|
EXPECT_LT(encode_frame_info->show_index, kFrameNumGOPShort);
|
|
EXPECT_EQ(encode_frame_info->coding_index, toy_rate_ctrl->coding_index);
|
|
|
|
if (encode_frame_info->coding_index == 0) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 0);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 0);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeKey);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
0); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
} else if (encode_frame_info->coding_index == 1) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 3);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 1);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeAltRef);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
1); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[0],
|
|
0); // kRefFrameTypeLast
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
} else if (encode_frame_info->coding_index == 2) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 1);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 2);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeInter);
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
} else if (encode_frame_info->coding_index == 3) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 2);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 3);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeInter);
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
} else if (encode_frame_info->coding_index == 4) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 3);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 0);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeOverlay);
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 2);
|
|
}
|
|
|
|
// When the model recommends an invalid q, valid range [0, 255],
|
|
// the encoder will ignore it and use the default q selected
|
|
// by libvpx rate control strategy.
|
|
frame_decision->q_index = VPX_DEFAULT_Q;
|
|
frame_decision->max_frame_size = 0;
|
|
|
|
toy_rate_ctrl->coding_index += 1;
|
|
return VPX_RC_OK;
|
|
}
|
|
|
|
vpx_rc_status_t rc_get_encodeframe_decision_gop_short_no_arf(
|
|
vpx_rc_model_t rate_ctrl_model,
|
|
const vpx_rc_encodeframe_info_t *encode_frame_info,
|
|
vpx_rc_encodeframe_decision_t *frame_decision) {
|
|
ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
|
|
EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
|
|
EXPECT_LT(encode_frame_info->show_index, kFrameNumGOPShort);
|
|
EXPECT_EQ(encode_frame_info->coding_index, toy_rate_ctrl->coding_index);
|
|
|
|
if (encode_frame_info->coding_index == 0) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 0);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 0);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeKey);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
0); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
} else if (encode_frame_info->coding_index == 1) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 1);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 1);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeInter);
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
|
|
1); // kRefFrameTypeLast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
|
|
0); // kRefFrameTypePast
|
|
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
|
|
0); // kRefFrameTypeFuture
|
|
EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[0],
|
|
0); // kRefFrameTypeLast
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
} else if (encode_frame_info->coding_index == 2) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 2);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 2);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeInter);
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
} else if (encode_frame_info->coding_index == 3) {
|
|
EXPECT_EQ(encode_frame_info->show_index, 3);
|
|
EXPECT_EQ(encode_frame_info->gop_index, 3);
|
|
EXPECT_EQ(encode_frame_info->frame_type, vp9::kFrameTypeInter);
|
|
EXPECT_EQ(toy_rate_ctrl->gop_global_index, 1);
|
|
}
|
|
|
|
// When the model recommends an invalid q, valid range [0, 255],
|
|
// the encoder will ignore it and use the default q selected
|
|
// by libvpx rate control strategy.
|
|
frame_decision->q_index = VPX_DEFAULT_Q;
|
|
frame_decision->max_frame_size = 0;
|
|
|
|
toy_rate_ctrl->coding_index += 1;
|
|
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, kDefaultMinGfInterval);
|
|
EXPECT_EQ(gop_info->max_gf_interval, kDefaultMaxGfInterval);
|
|
EXPECT_EQ(gop_info->active_min_gf_interval, kReadMinGfInterval);
|
|
EXPECT_EQ(gop_info->active_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_global_index, 0);
|
|
toy_rate_ctrl->gop_global_index = 0;
|
|
toy_rate_ctrl->frames_since_key = 0;
|
|
} else {
|
|
EXPECT_EQ(gop_info->last_gop_use_alt_ref, 1);
|
|
}
|
|
EXPECT_EQ(gop_info->gop_global_index, toy_rate_ctrl->gop_global_index);
|
|
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->gop_global_index;
|
|
return VPX_RC_OK;
|
|
}
|
|
|
|
// Test on a 4 frame video.
|
|
// Test a setting of 2 GOPs.
|
|
// The first GOP has 3 coding frames, no alt ref.
|
|
// The second GOP has 1 coding frame, no alt ref.
|
|
vpx_rc_status_t rc_get_gop_decision_short(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 - 1);
|
|
EXPECT_EQ(gop_info->min_gf_interval, kDefaultMinGfInterval);
|
|
EXPECT_EQ(gop_info->max_gf_interval, kDefaultMaxGfInterval);
|
|
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_global_index, 0);
|
|
toy_rate_ctrl->gop_global_index = 0;
|
|
toy_rate_ctrl->frames_since_key = 0;
|
|
} else {
|
|
EXPECT_EQ(gop_info->last_gop_use_alt_ref, 0);
|
|
}
|
|
EXPECT_EQ(gop_info->gop_global_index, toy_rate_ctrl->gop_global_index);
|
|
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 = gop_info->gop_global_index == 0 ? 3 : 1;
|
|
gop_decision->use_alt_ref = 0;
|
|
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->gop_global_index;
|
|
return VPX_RC_OK;
|
|
}
|
|
|
|
// Test on a 4 frame video.
|
|
// Test a setting of 2 GOPs.
|
|
// The first GOP has 4 coding frames. Use alt ref.
|
|
// The second GOP only contains the overlay frame of the first GOP's alt ref
|
|
// frame.
|
|
vpx_rc_status_t rc_get_gop_decision_short_overlay(
|
|
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 - 1);
|
|
EXPECT_EQ(gop_info->min_gf_interval, kDefaultMinGfInterval);
|
|
EXPECT_EQ(gop_info->max_gf_interval, kDefaultMaxGfInterval);
|
|
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_global_index, 0);
|
|
toy_rate_ctrl->gop_global_index = 0;
|
|
toy_rate_ctrl->frames_since_key = 0;
|
|
} else {
|
|
EXPECT_EQ(gop_info->last_gop_use_alt_ref, 1);
|
|
}
|
|
EXPECT_EQ(gop_info->gop_global_index, toy_rate_ctrl->gop_global_index);
|
|
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 = gop_info->gop_global_index == 0 ? 4 : 1;
|
|
gop_decision->use_alt_ref = gop_info->is_key_frame ? 1 : 0;
|
|
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->gop_global_index;
|
|
return VPX_RC_OK;
|
|
}
|
|
|
|
// Test on a 4 frame video.
|
|
// Test a setting of 1 GOP.
|
|
// The GOP has 4 coding frames. Do not use alt ref.
|
|
vpx_rc_status_t rc_get_gop_decision_short_no_arf(
|
|
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 - 1);
|
|
EXPECT_EQ(gop_info->min_gf_interval, kDefaultMinGfInterval);
|
|
EXPECT_EQ(gop_info->max_gf_interval, kDefaultMaxGfInterval);
|
|
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_global_index, 0);
|
|
toy_rate_ctrl->gop_global_index = 0;
|
|
toy_rate_ctrl->frames_since_key = 0;
|
|
} else {
|
|
EXPECT_EQ(gop_info->last_gop_use_alt_ref, 0);
|
|
}
|
|
EXPECT_EQ(gop_info->gop_global_index, toy_rate_ctrl->gop_global_index);
|
|
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 = gop_info->gop_global_index == 0 ? 4 : 1;
|
|
gop_decision->use_alt_ref = 0;
|
|
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->gop_global_index;
|
|
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) {
|
|
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 = 352 * 288 * 3 / 2;
|
|
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;
|
|
}
|
|
|
|
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_update_encodeframe_result_gop_short(
|
|
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 = 352 * 288 * 3 / 2;
|
|
EXPECT_EQ(encode_frame_result->pixel_count, ref_pixel_count);
|
|
return VPX_RC_OK;
|
|
}
|
|
|
|
vpx_rc_status_t rc_get_default_frame_rdmult(
|
|
vpx_rc_model_t rate_ctrl_model,
|
|
const vpx_rc_encodeframe_info_t *encode_frame_info, int *rdmult) {
|
|
const ToyRateCtrl *toy_rate_ctrl =
|
|
static_cast<ToyRateCtrl *>(rate_ctrl_model);
|
|
EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
|
|
EXPECT_LT(encode_frame_info->show_index, kFrameNumGOPShort);
|
|
EXPECT_EQ(encode_frame_info->coding_index, toy_rate_ctrl->coding_index);
|
|
|
|
*rdmult = VPX_DEFAULT_RDMULT;
|
|
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);
|
|
delete toy_rate_ctrl;
|
|
return VPX_RC_OK;
|
|
}
|
|
|
|
class ExtRateCtrlTest : public ::libvpx_test::EncoderTest,
|
|
public ::testing::Test {
|
|
protected:
|
|
ExtRateCtrlTest() : EncoderTest(&::libvpx_test::kVP9) {}
|
|
|
|
~ExtRateCtrlTest() 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) {
|
|
vpx_rc_funcs_t rc_funcs;
|
|
rc_funcs.rc_type = VPX_RC_QP;
|
|
rc_funcs.create_model = rc_create_model;
|
|
rc_funcs.send_firstpass_stats = rc_send_firstpass_stats;
|
|
rc_funcs.get_encodeframe_decision = rc_get_encodeframe_decision;
|
|
rc_funcs.update_encodeframe_result = rc_update_encodeframe_result;
|
|
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(ExtRateCtrlTest, EncodeTest) {
|
|
cfg_.rc_target_bitrate = 24000;
|
|
|
|
std::unique_ptr<libvpx_test::VideoSource> video;
|
|
video.reset(new (std::nothrow) libvpx_test::YUVVideoSource(
|
|
"bus_352x288_420_f20_b8.yuv", VPX_IMG_FMT_I420, 352, 288, 30, 1, 0,
|
|
kFrameNum));
|
|
|
|
ASSERT_NE(video, nullptr);
|
|
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_QP;
|
|
rc_funcs.create_model = rc_create_model_gop;
|
|
rc_funcs.send_firstpass_stats = rc_send_firstpass_stats_gop;
|
|
rc_funcs.get_encodeframe_decision = rc_get_encodeframe_decision_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, nullptr);
|
|
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
|
}
|
|
|
|
class ExtRateCtrlTestGOPShort : public ::libvpx_test::EncoderTest,
|
|
public ::libvpx_test::CodecTestWithParam<int> {
|
|
protected:
|
|
ExtRateCtrlTestGOPShort() : EncoderTest(&::libvpx_test::kVP9) {}
|
|
|
|
~ExtRateCtrlTestGOPShort() 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);
|
|
encoder->Control(VP9E_SET_TARGET_LEVEL, vp9::LEVEL_AUTO);
|
|
|
|
vpx_rc_funcs_t rc_funcs;
|
|
rc_funcs.rc_type = VPX_RC_GOP_QP;
|
|
rc_funcs.create_model = rc_create_model_gop_short;
|
|
rc_funcs.send_firstpass_stats = rc_send_firstpass_stats_gop_short;
|
|
rc_funcs.get_encodeframe_decision = rc_get_encodeframe_decision_gop_short;
|
|
rc_funcs.get_gop_decision = rc_get_gop_decision_short;
|
|
rc_funcs.update_encodeframe_result =
|
|
rc_update_encodeframe_result_gop_short;
|
|
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(ExtRateCtrlTestGOPShort, EncodeTest) {
|
|
cfg_.rc_target_bitrate = 500;
|
|
cfg_.g_lag_in_frames = kMaxLagInFrames - 1;
|
|
cfg_.rc_end_usage = VPX_VBR;
|
|
|
|
std::unique_ptr<libvpx_test::VideoSource> video;
|
|
video.reset(new (std::nothrow) libvpx_test::YUVVideoSource(
|
|
kTestFileName, VPX_IMG_FMT_I420, 352, 288, 30, 1, 0, kFrameNumGOPShort));
|
|
|
|
ASSERT_NE(video, nullptr);
|
|
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
|
}
|
|
|
|
class ExtRateCtrlTestGOPShortOverlay
|
|
: public ::libvpx_test::EncoderTest,
|
|
public ::libvpx_test::CodecTestWithParam<int> {
|
|
protected:
|
|
ExtRateCtrlTestGOPShortOverlay() : EncoderTest(&::libvpx_test::kVP9) {}
|
|
|
|
~ExtRateCtrlTestGOPShortOverlay() 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);
|
|
encoder->Control(VP9E_SET_TARGET_LEVEL, vp9::LEVEL_AUTO);
|
|
|
|
vpx_rc_funcs_t rc_funcs;
|
|
rc_funcs.rc_type = VPX_RC_GOP_QP;
|
|
rc_funcs.create_model = rc_create_model_gop_short;
|
|
rc_funcs.send_firstpass_stats = rc_send_firstpass_stats_gop_short;
|
|
rc_funcs.get_encodeframe_decision =
|
|
rc_get_encodeframe_decision_gop_short_overlay;
|
|
rc_funcs.get_gop_decision = rc_get_gop_decision_short_overlay;
|
|
rc_funcs.update_encodeframe_result =
|
|
rc_update_encodeframe_result_gop_short;
|
|
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(ExtRateCtrlTestGOPShortOverlay, EncodeTest) {
|
|
cfg_.rc_target_bitrate = 500;
|
|
cfg_.g_lag_in_frames = kMaxLagInFrames - 1;
|
|
cfg_.rc_end_usage = VPX_VBR;
|
|
|
|
std::unique_ptr<libvpx_test::VideoSource> video;
|
|
video.reset(new (std::nothrow) libvpx_test::YUVVideoSource(
|
|
kTestFileName, VPX_IMG_FMT_I420, 352, 288, 30, 1, 0, kFrameNumGOPShort));
|
|
|
|
ASSERT_NE(video, nullptr);
|
|
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
|
}
|
|
|
|
class ExtRateCtrlTestGOPShortNoARF
|
|
: public ::libvpx_test::EncoderTest,
|
|
public ::libvpx_test::CodecTestWithParam<int> {
|
|
protected:
|
|
ExtRateCtrlTestGOPShortNoARF() : EncoderTest(&::libvpx_test::kVP9) {}
|
|
|
|
~ExtRateCtrlTestGOPShortNoARF() 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);
|
|
encoder->Control(VP9E_SET_TARGET_LEVEL, vp9::LEVEL_AUTO);
|
|
|
|
vpx_rc_funcs_t rc_funcs;
|
|
rc_funcs.rc_type = VPX_RC_GOP_QP;
|
|
rc_funcs.create_model = rc_create_model_gop_short;
|
|
rc_funcs.send_firstpass_stats = rc_send_firstpass_stats_gop_short;
|
|
rc_funcs.get_encodeframe_decision =
|
|
rc_get_encodeframe_decision_gop_short_no_arf;
|
|
rc_funcs.get_gop_decision = rc_get_gop_decision_short_no_arf;
|
|
rc_funcs.update_encodeframe_result =
|
|
rc_update_encodeframe_result_gop_short;
|
|
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(ExtRateCtrlTestGOPShortNoARF, EncodeTest) {
|
|
cfg_.rc_target_bitrate = 500;
|
|
cfg_.g_lag_in_frames = kMaxLagInFrames - 1;
|
|
cfg_.rc_end_usage = VPX_VBR;
|
|
|
|
std::unique_ptr<libvpx_test::VideoSource> video;
|
|
video.reset(new (std::nothrow) libvpx_test::YUVVideoSource(
|
|
kTestFileName, VPX_IMG_FMT_I420, 352, 288, 30, 1, 0, kFrameNumGOPShort));
|
|
|
|
ASSERT_NE(video, nullptr);
|
|
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
|
}
|
|
|
|
class ExtRateCtrlTestRdmult : public ::libvpx_test::EncoderTest,
|
|
public ::testing::Test {
|
|
protected:
|
|
ExtRateCtrlTestRdmult() : EncoderTest(&::libvpx_test::kVP9) {}
|
|
|
|
~ExtRateCtrlTestRdmult() override = default;
|
|
|
|
void SetUp() override {
|
|
InitializeConfig();
|
|
SetMode(::libvpx_test::kTwoPassGood);
|
|
}
|
|
|
|
void BeginPassHook(unsigned int) override {
|
|
psnr_ = 0.0;
|
|
nframes_ = 0;
|
|
}
|
|
|
|
void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) override {
|
|
psnr_ += pkt->data.psnr.psnr[0];
|
|
nframes_++;
|
|
}
|
|
|
|
void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
|
|
::libvpx_test::Encoder *encoder) override {
|
|
if (video->frame() == 0) {
|
|
vpx_rc_funcs_t rc_funcs;
|
|
rc_funcs.rc_type = VPX_RC_GOP_QP_RDMULT;
|
|
rc_funcs.create_model = rc_create_model_gop_short;
|
|
rc_funcs.send_firstpass_stats = rc_send_firstpass_stats_gop_short;
|
|
rc_funcs.get_encodeframe_decision = rc_get_encodeframe_decision_gop_short;
|
|
rc_funcs.get_gop_decision = rc_get_gop_decision_short;
|
|
rc_funcs.update_encodeframe_result =
|
|
rc_update_encodeframe_result_gop_short;
|
|
rc_funcs.get_frame_rdmult = rc_get_default_frame_rdmult;
|
|
rc_funcs.delete_model = rc_delete_model;
|
|
rc_funcs.priv = reinterpret_cast<void *>(PrivMagicNumber);
|
|
encoder->Control(VP9E_SET_EXTERNAL_RATE_CONTROL, &rc_funcs);
|
|
}
|
|
}
|
|
|
|
double GetAveragePsnr() const {
|
|
if (nframes_) return psnr_ / nframes_;
|
|
return 0.0;
|
|
}
|
|
|
|
private:
|
|
double psnr_;
|
|
unsigned int nframes_;
|
|
};
|
|
|
|
TEST_F(ExtRateCtrlTestRdmult, DefaultRdmult) {
|
|
cfg_.rc_target_bitrate = 500;
|
|
cfg_.g_lag_in_frames = kMaxLagInFrames - 1;
|
|
cfg_.rc_end_usage = VPX_VBR;
|
|
init_flags_ = VPX_CODEC_USE_PSNR;
|
|
|
|
std::unique_ptr<libvpx_test::VideoSource> video;
|
|
video.reset(new (std::nothrow) libvpx_test::YUVVideoSource(
|
|
kTestFileName, VPX_IMG_FMT_I420, 352, 288, 30, 1, 0, kFrameNumGOPShort));
|
|
|
|
ASSERT_NE(video, nullptr);
|
|
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
|
|
|
const double psnr = GetAveragePsnr();
|
|
EXPECT_GT(psnr, kPsnrThreshold);
|
|
}
|
|
|
|
} // namespace
|