#include <climits>
#include <vector>
#include "aom/aomcx.h"
#include "aom_dsp/aom_dsp_common.h"
#include "av1/encoder/encoder.h"
#include "gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/util.h"
#include "test/video_source.h"
#include "test/y4m_video_source.h"
#define WRITE_COMPRESSED_STREAM …
namespace {
#if WRITE_COMPRESSED_STREAM
static void mem_put_le16(char *const mem, unsigned int val) {
mem[0] = val;
mem[1] = val >> 8;
}
static void mem_put_le32(char *const mem, unsigned int val) {
mem[0] = val;
mem[1] = val >> 8;
mem[2] = val >> 16;
mem[3] = val >> 24;
}
static void write_ivf_file_header(const aom_codec_enc_cfg_t *const cfg,
int frame_cnt, FILE *const outfile) {
char header[32];
header[0] = 'D';
header[1] = 'K';
header[2] = 'I';
header[3] = 'F';
mem_put_le16(header + 4, 0);
mem_put_le16(header + 6, 32);
mem_put_le32(header + 8, AV1_FOURCC);
mem_put_le16(header + 12, cfg->g_w);
mem_put_le16(header + 14, cfg->g_h);
mem_put_le32(header + 16, cfg->g_timebase.den);
mem_put_le32(header + 20, cfg->g_timebase.num);
mem_put_le32(header + 24, frame_cnt);
mem_put_le32(header + 28, 0);
(void)fwrite(header, 1, 32, outfile);
}
static void write_ivf_frame_size(FILE *const outfile, const size_t size) {
char header[4];
mem_put_le32(header, static_cast<unsigned int>(size));
(void)fwrite(header, 1, 4, outfile);
}
static void write_ivf_frame_header(const aom_codec_cx_pkt_t *const pkt,
FILE *const outfile) {
char header[12];
aom_codec_pts_t pts;
if (pkt->kind != AOM_CODEC_CX_FRAME_PKT) return;
pts = pkt->data.frame.pts;
mem_put_le32(header, static_cast<unsigned int>(pkt->data.frame.sz));
mem_put_le32(header + 4, pts & 0xFFFFFFFF);
mem_put_le32(header + 8, pts >> 32);
(void)fwrite(header, 1, 12, outfile);
}
#endif
const unsigned int kInitialWidth = …;
const unsigned int kInitialHeight = …;
struct FrameInfo { … };
void ScaleForFrameNumber(unsigned int frame, unsigned int initial_w,
unsigned int initial_h, int flag_codec,
bool change_start_resln, unsigned int *w,
unsigned int *h) { … }
class ResizingVideoSource : public ::libaom_test::DummyVideoSource { … };
class ResizeTest
: public ::libaom_test::CodecTestWithParam<libaom_test::TestMode>,
public ::libaom_test::EncoderTest { … };
TEST_P(ResizeTest, TestExternalResizeWorks) { … }
#if !CONFIG_REALTIME_ONLY
const unsigned int kStepDownFrame = 3;
const unsigned int kStepUpFrame = 6;
class ResizeInternalTestLarge : public ResizeTest {
protected:
#if WRITE_COMPRESSED_STREAM
ResizeInternalTestLarge()
: ResizeTest(), frame0_psnr_(0.0), outfile_(nullptr), out_frames_(0) {}
#else
ResizeInternalTestLarge() : ResizeTest(), frame0_psnr_(0.0) {}
#endif
~ResizeInternalTestLarge() override = default;
void BeginPassHook(unsigned int ) override {
#if WRITE_COMPRESSED_STREAM
outfile_ = fopen("av10-2-05-resize.ivf", "wb");
#endif
}
void EndPassHook() override {
#if WRITE_COMPRESSED_STREAM
if (outfile_) {
if (!fseek(outfile_, 0, SEEK_SET))
write_ivf_file_header(&cfg_, out_frames_, outfile_);
fclose(outfile_);
outfile_ = nullptr;
}
#endif
}
void PreEncodeFrameHook(libaom_test::VideoSource *video,
libaom_test::Encoder *encoder) override {
if (change_config_) {
int new_q = 60;
if (video->frame() == 0) {
struct aom_scaling_mode mode = { AOME_ONETWO, AOME_ONETWO };
encoder->Control(AOME_SET_SCALEMODE, &mode);
} else if (video->frame() == 1) {
struct aom_scaling_mode mode = { AOME_NORMAL, AOME_NORMAL };
encoder->Control(AOME_SET_SCALEMODE, &mode);
cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = new_q;
encoder->Config(&cfg_);
}
} else {
if (video->frame() >= kStepDownFrame && video->frame() < kStepUpFrame) {
struct aom_scaling_mode mode = { AOME_FOURFIVE, AOME_THREEFIVE };
encoder->Control(AOME_SET_SCALEMODE, &mode);
}
if (video->frame() >= kStepUpFrame) {
struct aom_scaling_mode mode = { AOME_NORMAL, AOME_NORMAL };
encoder->Control(AOME_SET_SCALEMODE, &mode);
}
}
}
void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) override {
if (frame0_psnr_ == 0.) frame0_psnr_ = pkt->data.psnr.psnr[0];
EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 4.1);
}
#if WRITE_COMPRESSED_STREAM
void FramePktHook(const aom_codec_cx_pkt_t *pkt) override {
++out_frames_;
if (pkt->data.frame.pts == 0) write_ivf_file_header(&cfg_, 0, outfile_);
write_ivf_frame_header(pkt, outfile_);
(void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_);
}
#endif
double frame0_psnr_;
bool change_config_;
#if WRITE_COMPRESSED_STREAM
FILE *outfile_;
unsigned int out_frames_;
#endif
};
TEST_P(ResizeInternalTestLarge, TestInternalResizeWorks) {
::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 10);
init_flags_ = AOM_CODEC_USE_PSNR;
change_config_ = false;
cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48;
cfg_.g_lag_in_frames = 0;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
info != frame_info_list_.end(); ++info) {
}
for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
info != frame_info_list_.end(); ++info) {
const aom_codec_pts_t pts = info->pts;
if (pts >= kStepDownFrame && pts < kStepUpFrame) {
ASSERT_EQ(282U, info->w) << "Frame " << pts << " had unexpected width";
ASSERT_EQ(173U, info->h) << "Frame " << pts << " had unexpected height";
} else {
EXPECT_EQ(352U, info->w) << "Frame " << pts << " had unexpected width";
EXPECT_EQ(288U, info->h) << "Frame " << pts << " had unexpected height";
}
}
}
TEST_P(ResizeInternalTestLarge, TestInternalResizeChangeConfig) {
::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 10);
cfg_.g_w = 352;
cfg_.g_h = 288;
change_config_ = true;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
AV1_INSTANTIATE_TEST_SUITE(ResizeInternalTestLarge,
::testing::Values(::libaom_test::kOnePassGood));
#endif
class ResizeRealtimeTest
: public ::libaom_test::CodecTestWith3Params<libaom_test::TestMode, int,
int>,
public ::libaom_test::EncoderTest { … };
TEST_P(ResizeRealtimeTest, TestInternalResizeSetScaleMode1) { … }
TEST_P(ResizeRealtimeTest, TestInternalResizeSetScaleMode1QVGA) { … }
TEST_P(ResizeRealtimeTest, TestInternalResizeSetScaleMode2) { … }
TEST_P(ResizeRealtimeTest, TestInternalResizeSetScaleMode3) { … }
TEST_P(ResizeRealtimeTest, TestExternalResizeWorks) { … }
TEST_P(ResizeRealtimeTest, TestExternalResizeWorksUsePSNR) { … }
TEST_P(ResizeRealtimeTest, TestInternalResizeDown) { … }
TEST_P(ResizeRealtimeTest, TestInternalResizeDownUpChangeBitRate) { … }
TEST_P(ResizeRealtimeTest, TestInternalResizeDownUpChangeBitRateScreen) { … }
class ResizeCspTest : public ResizeTest { … };
class ResizingCspVideoSource : public ::libaom_test::DummyVideoSource { … };
#if (defined(DISABLE_TRELLISQ_SEARCH) && DISABLE_TRELLISQ_SEARCH) || \
(defined(CONFIG_MAX_DECODE_PROFILE) && CONFIG_MAX_DECODE_PROFILE < 1)
TEST_P(ResizeCspTest, DISABLED_TestResizeCspWorks) {
#else
TEST_P(ResizeCspTest, TestResizeCspWorks) { … }
#if !CONFIG_REALTIME_ONLY
class ResizeModeTestLarge
: public ::libaom_test::CodecTestWith5Params<libaom_test::TestMode, int,
int, int, int>,
public ::libaom_test::EncoderTest {
protected:
ResizeModeTestLarge()
: EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)),
resize_mode_(GET_PARAM(2)), resize_denominator_(GET_PARAM(3)),
resize_kf_denominator_(GET_PARAM(4)), cpu_used_(GET_PARAM(5)) {}
~ResizeModeTestLarge() override = default;
void SetUp() override {
InitializeConfig(encoding_mode_);
const aom_rational timebase = { 1, 30 };
cfg_.g_timebase = timebase;
cfg_.rc_end_usage = AOM_VBR;
cfg_.g_threads = 1;
cfg_.g_lag_in_frames = 35;
cfg_.rc_target_bitrate = 1000;
cfg_.rc_resize_mode = resize_mode_;
cfg_.rc_resize_denominator = resize_denominator_;
cfg_.rc_resize_kf_denominator = resize_kf_denominator_;
init_flags_ = AOM_CODEC_USE_PSNR;
}
void PreEncodeFrameHook(::libaom_test::VideoSource *video,
::libaom_test::Encoder *encoder) override {
if (video->frame() == 0) {
encoder->Control(AOME_SET_CPUUSED, cpu_used_);
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
}
}
::libaom_test::TestMode encoding_mode_;
int resize_mode_;
int resize_denominator_;
int resize_kf_denominator_;
int cpu_used_;
};
TEST_P(ResizeModeTestLarge, ResizeModeTest) {
::libaom_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 30);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ResizeModeTestLarge);
AV1_INSTANTIATE_TEST_SUITE(ResizeModeTestLarge,
::testing::Values(::libaom_test::kOnePassGood,
::libaom_test::kTwoPassGood),
::testing::Values(1, 2), ::testing::Values(8, 12),
::testing::Values(10, 14), ::testing::Values(3, 6));
#endif
AV1_INSTANTIATE_TEST_SUITE(…);
AV1_INSTANTIATE_TEST_SUITE(…) …;
AV1_INSTANTIATE_TEST_SUITE(…);
TEST(ResizeSimpleTest, TemporarySmallerFrameSize) { … }
TEST(ResizeSimpleTest, SmallerFrameSizeSVC) { … }
const int kUsages[] = …;
#else
{ AOM_USAGE_GOOD_QUALITY, AOM_USAGE_REALTIME, AOM_USAGE_ALL_INTRA };
#endif
const int kNumThreads[] = …;
class FrameSizeChangeTest
: public ::libaom_test::CodecTestWith3Params<int, int, int> { … };
TEST_P(FrameSizeChangeTest, FixedThreads) { … }
TEST_P(FrameSizeChangeTest, DecreasingThreads) { … }
TEST_P(FrameSizeChangeTest, IncreasingThreads) { … }
AV1_INSTANTIATE_TEST_SUITE(…) …;
}