1 /*
2 * Copyright (c) 2022, Alliance for Open Media. All rights reserved.
3 *
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.
10 */
11
12 #include "av1/encoder/cost.h"
13 #include "av1/encoder/encodemv.h"
14 #include "gtest/gtest.h"
15
16 namespace {
17
ReferenceBuildNmvComponentCostTable(int * mvcost,const nmv_component * const mvcomp,MvSubpelPrecision precision)18 void ReferenceBuildNmvComponentCostTable(int *mvcost,
19 const nmv_component *const mvcomp,
20 MvSubpelPrecision precision) {
21 int i, v;
22 int sign_cost[2], class_cost[MV_CLASSES], class0_cost[CLASS0_SIZE];
23 int bits_cost[MV_OFFSET_BITS][2];
24 int class0_fp_cost[CLASS0_SIZE][MV_FP_SIZE], fp_cost[MV_FP_SIZE];
25 int class0_hp_cost[2], hp_cost[2];
26 av1_cost_tokens_from_cdf(sign_cost, mvcomp->sign_cdf, nullptr);
27 av1_cost_tokens_from_cdf(class_cost, mvcomp->classes_cdf, nullptr);
28 av1_cost_tokens_from_cdf(class0_cost, mvcomp->class0_cdf, nullptr);
29 for (i = 0; i < MV_OFFSET_BITS; ++i) {
30 av1_cost_tokens_from_cdf(bits_cost[i], mvcomp->bits_cdf[i], nullptr);
31 }
32 for (i = 0; i < CLASS0_SIZE; ++i)
33 av1_cost_tokens_from_cdf(class0_fp_cost[i], mvcomp->class0_fp_cdf[i],
34 nullptr);
35 av1_cost_tokens_from_cdf(fp_cost, mvcomp->fp_cdf, nullptr);
36 if (precision > MV_SUBPEL_LOW_PRECISION) {
37 av1_cost_tokens_from_cdf(class0_hp_cost, mvcomp->class0_hp_cdf, nullptr);
38 av1_cost_tokens_from_cdf(hp_cost, mvcomp->hp_cdf, nullptr);
39 }
40 mvcost[0] = 0;
41 for (v = 1; v <= MV_MAX; ++v) {
42 int z, c, o, d, e, f, cost = 0;
43 z = v - 1;
44 c = av1_get_mv_class(z, &o);
45 cost += class_cost[c];
46 d = (o >> 3); /* int mv data */
47 f = (o >> 1) & 3; /* fractional pel mv data */
48 e = (o & 1); /* high precision mv data */
49 if (c == MV_CLASS_0) {
50 cost += class0_cost[d];
51 } else {
52 const int b = c + CLASS0_BITS - 1; /* number of bits */
53 for (i = 0; i < b; ++i) cost += bits_cost[i][((d >> i) & 1)];
54 }
55 if (precision > MV_SUBPEL_NONE) {
56 if (c == MV_CLASS_0) {
57 cost += class0_fp_cost[d][f];
58 } else {
59 cost += fp_cost[f];
60 }
61 if (precision > MV_SUBPEL_LOW_PRECISION) {
62 if (c == MV_CLASS_0) {
63 cost += class0_hp_cost[e];
64 } else {
65 cost += hp_cost[e];
66 }
67 }
68 }
69 mvcost[v] = cost + sign_cost[0];
70 mvcost[-v] = cost + sign_cost[1];
71 }
72 }
73
74 // Test using the default context, except for sign
75 static const nmv_component kTestComponentContext = {
76 { AOM_CDF11(28672, 30976, 31858, 32320, 32551, 32656, 32740, 32757, 32762,
77 32767) }, // class_cdf // fp
78 { { AOM_CDF4(16384, 24576, 26624) },
79 { AOM_CDF4(12288, 21248, 24128) } }, // class0_fp_cdf
80 { AOM_CDF4(8192, 17408, 21248) }, // fp_cdf
81 { AOM_CDF2(70 * 128) }, // sign_cdf
82 { AOM_CDF2(160 * 128) }, // class0_hp_cdf
83 { AOM_CDF2(128 * 128) }, // hp_cdf
84 { AOM_CDF2(216 * 128) }, // class0_cdf
85 { { AOM_CDF2(128 * 136) },
86 { AOM_CDF2(128 * 140) },
87 { AOM_CDF2(128 * 148) },
88 { AOM_CDF2(128 * 160) },
89 { AOM_CDF2(128 * 176) },
90 { AOM_CDF2(128 * 192) },
91 { AOM_CDF2(128 * 224) },
92 { AOM_CDF2(128 * 234) },
93 { AOM_CDF2(128 * 234) },
94 { AOM_CDF2(128 * 240) } }, // bits_cdf
95 };
96
TestMvComponentCostTable(MvSubpelPrecision precision)97 void TestMvComponentCostTable(MvSubpelPrecision precision) {
98 std::unique_ptr<int[]> mvcost_ref_buf(new int[MV_VALS]);
99 std::unique_ptr<int[]> mvcost_buf(new int[MV_VALS]);
100 int *mvcost_ref = mvcost_ref_buf.get() + MV_MAX;
101 int *mvcost = mvcost_buf.get() + MV_MAX;
102
103 ReferenceBuildNmvComponentCostTable(mvcost_ref, &kTestComponentContext,
104 precision);
105 av1_build_nmv_component_cost_table(mvcost, &kTestComponentContext, precision);
106
107 for (int v = 0; v <= MV_MAX; ++v) {
108 ASSERT_EQ(mvcost_ref[v], mvcost[v]) << "v = " << v;
109 ASSERT_EQ(mvcost_ref[-v], mvcost[-v]) << "v = " << v;
110 }
111 }
112
TEST(MvCostTest,BuildMvComponentCostTableTest1)113 TEST(MvCostTest, BuildMvComponentCostTableTest1) {
114 TestMvComponentCostTable(MV_SUBPEL_NONE);
115 }
116
TEST(MvCostTest,BuildMvComponentCostTableTest2)117 TEST(MvCostTest, BuildMvComponentCostTableTest2) {
118 TestMvComponentCostTable(MV_SUBPEL_LOW_PRECISION);
119 }
120
TEST(MvCostTest,BuildMvComponentCostTableTest3)121 TEST(MvCostTest, BuildMvComponentCostTableTest3) {
122 TestMvComponentCostTable(MV_SUBPEL_HIGH_PRECISION);
123 }
124
125 } // namespace