aboutsummaryrefslogtreecommitdiff
path: root/src/warp_prediction_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/warp_prediction_test.cc')
-rw-r--r--src/warp_prediction_test.cc246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/warp_prediction_test.cc b/src/warp_prediction_test.cc
new file mode 100644
index 0000000..46f262f
--- /dev/null
+++ b/src/warp_prediction_test.cc
@@ -0,0 +1,246 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/warp_prediction.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <ostream>
+
+#include "absl/base/macros.h"
+#include "gtest/gtest.h"
+#include "src/obu_parser.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/types.h"
+#include "tests/third_party/libvpx/acm_random.h"
+
+namespace libgav1 {
+namespace {
+
+constexpr int16_t kExpectedWarpParamsOutput[10][4] = {
+ {0, 0, 0, 0},
+ {2880, 2880, 2752, 2752},
+ {-1408, -1408, -1472, -1472},
+ {0, 0, 0, 0},
+ {6784, 6784, 6144, 6144}, // Invalid.
+ {-5312, -5312, -5824, -5824},
+ {-3904, -3904, -4160, -4160},
+ {2496, 2496, 2368, 2368},
+ {1024, 1024, 1024, 1024},
+ {-7808, -7808, -8832, -8832}, // Invalid.
+};
+
+constexpr bool kExpectedWarpValid[10] = {
+ true, true, true, true, false, true, true, true, true, false,
+};
+
+int RandomWarpedParam(int seed_offset, int bits) {
+ libvpx_test::ACMRandom rnd(seed_offset +
+ libvpx_test::ACMRandom::DeterministicSeed());
+ // 1 in 8 chance of generating zero (arbitrary).
+ const bool zero = (rnd.Rand16() & 7) == 0;
+ if (zero) return 0;
+ // Generate uniform values in the range [-(1 << bits), 1] U [1, 1 << bits].
+ const int mask = (1 << bits) - 1;
+ const int value = 1 + (rnd.RandRange(1U << 31) & mask);
+ const bool sign = (rnd.Rand16() & 1) != 0;
+ return sign ? value : -value;
+}
+
+void GenerateWarpedModel(GlobalMotion* warp_params, int seed) {
+ do {
+ warp_params->params[0] =
+ RandomWarpedParam(seed, kWarpedModelPrecisionBits + 6);
+ warp_params->params[1] =
+ RandomWarpedParam(seed, kWarpedModelPrecisionBits + 6);
+ warp_params->params[2] =
+ RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3) +
+ (1 << kWarpedModelPrecisionBits);
+ warp_params->params[3] =
+ RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3);
+ warp_params->params[4] =
+ RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3);
+ warp_params->params[5] =
+ RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3) +
+ (1 << kWarpedModelPrecisionBits);
+ } while (warp_params->params[2] == 0);
+}
+
+TEST(WarpPredictionTest, SetupShear) {
+ for (size_t i = 0; i < ABSL_ARRAYSIZE(kExpectedWarpParamsOutput); ++i) {
+ GlobalMotion warp_params;
+ GenerateWarpedModel(&warp_params, static_cast<int>(i));
+ const bool warp_valid = SetupShear(&warp_params);
+
+ SCOPED_TRACE(testing::Message() << "Test failure at iteration: " << i);
+ EXPECT_EQ(warp_valid, kExpectedWarpValid[i]);
+ EXPECT_EQ(warp_params.alpha, kExpectedWarpParamsOutput[i][0]);
+ EXPECT_EQ(warp_params.beta, kExpectedWarpParamsOutput[i][1]);
+ EXPECT_EQ(warp_params.gamma, kExpectedWarpParamsOutput[i][2]);
+ EXPECT_EQ(warp_params.delta, kExpectedWarpParamsOutput[i][3]);
+ }
+
+ // Test signed shift behavior in delta and gamma generation.
+ GlobalMotion warp_params;
+ warp_params.params[0] = 24748;
+ warp_params.params[1] = -142530;
+ warp_params.params[2] = 65516;
+ warp_params.params[3] = -640;
+ warp_params.params[4] = 256;
+ warp_params.params[5] = 65310;
+ EXPECT_TRUE(SetupShear(&warp_params));
+ EXPECT_EQ(warp_params.alpha, 0);
+ EXPECT_EQ(warp_params.beta, -640);
+ EXPECT_EQ(warp_params.gamma, 256);
+ EXPECT_EQ(warp_params.delta, -192);
+
+ warp_params.params[0] = 24748;
+ warp_params.params[1] = -142530;
+ warp_params.params[2] = 61760;
+ warp_params.params[3] = -640;
+ warp_params.params[4] = -13312;
+ warp_params.params[5] = 65310;
+ EXPECT_TRUE(SetupShear(&warp_params));
+ EXPECT_EQ(warp_params.alpha, -3776);
+ EXPECT_EQ(warp_params.beta, -640);
+ EXPECT_EQ(warp_params.gamma, -14144);
+ EXPECT_EQ(warp_params.delta, -384);
+}
+
+struct WarpInputParam {
+ WarpInputParam(int num_samples, int block_width4x4, int block_height4x4)
+ : num_samples(num_samples),
+ block_width4x4(block_width4x4),
+ block_height4x4(block_height4x4) {}
+ int num_samples;
+ int block_width4x4;
+ int block_height4x4;
+};
+
+std::ostream& operator<<(std::ostream& os, const WarpInputParam& param) {
+ return os << "num_samples: " << param.num_samples
+ << ", block_(width/height)4x4: " << param.block_width4x4 << "x"
+ << param.block_height4x4;
+}
+
+const WarpInputParam warp_test_param[] = {
+ // sample = 1.
+ WarpInputParam(1, 1, 1),
+ WarpInputParam(1, 1, 2),
+ WarpInputParam(1, 2, 1),
+ WarpInputParam(1, 2, 2),
+ WarpInputParam(1, 2, 4),
+ WarpInputParam(1, 4, 2),
+ WarpInputParam(1, 4, 4),
+ WarpInputParam(1, 4, 8),
+ WarpInputParam(1, 8, 4),
+ WarpInputParam(1, 8, 8),
+ WarpInputParam(1, 8, 16),
+ WarpInputParam(1, 16, 8),
+ WarpInputParam(1, 16, 16),
+ WarpInputParam(1, 16, 32),
+ WarpInputParam(1, 32, 16),
+ WarpInputParam(1, 32, 32),
+ // sample = 8.
+ WarpInputParam(8, 1, 1),
+ WarpInputParam(8, 1, 2),
+ WarpInputParam(8, 2, 1),
+ WarpInputParam(8, 2, 2),
+ WarpInputParam(8, 2, 4),
+ WarpInputParam(8, 4, 2),
+ WarpInputParam(8, 4, 4),
+ WarpInputParam(8, 4, 8),
+ WarpInputParam(8, 8, 4),
+ WarpInputParam(8, 8, 8),
+ WarpInputParam(8, 8, 16),
+ WarpInputParam(8, 16, 8),
+ WarpInputParam(8, 16, 16),
+ WarpInputParam(8, 16, 32),
+ WarpInputParam(8, 32, 16),
+ WarpInputParam(8, 32, 32),
+};
+
+constexpr bool kExpectedWarpEstimationValid[2] = {false, true};
+
+constexpr int kExpectedWarpEstimationOutput[16][6] = {
+ {8388607, 8388607, 57345, -8191, -8191, 57345},
+ {8388607, 8388607, 57345, -8191, -8191, 57345},
+ {8388607, 8388607, 57345, -8191, -8191, 57345},
+ {8388607, 8388607, 57345, -8191, -8191, 57345},
+ {8388607, 8388607, 57345, -8191, -8191, 57345},
+ {8388607, 8388607, 57345, -8191, -8191, 57345},
+ {8388607, 8388607, 57345, -8191, -8191, 57345},
+ {8388607, 8388607, 57345, -8191, -8191, 57345},
+ {8388607, 8388607, 57345, -8191, -8191, 57345},
+ {8388607, 8388607, 57345, -8191, -8191, 57345},
+ {2146296, 1589240, 57345, 8191, -8191, 73727},
+ {1753128, 1196072, 73727, -8191, 8191, 57345},
+ {-8388608, -8388608, 73727, 8191, 8191, 73727},
+ {-4435485, -8388608, 65260, 8191, 8191, 73727},
+ {-8388608, -7552929, 73727, 8191, 8191, 68240},
+ {-8388608, -8388608, 73727, 8191, 8191, 70800},
+};
+
+class WarpEstimationTest : public testing::TestWithParam<WarpInputParam> {
+ public:
+ WarpEstimationTest() = default;
+ ~WarpEstimationTest() override = default;
+
+ protected:
+ WarpInputParam param_ = GetParam();
+};
+
+TEST_P(WarpEstimationTest, WarpEstimation) {
+ // Set input params.
+ libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+ const int row4x4 = rnd.Rand8();
+ const int column4x4 = rnd.Rand8();
+ MotionVector mv;
+ mv.mv[0] = rnd.Rand8();
+ mv.mv[1] = rnd.Rand8();
+ int candidates[kMaxLeastSquaresSamples][4];
+ for (int i = 0; i < param_.num_samples; ++i) {
+ // Make candidates relative to the top left of frame.
+ candidates[i][0] = rnd.Rand8() + MultiplyBy32(row4x4);
+ candidates[i][1] = rnd.Rand8() + MultiplyBy32(column4x4);
+ candidates[i][2] = rnd.Rand8() + MultiplyBy32(row4x4);
+ candidates[i][3] = rnd.Rand8() + MultiplyBy32(column4x4);
+ }
+
+ // Get output.
+ GlobalMotion warp_params;
+ const bool warp_success = WarpEstimation(
+ param_.num_samples, param_.block_width4x4, param_.block_height4x4, row4x4,
+ column4x4, mv, candidates, &warp_params);
+ if (param_.num_samples == 1) {
+ EXPECT_EQ(warp_success, kExpectedWarpEstimationValid[0]);
+ } else {
+ EXPECT_EQ(warp_success, kExpectedWarpEstimationValid[1]);
+ int index = FloorLog2(param_.block_width4x4) * 3 - 1;
+ if (param_.block_width4x4 == param_.block_height4x4) {
+ index += 1;
+ } else if (param_.block_width4x4 < param_.block_height4x4) {
+ index += 2;
+ }
+ for (size_t i = 0; i < ABSL_ARRAYSIZE(warp_params.params); ++i) {
+ EXPECT_EQ(warp_params.params[i], kExpectedWarpEstimationOutput[index][i]);
+ }
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(WarpFuncTest, WarpEstimationTest,
+ testing::ValuesIn(warp_test_param));
+} // namespace
+} // namespace libgav1