diff options
Diffstat (limited to 'src/warp_prediction_test.cc')
-rw-r--r-- | src/warp_prediction_test.cc | 246 |
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 |