2 * Copyright (c) 2021, Alliance for Open Media. All rights reserved
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
12 #include "aom_ports/mem.h"
13 #include "aom_dsp/ssim.h"
14 #include "av1/common/blockd.h"
15 #include "test/codec_factory.h"
16 #include "test/encode_test_driver.h"
17 #include "test/util.h"
18 #include "test/y4m_video_source.h"
19 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
23 const unsigned int kFrames
= 10;
24 const unsigned int kCqLevel
= 18;
25 // List of ssim thresholds for speed settings 0-8 with all intra encoding mode.
26 const double kSsimThreshold
[] = { 83.4, 83.4, 83.4, 83.3, 83.3,
27 83.0, 82.3, 81.1, 81.1 };
31 unsigned int input_bit_depth
;
33 aom_bit_depth_t bit_depth
;
37 std::ostream
&operator<<(std::ostream
&os
, const TestVideoParam
&test_arg
) {
38 return os
<< "TestVideoParam { filename:" << test_arg
.filename
39 << " input_bit_depth:" << test_arg
.input_bit_depth
40 << " fmt:" << test_arg
.fmt
<< " bit_depth:" << test_arg
.bit_depth
41 << " profile:" << test_arg
.profile
<< " }";
44 const TestVideoParam kTestVectors
[] = {
45 { "park_joy_90p_8_420.y4m", 8, AOM_IMG_FMT_I420
, AOM_BITS_8
, 0 },
46 { "park_joy_90p_8_422.y4m", 8, AOM_IMG_FMT_I422
, AOM_BITS_8
, 2 },
47 { "park_joy_90p_8_444.y4m", 8, AOM_IMG_FMT_I444
, AOM_BITS_8
, 1 },
48 #if CONFIG_AV1_HIGHBITDEPTH
49 { "park_joy_90p_10_420.y4m", 10, AOM_IMG_FMT_I42016
, AOM_BITS_10
, 0 },
50 { "park_joy_90p_10_422.y4m", 10, AOM_IMG_FMT_I42216
, AOM_BITS_10
, 2 },
51 { "park_joy_90p_10_444.y4m", 10, AOM_IMG_FMT_I44416
, AOM_BITS_10
, 1 },
52 { "park_joy_90p_12_420.y4m", 12, AOM_IMG_FMT_I42016
, AOM_BITS_12
, 2 },
53 { "park_joy_90p_12_422.y4m", 12, AOM_IMG_FMT_I42216
, AOM_BITS_12
, 2 },
54 { "park_joy_90p_12_444.y4m", 12, AOM_IMG_FMT_I44416
, AOM_BITS_12
, 2 },
58 // This class is used to check adherence to given ssim value.
59 class EndToEndSSIMTest
60 : public ::libaom_test::CodecTestWith3Params
<libaom_test::TestMode
,
62 public ::libaom_test::EncoderTest
{
65 : EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)),
66 test_video_param_(GET_PARAM(2)), cpu_used_(GET_PARAM(3)), nframes_(0),
69 ~EndToEndSSIMTest() override
= default;
71 void SetUp() override
{ InitializeConfig(encoding_mode_
); }
73 void BeginPassHook(unsigned int) override
{
78 void CalculateFrameLevelSSIM(const aom_image_t
*img_src
,
79 const aom_image_t
*img_enc
,
80 aom_bit_depth_t bit_depth
,
81 unsigned int input_bit_depth
) override
{
83 double plane_ssim
[MAX_MB_PLANE
] = { 0.0, 0.0, 0.0 };
84 int crop_widths
[PLANE_TYPES
];
85 int crop_heights
[PLANE_TYPES
];
86 crop_widths
[PLANE_TYPE_Y
] = img_src
->d_w
;
87 crop_heights
[PLANE_TYPE_Y
] = img_src
->d_h
;
88 // Width of UV planes calculated based on chroma_shift values.
89 crop_widths
[PLANE_TYPE_UV
] =
90 img_src
->x_chroma_shift
== 1 ? (img_src
->w
+ 1) >> 1 : img_src
->w
;
91 crop_heights
[PLANE_TYPE_UV
] =
92 img_src
->y_chroma_shift
== 1 ? (img_src
->h
+ 1) >> 1 : img_src
->h
;
95 #if CONFIG_AV1_HIGHBITDEPTH
96 uint8_t is_hbd
= bit_depth
> AOM_BITS_8
;
98 // HBD ssim calculation.
99 uint8_t shift
= bit_depth
- input_bit_depth
;
100 for (int i
= AOM_PLANE_Y
; i
< MAX_MB_PLANE
; ++i
) {
101 const int is_uv
= i
> AOM_PLANE_Y
;
102 plane_ssim
[i
] = aom_highbd_ssim2(
103 CONVERT_TO_BYTEPTR(img_src
->planes
[i
]),
104 CONVERT_TO_BYTEPTR(img_enc
->planes
[i
]),
105 img_src
->stride
[is_uv
] >> is_hbd
, img_enc
->stride
[is_uv
] >> is_hbd
,
106 crop_widths
[is_uv
], crop_heights
[is_uv
], input_bit_depth
, shift
);
108 frame_ssim
= plane_ssim
[AOM_PLANE_Y
] * .8 +
109 .1 * (plane_ssim
[AOM_PLANE_U
] + plane_ssim
[AOM_PLANE_V
]);
110 // Accumulate to find sequence level ssim value.
116 (void)input_bit_depth
;
117 #endif // CONFIG_AV1_HIGHBITDEPTH
119 // LBD ssim calculation.
120 for (int i
= AOM_PLANE_Y
; i
< MAX_MB_PLANE
; ++i
) {
121 const int is_uv
= i
> AOM_PLANE_Y
;
122 plane_ssim
[i
] = aom_ssim2(img_src
->planes
[i
], img_enc
->planes
[i
],
123 img_src
->stride
[is_uv
], img_enc
->stride
[is_uv
],
124 crop_widths
[is_uv
], crop_heights
[is_uv
]);
126 frame_ssim
= plane_ssim
[AOM_PLANE_Y
] * .8 +
127 .1 * (plane_ssim
[AOM_PLANE_U
] + plane_ssim
[AOM_PLANE_V
]);
128 // Accumulate to find sequence level ssim value.
132 void PreEncodeFrameHook(::libaom_test::VideoSource
*video
,
133 ::libaom_test::Encoder
*encoder
) override
{
134 if (video
->frame() == 0) {
135 encoder
->Control(AV1E_SET_FRAME_PARALLEL_DECODING
, 1);
136 encoder
->Control(AV1E_SET_TILE_COLUMNS
, 4);
137 encoder
->Control(AOME_SET_CPUUSED
, cpu_used_
);
138 encoder
->Control(AOME_SET_TUNING
, AOM_TUNE_SSIM
);
139 encoder
->Control(AOME_SET_CQ_LEVEL
, kCqLevel
);
143 double GetAverageSsim() const {
144 if (nframes_
) return 100 * pow(ssim_
/ nframes_
, 8.0);
148 double GetSsimThreshold() { return kSsimThreshold
[cpu_used_
]; }
151 cfg_
.g_profile
= test_video_param_
.profile
;
152 cfg_
.g_input_bit_depth
= test_video_param_
.input_bit_depth
;
153 cfg_
.g_bit_depth
= test_video_param_
.bit_depth
;
154 if (cfg_
.g_bit_depth
> 8) init_flags_
|= AOM_CODEC_USE_HIGHBITDEPTH
;
156 std::unique_ptr
<libaom_test::VideoSource
> video(
157 new libaom_test::Y4mVideoSource(test_video_param_
.filename
, 0,
159 ASSERT_NE(video
, nullptr);
160 ASSERT_NO_FATAL_FAILURE(RunLoop(video
.get()));
161 const double ssim
= GetAverageSsim();
162 EXPECT_GT(ssim
, GetSsimThreshold())
163 << "encoding mode = " << encoding_mode_
<< ", cpu used = " << cpu_used_
;
167 const libaom_test::TestMode encoding_mode_
;
168 const TestVideoParam test_video_param_
;
170 unsigned int nframes_
;
174 class EndToEndSSIMTestLarge
: public EndToEndSSIMTest
{};
176 TEST_P(EndToEndSSIMTestLarge
, EndtoEndSSIMTest
) { DoTest(); }
178 TEST_P(EndToEndSSIMTest
, EndtoEndSSIMTest
) { DoTest(); }
180 AV1_INSTANTIATE_TEST_SUITE(EndToEndSSIMTestLarge
,
181 ::testing::Values(::libaom_test::kAllIntra
),
182 ::testing::ValuesIn(kTestVectors
),
183 ::testing::Values(2, 4, 6, 8)); // cpu_used
185 AV1_INSTANTIATE_TEST_SUITE(EndToEndSSIMTest
,
186 ::testing::Values(::libaom_test::kAllIntra
),
187 ::testing::Values(kTestVectors
[0]), // 420
188 ::testing::Values(6)); // cpu_used