1 // Copyright 2019 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/warp_prediction.h"
16
17 #include <cmath>
18 #include <cstdint>
19 #include <cstdlib>
20
21 #include "src/tile.h"
22 #include "src/utils/block_parameters_holder.h"
23 #include "src/utils/common.h"
24 #include "src/utils/constants.h"
25 #include "src/utils/logging.h"
26
27 namespace libgav1 {
28 namespace {
29
30 constexpr int kWarpModelTranslationClamp = 1 << 23;
31 constexpr int kWarpModelAffineClamp = 1 << 13;
32 constexpr int kLargestMotionVectorDiff = 256;
33
34 constexpr uint16_t kDivisorLookup[257] = {
35 16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948, 15888, 15828, 15768,
36 15709, 15650, 15592, 15534, 15477, 15420, 15364, 15308, 15252, 15197, 15142,
37 15087, 15033, 14980, 14926, 14873, 14821, 14769, 14717, 14665, 14614, 14564,
38 14513, 14463, 14413, 14364, 14315, 14266, 14218, 14170, 14122, 14075, 14028,
39 13981, 13935, 13888, 13843, 13797, 13752, 13707, 13662, 13618, 13574, 13530,
40 13487, 13443, 13400, 13358, 13315, 13273, 13231, 13190, 13148, 13107, 13066,
41 13026, 12985, 12945, 12906, 12866, 12827, 12788, 12749, 12710, 12672, 12633,
42 12596, 12558, 12520, 12483, 12446, 12409, 12373, 12336, 12300, 12264, 12228,
43 12193, 12157, 12122, 12087, 12053, 12018, 11984, 11950, 11916, 11882, 11848,
44 11815, 11782, 11749, 11716, 11683, 11651, 11619, 11586, 11555, 11523, 11491,
45 11460, 11429, 11398, 11367, 11336, 11305, 11275, 11245, 11215, 11185, 11155,
46 11125, 11096, 11067, 11038, 11009, 10980, 10951, 10923, 10894, 10866, 10838,
47 10810, 10782, 10755, 10727, 10700, 10673, 10645, 10618, 10592, 10565, 10538,
48 10512, 10486, 10460, 10434, 10408, 10382, 10356, 10331, 10305, 10280, 10255,
49 10230, 10205, 10180, 10156, 10131, 10107, 10082, 10058, 10034, 10010, 9986,
50 9963, 9939, 9916, 9892, 9869, 9846, 9823, 9800, 9777, 9754, 9732,
51 9709, 9687, 9664, 9642, 9620, 9598, 9576, 9554, 9533, 9511, 9489,
52 9468, 9447, 9425, 9404, 9383, 9362, 9341, 9321, 9300, 9279, 9259,
53 9239, 9218, 9198, 9178, 9158, 9138, 9118, 9098, 9079, 9059, 9039,
54 9020, 9001, 8981, 8962, 8943, 8924, 8905, 8886, 8867, 8849, 8830,
55 8812, 8793, 8775, 8756, 8738, 8720, 8702, 8684, 8666, 8648, 8630,
56 8613, 8595, 8577, 8560, 8542, 8525, 8508, 8490, 8473, 8456, 8439,
57 8422, 8405, 8389, 8372, 8355, 8339, 8322, 8306, 8289, 8273, 8257,
58 8240, 8224, 8208, 8192};
59
60 // Number of fractional bits of lookup in divisor lookup table.
61 constexpr int kDivisorLookupBits = 8;
62 // Number of fractional bits of entries in divisor lookup table.
63 constexpr int kDivisorLookupPrecisionBits = 14;
64
65 // 7.11.3.7.
66 template <typename T>
GenerateApproximateDivisor(T value,int16_t * division_factor,int16_t * division_shift)67 void GenerateApproximateDivisor(T value, int16_t* division_factor,
68 int16_t* division_shift) {
69 const int n = FloorLog2(std::abs(value));
70 const T e = std::abs(value) - (static_cast<T>(1) << n);
71 const int entry = (n > kDivisorLookupBits)
72 ? RightShiftWithRounding(e, n - kDivisorLookupBits)
73 : static_cast<int>(e << (kDivisorLookupBits - n));
74 *division_shift = n + kDivisorLookupPrecisionBits;
75 *division_factor =
76 (value < 0) ? -kDivisorLookup[entry] : kDivisorLookup[entry];
77 }
78
79 // 7.11.3.8.
LeastSquareProduct(int a,int b)80 int LeastSquareProduct(int a, int b) { return ((a * b) >> 2) + a + b; }
81
82 // 7.11.3.8.
DiagonalClamp(int32_t value)83 int DiagonalClamp(int32_t value) {
84 return Clip3(value,
85 (1 << kWarpedModelPrecisionBits) - kWarpModelAffineClamp + 1,
86 (1 << kWarpedModelPrecisionBits) + kWarpModelAffineClamp - 1);
87 }
88
89 // 7.11.3.8.
NonDiagonalClamp(int32_t value)90 int NonDiagonalClamp(int32_t value) {
91 return Clip3(value, -kWarpModelAffineClamp + 1, kWarpModelAffineClamp - 1);
92 }
93
GetShearParameter(int value)94 int16_t GetShearParameter(int value) {
95 return static_cast<int16_t>(
96 LeftShift(RightShiftWithRoundingSigned(Clip3(value, INT16_MIN, INT16_MAX),
97 kWarpParamRoundingBits),
98 kWarpParamRoundingBits));
99 }
100
101 } // namespace
102
SetupShear(GlobalMotion * const warp_params)103 bool SetupShear(GlobalMotion* const warp_params) {
104 int16_t division_shift;
105 int16_t division_factor;
106 const auto* const params = warp_params->params;
107 GenerateApproximateDivisor<int32_t>(params[2], &division_factor,
108 &division_shift);
109 const int alpha = params[2] - (1 << kWarpedModelPrecisionBits);
110 const int beta = params[3];
111 const int64_t v = LeftShift(params[4], kWarpedModelPrecisionBits);
112 const int gamma =
113 RightShiftWithRoundingSigned(v * division_factor, division_shift);
114 const int64_t w = static_cast<int64_t>(params[3]) * params[4];
115 const int delta =
116 params[5] -
117 RightShiftWithRoundingSigned(w * division_factor, division_shift) -
118 (1 << kWarpedModelPrecisionBits);
119
120 warp_params->alpha = GetShearParameter(alpha);
121 warp_params->beta = GetShearParameter(beta);
122 warp_params->gamma = GetShearParameter(gamma);
123 warp_params->delta = GetShearParameter(delta);
124 if ((4 * std::abs(warp_params->alpha) + 7 * std::abs(warp_params->beta) >=
125 (1 << kWarpedModelPrecisionBits)) ||
126 (4 * std::abs(warp_params->gamma) + 4 * std::abs(warp_params->delta) >=
127 (1 << kWarpedModelPrecisionBits))) {
128 return false; // NOLINT (easier condition to understand).
129 }
130
131 return true;
132 }
133
WarpEstimation(const int num_samples,const int block_width4x4,const int block_height4x4,const int row4x4,const int column4x4,const MotionVector & mv,const int candidates[kMaxLeastSquaresSamples][4],GlobalMotion * const warp_params)134 bool WarpEstimation(const int num_samples, const int block_width4x4,
135 const int block_height4x4, const int row4x4,
136 const int column4x4, const MotionVector& mv,
137 const int candidates[kMaxLeastSquaresSamples][4],
138 GlobalMotion* const warp_params) {
139 // |a| fits into int32_t. To avoid cast to int64_t in the following
140 // computation, we declare |a| as int64_t.
141 int64_t a[2][2] = {};
142 int bx[2] = {};
143 int by[2] = {};
144
145 // Note: for simplicity, the spec always uses absolute coordinates
146 // in the warp estimation process. subpixel_mid_x, subpixel_mid_y,
147 // and candidates are relative to the top left of the frame.
148 // In contrast, libaom uses a mixture of coordinate systems.
149 // In av1/common/warped_motion.c:find_affine_int(). The coordinate is relative
150 // to the top left of the block.
151 // mid_y/mid_x: the row/column coordinate of the center of the block.
152 const int mid_y = MultiplyBy4(row4x4) + MultiplyBy2(block_height4x4) - 1;
153 const int mid_x = MultiplyBy4(column4x4) + MultiplyBy2(block_width4x4) - 1;
154 const int subpixel_mid_y = MultiplyBy8(mid_y);
155 const int subpixel_mid_x = MultiplyBy8(mid_x);
156 const int reference_subpixel_mid_y =
157 subpixel_mid_y + mv.mv[MotionVector::kRow];
158 const int reference_subpixel_mid_x =
159 subpixel_mid_x + mv.mv[MotionVector::kColumn];
160
161 for (int i = 0; i < num_samples; ++i) {
162 // candidates[][0] and candidates[][1] are the row/column coordinates of the
163 // sample point in this block, to the top left of the frame.
164 // candidates[][2] and candidates[][3] are the row/column coordinates of the
165 // sample point in this reference block, to the top left of the frame.
166 // sy/sx: the row/column coordinates of the sample point, with center of
167 // the block as origin.
168 const int sy = candidates[i][0] - subpixel_mid_y;
169 const int sx = candidates[i][1] - subpixel_mid_x;
170 // dy/dx: the row/column coordinates of the sample point in the reference
171 // block, with center of the reference block as origin.
172 const int dy = candidates[i][2] - reference_subpixel_mid_y;
173 const int dx = candidates[i][3] - reference_subpixel_mid_x;
174 if (std::abs(sx - dx) < kLargestMotionVectorDiff &&
175 std::abs(sy - dy) < kLargestMotionVectorDiff) {
176 a[0][0] += LeastSquareProduct(sx, sx) + 8;
177 a[0][1] += LeastSquareProduct(sx, sy) + 4;
178 a[1][1] += LeastSquareProduct(sy, sy) + 8;
179 bx[0] += LeastSquareProduct(sx, dx) + 8;
180 bx[1] += LeastSquareProduct(sy, dx) + 4;
181 by[0] += LeastSquareProduct(sx, dy) + 4;
182 by[1] += LeastSquareProduct(sy, dy) + 8;
183 }
184 }
185
186 // a[0][1] == a[1][0], because the matrix is symmetric. We don't have to
187 // compute a[1][0].
188 const int64_t determinant = a[0][0] * a[1][1] - a[0][1] * a[0][1];
189 if (determinant == 0) return false;
190
191 int16_t division_shift;
192 int16_t division_factor;
193 GenerateApproximateDivisor<int64_t>(determinant, &division_factor,
194 &division_shift);
195
196 division_shift -= kWarpedModelPrecisionBits;
197
198 const int64_t params_2 = a[1][1] * bx[0] - a[0][1] * bx[1];
199 const int64_t params_3 = -a[0][1] * bx[0] + a[0][0] * bx[1];
200 const int64_t params_4 = a[1][1] * by[0] - a[0][1] * by[1];
201 const int64_t params_5 = -a[0][1] * by[0] + a[0][0] * by[1];
202 auto* const params = warp_params->params;
203
204 if (division_shift <= 0) {
205 division_factor <<= -division_shift;
206 params[2] = static_cast<int32_t>(params_2) * division_factor;
207 params[3] = static_cast<int32_t>(params_3) * division_factor;
208 params[4] = static_cast<int32_t>(params_4) * division_factor;
209 params[5] = static_cast<int32_t>(params_5) * division_factor;
210 } else {
211 params[2] = RightShiftWithRoundingSigned(params_2 * division_factor,
212 division_shift);
213 params[3] = RightShiftWithRoundingSigned(params_3 * division_factor,
214 division_shift);
215 params[4] = RightShiftWithRoundingSigned(params_4 * division_factor,
216 division_shift);
217 params[5] = RightShiftWithRoundingSigned(params_5 * division_factor,
218 division_shift);
219 }
220
221 params[2] = DiagonalClamp(params[2]);
222 params[3] = NonDiagonalClamp(params[3]);
223 params[4] = NonDiagonalClamp(params[4]);
224 params[5] = DiagonalClamp(params[5]);
225
226 const int vx =
227 mv.mv[MotionVector::kColumn] * (1 << (kWarpedModelPrecisionBits - 3)) -
228 (mid_x * (params[2] - (1 << kWarpedModelPrecisionBits)) +
229 mid_y * params[3]);
230 const int vy =
231 mv.mv[MotionVector::kRow] * (1 << (kWarpedModelPrecisionBits - 3)) -
232 (mid_x * params[4] +
233 mid_y * (params[5] - (1 << kWarpedModelPrecisionBits)));
234 params[0] =
235 Clip3(vx, -kWarpModelTranslationClamp, kWarpModelTranslationClamp - 1);
236 params[1] =
237 Clip3(vy, -kWarpModelTranslationClamp, kWarpModelTranslationClamp - 1);
238
239 params[6] = 0;
240 params[7] = 0;
241 return true;
242 }
243
244 } // namespace libgav1
245