1*09537850SAkhilesh Sanikop // Copyright 2021 The libgav1 Authors
2*09537850SAkhilesh Sanikop //
3*09537850SAkhilesh Sanikop // Licensed under the Apache License, Version 2.0 (the "License");
4*09537850SAkhilesh Sanikop // you may not use this file except in compliance with the License.
5*09537850SAkhilesh Sanikop // You may obtain a copy of the License at
6*09537850SAkhilesh Sanikop //
7*09537850SAkhilesh Sanikop // http://www.apache.org/licenses/LICENSE-2.0
8*09537850SAkhilesh Sanikop //
9*09537850SAkhilesh Sanikop // Unless required by applicable law or agreed to in writing, software
10*09537850SAkhilesh Sanikop // distributed under the License is distributed on an "AS IS" BASIS,
11*09537850SAkhilesh Sanikop // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*09537850SAkhilesh Sanikop // See the License for the specific language governing permissions and
13*09537850SAkhilesh Sanikop // limitations under the License.
14*09537850SAkhilesh Sanikop
15*09537850SAkhilesh Sanikop #include "src/warp_prediction.h"
16*09537850SAkhilesh Sanikop
17*09537850SAkhilesh Sanikop #include <cstddef>
18*09537850SAkhilesh Sanikop #include <cstdint>
19*09537850SAkhilesh Sanikop #include <ostream>
20*09537850SAkhilesh Sanikop
21*09537850SAkhilesh Sanikop #include "absl/base/macros.h"
22*09537850SAkhilesh Sanikop #include "gtest/gtest.h"
23*09537850SAkhilesh Sanikop #include "src/obu_parser.h"
24*09537850SAkhilesh Sanikop #include "src/utils/common.h"
25*09537850SAkhilesh Sanikop #include "src/utils/constants.h"
26*09537850SAkhilesh Sanikop #include "src/utils/types.h"
27*09537850SAkhilesh Sanikop #include "tests/third_party/libvpx/acm_random.h"
28*09537850SAkhilesh Sanikop
29*09537850SAkhilesh Sanikop namespace libgav1 {
30*09537850SAkhilesh Sanikop namespace {
31*09537850SAkhilesh Sanikop
32*09537850SAkhilesh Sanikop constexpr int16_t kExpectedWarpParamsOutput[10][4] = {
33*09537850SAkhilesh Sanikop {0, 0, 0, 0},
34*09537850SAkhilesh Sanikop {2880, 2880, 2752, 2752},
35*09537850SAkhilesh Sanikop {-1408, -1408, -1472, -1472},
36*09537850SAkhilesh Sanikop {0, 0, 0, 0},
37*09537850SAkhilesh Sanikop {6784, 6784, 6144, 6144}, // Invalid.
38*09537850SAkhilesh Sanikop {-5312, -5312, -5824, -5824},
39*09537850SAkhilesh Sanikop {-3904, -3904, -4160, -4160},
40*09537850SAkhilesh Sanikop {2496, 2496, 2368, 2368},
41*09537850SAkhilesh Sanikop {1024, 1024, 1024, 1024},
42*09537850SAkhilesh Sanikop {-7808, -7808, -8832, -8832}, // Invalid.
43*09537850SAkhilesh Sanikop };
44*09537850SAkhilesh Sanikop
45*09537850SAkhilesh Sanikop constexpr bool kExpectedWarpValid[10] = {
46*09537850SAkhilesh Sanikop true, true, true, true, false, true, true, true, true, false,
47*09537850SAkhilesh Sanikop };
48*09537850SAkhilesh Sanikop
RandomWarpedParam(int seed_offset,int bits)49*09537850SAkhilesh Sanikop int RandomWarpedParam(int seed_offset, int bits) {
50*09537850SAkhilesh Sanikop libvpx_test::ACMRandom rnd(seed_offset +
51*09537850SAkhilesh Sanikop libvpx_test::ACMRandom::DeterministicSeed());
52*09537850SAkhilesh Sanikop // 1 in 8 chance of generating zero (arbitrary).
53*09537850SAkhilesh Sanikop const bool zero = (rnd.Rand16() & 7) == 0;
54*09537850SAkhilesh Sanikop if (zero) return 0;
55*09537850SAkhilesh Sanikop // Generate uniform values in the range [-(1 << bits), 1] U [1, 1 << bits].
56*09537850SAkhilesh Sanikop const int mask = (1 << bits) - 1;
57*09537850SAkhilesh Sanikop const int value = 1 + (rnd.RandRange(1U << 31) & mask);
58*09537850SAkhilesh Sanikop const bool sign = (rnd.Rand16() & 1) != 0;
59*09537850SAkhilesh Sanikop return sign ? value : -value;
60*09537850SAkhilesh Sanikop }
61*09537850SAkhilesh Sanikop
GenerateWarpedModel(GlobalMotion * warp_params,int seed)62*09537850SAkhilesh Sanikop void GenerateWarpedModel(GlobalMotion* warp_params, int seed) {
63*09537850SAkhilesh Sanikop do {
64*09537850SAkhilesh Sanikop warp_params->params[0] =
65*09537850SAkhilesh Sanikop RandomWarpedParam(seed, kWarpedModelPrecisionBits + 6);
66*09537850SAkhilesh Sanikop warp_params->params[1] =
67*09537850SAkhilesh Sanikop RandomWarpedParam(seed, kWarpedModelPrecisionBits + 6);
68*09537850SAkhilesh Sanikop warp_params->params[2] =
69*09537850SAkhilesh Sanikop RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3) +
70*09537850SAkhilesh Sanikop (1 << kWarpedModelPrecisionBits);
71*09537850SAkhilesh Sanikop warp_params->params[3] =
72*09537850SAkhilesh Sanikop RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3);
73*09537850SAkhilesh Sanikop warp_params->params[4] =
74*09537850SAkhilesh Sanikop RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3);
75*09537850SAkhilesh Sanikop warp_params->params[5] =
76*09537850SAkhilesh Sanikop RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3) +
77*09537850SAkhilesh Sanikop (1 << kWarpedModelPrecisionBits);
78*09537850SAkhilesh Sanikop } while (warp_params->params[2] == 0);
79*09537850SAkhilesh Sanikop }
80*09537850SAkhilesh Sanikop
TEST(WarpPredictionTest,SetupShear)81*09537850SAkhilesh Sanikop TEST(WarpPredictionTest, SetupShear) {
82*09537850SAkhilesh Sanikop for (size_t i = 0; i < ABSL_ARRAYSIZE(kExpectedWarpParamsOutput); ++i) {
83*09537850SAkhilesh Sanikop GlobalMotion warp_params;
84*09537850SAkhilesh Sanikop GenerateWarpedModel(&warp_params, static_cast<int>(i));
85*09537850SAkhilesh Sanikop const bool warp_valid = SetupShear(&warp_params);
86*09537850SAkhilesh Sanikop
87*09537850SAkhilesh Sanikop SCOPED_TRACE(testing::Message() << "Test failure at iteration: " << i);
88*09537850SAkhilesh Sanikop EXPECT_EQ(warp_valid, kExpectedWarpValid[i]);
89*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.alpha, kExpectedWarpParamsOutput[i][0]);
90*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.beta, kExpectedWarpParamsOutput[i][1]);
91*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.gamma, kExpectedWarpParamsOutput[i][2]);
92*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.delta, kExpectedWarpParamsOutput[i][3]);
93*09537850SAkhilesh Sanikop }
94*09537850SAkhilesh Sanikop
95*09537850SAkhilesh Sanikop // Test signed shift behavior in delta and gamma generation.
96*09537850SAkhilesh Sanikop GlobalMotion warp_params;
97*09537850SAkhilesh Sanikop warp_params.params[0] = 24748;
98*09537850SAkhilesh Sanikop warp_params.params[1] = -142530;
99*09537850SAkhilesh Sanikop warp_params.params[2] = 65516;
100*09537850SAkhilesh Sanikop warp_params.params[3] = -640;
101*09537850SAkhilesh Sanikop warp_params.params[4] = 256;
102*09537850SAkhilesh Sanikop warp_params.params[5] = 65310;
103*09537850SAkhilesh Sanikop EXPECT_TRUE(SetupShear(&warp_params));
104*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.alpha, 0);
105*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.beta, -640);
106*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.gamma, 256);
107*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.delta, -192);
108*09537850SAkhilesh Sanikop
109*09537850SAkhilesh Sanikop warp_params.params[0] = 24748;
110*09537850SAkhilesh Sanikop warp_params.params[1] = -142530;
111*09537850SAkhilesh Sanikop warp_params.params[2] = 61760;
112*09537850SAkhilesh Sanikop warp_params.params[3] = -640;
113*09537850SAkhilesh Sanikop warp_params.params[4] = -13312;
114*09537850SAkhilesh Sanikop warp_params.params[5] = 65310;
115*09537850SAkhilesh Sanikop EXPECT_TRUE(SetupShear(&warp_params));
116*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.alpha, -3776);
117*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.beta, -640);
118*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.gamma, -14144);
119*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.delta, -384);
120*09537850SAkhilesh Sanikop }
121*09537850SAkhilesh Sanikop
122*09537850SAkhilesh Sanikop struct WarpInputParam {
WarpInputParamlibgav1::__anona5d33bf00111::WarpInputParam123*09537850SAkhilesh Sanikop WarpInputParam(int num_samples, int block_width4x4, int block_height4x4)
124*09537850SAkhilesh Sanikop : num_samples(num_samples),
125*09537850SAkhilesh Sanikop block_width4x4(block_width4x4),
126*09537850SAkhilesh Sanikop block_height4x4(block_height4x4) {}
127*09537850SAkhilesh Sanikop int num_samples;
128*09537850SAkhilesh Sanikop int block_width4x4;
129*09537850SAkhilesh Sanikop int block_height4x4;
130*09537850SAkhilesh Sanikop };
131*09537850SAkhilesh Sanikop
operator <<(std::ostream & os,const WarpInputParam & param)132*09537850SAkhilesh Sanikop std::ostream& operator<<(std::ostream& os, const WarpInputParam& param) {
133*09537850SAkhilesh Sanikop return os << "num_samples: " << param.num_samples
134*09537850SAkhilesh Sanikop << ", block_(width/height)4x4: " << param.block_width4x4 << "x"
135*09537850SAkhilesh Sanikop << param.block_height4x4;
136*09537850SAkhilesh Sanikop }
137*09537850SAkhilesh Sanikop
138*09537850SAkhilesh Sanikop const WarpInputParam warp_test_param[] = {
139*09537850SAkhilesh Sanikop // sample = 1.
140*09537850SAkhilesh Sanikop WarpInputParam(1, 1, 1),
141*09537850SAkhilesh Sanikop WarpInputParam(1, 1, 2),
142*09537850SAkhilesh Sanikop WarpInputParam(1, 2, 1),
143*09537850SAkhilesh Sanikop WarpInputParam(1, 2, 2),
144*09537850SAkhilesh Sanikop WarpInputParam(1, 2, 4),
145*09537850SAkhilesh Sanikop WarpInputParam(1, 4, 2),
146*09537850SAkhilesh Sanikop WarpInputParam(1, 4, 4),
147*09537850SAkhilesh Sanikop WarpInputParam(1, 4, 8),
148*09537850SAkhilesh Sanikop WarpInputParam(1, 8, 4),
149*09537850SAkhilesh Sanikop WarpInputParam(1, 8, 8),
150*09537850SAkhilesh Sanikop WarpInputParam(1, 8, 16),
151*09537850SAkhilesh Sanikop WarpInputParam(1, 16, 8),
152*09537850SAkhilesh Sanikop WarpInputParam(1, 16, 16),
153*09537850SAkhilesh Sanikop WarpInputParam(1, 16, 32),
154*09537850SAkhilesh Sanikop WarpInputParam(1, 32, 16),
155*09537850SAkhilesh Sanikop WarpInputParam(1, 32, 32),
156*09537850SAkhilesh Sanikop // sample = 8.
157*09537850SAkhilesh Sanikop WarpInputParam(8, 1, 1),
158*09537850SAkhilesh Sanikop WarpInputParam(8, 1, 2),
159*09537850SAkhilesh Sanikop WarpInputParam(8, 2, 1),
160*09537850SAkhilesh Sanikop WarpInputParam(8, 2, 2),
161*09537850SAkhilesh Sanikop WarpInputParam(8, 2, 4),
162*09537850SAkhilesh Sanikop WarpInputParam(8, 4, 2),
163*09537850SAkhilesh Sanikop WarpInputParam(8, 4, 4),
164*09537850SAkhilesh Sanikop WarpInputParam(8, 4, 8),
165*09537850SAkhilesh Sanikop WarpInputParam(8, 8, 4),
166*09537850SAkhilesh Sanikop WarpInputParam(8, 8, 8),
167*09537850SAkhilesh Sanikop WarpInputParam(8, 8, 16),
168*09537850SAkhilesh Sanikop WarpInputParam(8, 16, 8),
169*09537850SAkhilesh Sanikop WarpInputParam(8, 16, 16),
170*09537850SAkhilesh Sanikop WarpInputParam(8, 16, 32),
171*09537850SAkhilesh Sanikop WarpInputParam(8, 32, 16),
172*09537850SAkhilesh Sanikop WarpInputParam(8, 32, 32),
173*09537850SAkhilesh Sanikop };
174*09537850SAkhilesh Sanikop
175*09537850SAkhilesh Sanikop constexpr bool kExpectedWarpEstimationValid[2] = {false, true};
176*09537850SAkhilesh Sanikop
177*09537850SAkhilesh Sanikop constexpr int kExpectedWarpEstimationOutput[16][6] = {
178*09537850SAkhilesh Sanikop {8388607, 8388607, 57345, -8191, -8191, 57345},
179*09537850SAkhilesh Sanikop {8388607, 8388607, 57345, -8191, -8191, 57345},
180*09537850SAkhilesh Sanikop {8388607, 8388607, 57345, -8191, -8191, 57345},
181*09537850SAkhilesh Sanikop {8388607, 8388607, 57345, -8191, -8191, 57345},
182*09537850SAkhilesh Sanikop {8388607, 8388607, 57345, -8191, -8191, 57345},
183*09537850SAkhilesh Sanikop {8388607, 8388607, 57345, -8191, -8191, 57345},
184*09537850SAkhilesh Sanikop {8388607, 8388607, 57345, -8191, -8191, 57345},
185*09537850SAkhilesh Sanikop {8388607, 8388607, 57345, -8191, -8191, 57345},
186*09537850SAkhilesh Sanikop {8388607, 8388607, 57345, -8191, -8191, 57345},
187*09537850SAkhilesh Sanikop {8388607, 8388607, 57345, -8191, -8191, 57345},
188*09537850SAkhilesh Sanikop {2146296, 1589240, 57345, 8191, -8191, 73727},
189*09537850SAkhilesh Sanikop {1753128, 1196072, 73727, -8191, 8191, 57345},
190*09537850SAkhilesh Sanikop {-8388608, -8388608, 73727, 8191, 8191, 73727},
191*09537850SAkhilesh Sanikop {-4435485, -8388608, 65260, 8191, 8191, 73727},
192*09537850SAkhilesh Sanikop {-8388608, -7552929, 73727, 8191, 8191, 68240},
193*09537850SAkhilesh Sanikop {-8388608, -8388608, 73727, 8191, 8191, 70800},
194*09537850SAkhilesh Sanikop };
195*09537850SAkhilesh Sanikop
196*09537850SAkhilesh Sanikop class WarpEstimationTest : public testing::TestWithParam<WarpInputParam> {
197*09537850SAkhilesh Sanikop public:
198*09537850SAkhilesh Sanikop WarpEstimationTest() = default;
199*09537850SAkhilesh Sanikop ~WarpEstimationTest() override = default;
200*09537850SAkhilesh Sanikop
201*09537850SAkhilesh Sanikop protected:
202*09537850SAkhilesh Sanikop WarpInputParam param_ = GetParam();
203*09537850SAkhilesh Sanikop };
204*09537850SAkhilesh Sanikop
TEST_P(WarpEstimationTest,WarpEstimation)205*09537850SAkhilesh Sanikop TEST_P(WarpEstimationTest, WarpEstimation) {
206*09537850SAkhilesh Sanikop // Set input params.
207*09537850SAkhilesh Sanikop libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
208*09537850SAkhilesh Sanikop const int row4x4 = rnd.Rand8();
209*09537850SAkhilesh Sanikop const int column4x4 = rnd.Rand8();
210*09537850SAkhilesh Sanikop MotionVector mv;
211*09537850SAkhilesh Sanikop mv.mv[0] = rnd.Rand8();
212*09537850SAkhilesh Sanikop mv.mv[1] = rnd.Rand8();
213*09537850SAkhilesh Sanikop int candidates[kMaxLeastSquaresSamples][4];
214*09537850SAkhilesh Sanikop for (int i = 0; i < param_.num_samples; ++i) {
215*09537850SAkhilesh Sanikop // Make candidates relative to the top left of frame.
216*09537850SAkhilesh Sanikop candidates[i][0] = rnd.Rand8() + MultiplyBy32(row4x4);
217*09537850SAkhilesh Sanikop candidates[i][1] = rnd.Rand8() + MultiplyBy32(column4x4);
218*09537850SAkhilesh Sanikop candidates[i][2] = rnd.Rand8() + MultiplyBy32(row4x4);
219*09537850SAkhilesh Sanikop candidates[i][3] = rnd.Rand8() + MultiplyBy32(column4x4);
220*09537850SAkhilesh Sanikop }
221*09537850SAkhilesh Sanikop
222*09537850SAkhilesh Sanikop // Get output.
223*09537850SAkhilesh Sanikop GlobalMotion warp_params;
224*09537850SAkhilesh Sanikop const bool warp_success = WarpEstimation(
225*09537850SAkhilesh Sanikop param_.num_samples, param_.block_width4x4, param_.block_height4x4, row4x4,
226*09537850SAkhilesh Sanikop column4x4, mv, candidates, &warp_params);
227*09537850SAkhilesh Sanikop if (param_.num_samples == 1) {
228*09537850SAkhilesh Sanikop EXPECT_EQ(warp_success, kExpectedWarpEstimationValid[0]);
229*09537850SAkhilesh Sanikop } else {
230*09537850SAkhilesh Sanikop EXPECT_EQ(warp_success, kExpectedWarpEstimationValid[1]);
231*09537850SAkhilesh Sanikop int index = FloorLog2(param_.block_width4x4) * 3 - 1;
232*09537850SAkhilesh Sanikop if (param_.block_width4x4 == param_.block_height4x4) {
233*09537850SAkhilesh Sanikop index += 1;
234*09537850SAkhilesh Sanikop } else if (param_.block_width4x4 < param_.block_height4x4) {
235*09537850SAkhilesh Sanikop index += 2;
236*09537850SAkhilesh Sanikop }
237*09537850SAkhilesh Sanikop for (size_t i = 0; i < ABSL_ARRAYSIZE(warp_params.params); ++i) {
238*09537850SAkhilesh Sanikop EXPECT_EQ(warp_params.params[i], kExpectedWarpEstimationOutput[index][i]);
239*09537850SAkhilesh Sanikop }
240*09537850SAkhilesh Sanikop }
241*09537850SAkhilesh Sanikop }
242*09537850SAkhilesh Sanikop
243*09537850SAkhilesh Sanikop INSTANTIATE_TEST_SUITE_P(WarpFuncTest, WarpEstimationTest,
244*09537850SAkhilesh Sanikop testing::ValuesIn(warp_test_param));
245*09537850SAkhilesh Sanikop } // namespace
246*09537850SAkhilesh Sanikop } // namespace libgav1
247