/src/avm/av2/common/warped_motion.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2021, Alliance for Open Media. All rights reserved |
3 | | * |
4 | | * This source code is subject to the terms of the BSD 3-Clause Clear License |
5 | | * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear |
6 | | * License was not distributed with this source code in the LICENSE file, you |
7 | | * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. If the |
8 | | * Alliance for Open Media Patent License 1.0 was not distributed with this |
9 | | * source code in the PATENTS file, you can obtain it at |
10 | | * aomedia.org/license/patent-license/. |
11 | | */ |
12 | | |
13 | | #include <stdio.h> |
14 | | #include <stdlib.h> |
15 | | #include <memory.h> |
16 | | #include <math.h> |
17 | | #include <assert.h> |
18 | | #include <stdbool.h> |
19 | | |
20 | | #include "config/av2_rtcd.h" |
21 | | |
22 | | #include "av2/common/warped_motion.h" |
23 | | #include "av2/common/scale.h" |
24 | | #include "av2/common/mvref_common.h" |
25 | | |
26 | | // For warping, we use 8/6/4/2-tap filters, but we do blocks of 8 pixels |
27 | | // at a time. The zoom/rotation/shear in the model are applied to the |
28 | | // "fractional" position of each pixel, which therefore varies within |
29 | | // [-3, 4) * WARPEDPIXEL_PREC_SHIFTS. |
30 | | // We need an extra 2-6 taps to fit this in, for a total of 8 taps. |
31 | | /* clang-format off */ |
32 | | const int16_t av2_warped_filter[WARPEDPIXEL_PREC_SHIFTS * 7 + 1][8] = { |
33 | | #if WARPEDPIXEL_PREC_BITS == 6 |
34 | | // [-3, -2) |
35 | | { 127, 1, 0, 0, 0, 0, 0, 0 }, { 126, 2, 0, 0, 0, 0, 0, 0 }, |
36 | | { 124, 4, 0, 0, 0, 0, 0, 0 }, { 122, 6, 0, 0, 0, 0, 0, 0 }, |
37 | | { 120, 8, 0, 0, 0, 0, 0, 0 }, { 118, 10, 0, 0, 0, 0, 0, 0 }, |
38 | | { 116, 12, 0, 0, 0, 0, 0, 0 }, { 114, 14, 0, 0, 0, 0, 0, 0 }, |
39 | | { 112, 16, 0, 0, 0, 0, 0, 0 }, { 110, 18, 0, 0, 0, 0, 0, 0 }, |
40 | | { 108, 20, 0, 0, 0, 0, 0, 0 }, { 106, 22, 0, 0, 0, 0, 0, 0 }, |
41 | | { 104, 24, 0, 0, 0, 0, 0, 0 }, { 102, 26, 0, 0, 0, 0, 0, 0 }, |
42 | | { 100, 28, 0, 0, 0, 0, 0, 0 }, { 98, 30, 0, 0, 0, 0, 0, 0 }, |
43 | | { 96, 32, 0, 0, 0, 0, 0, 0 }, { 94, 34, 0, 0, 0, 0, 0, 0 }, |
44 | | { 92, 36, 0, 0, 0, 0, 0, 0 }, { 90, 38, 0, 0, 0, 0, 0, 0 }, |
45 | | { 88, 40, 0, 0, 0, 0, 0, 0 }, { 86, 42, 0, 0, 0, 0, 0, 0 }, |
46 | | { 84, 44, 0, 0, 0, 0, 0, 0 }, { 82, 46, 0, 0, 0, 0, 0, 0 }, |
47 | | { 80, 48, 0, 0, 0, 0, 0, 0 }, { 78, 50, 0, 0, 0, 0, 0, 0 }, |
48 | | { 76, 52, 0, 0, 0, 0, 0, 0 }, { 74, 54, 0, 0, 0, 0, 0, 0 }, |
49 | | { 72, 56, 0, 0, 0, 0, 0, 0 }, { 70, 58, 0, 0, 0, 0, 0, 0 }, |
50 | | { 68, 60, 0, 0, 0, 0, 0, 0 }, { 66, 62, 0, 0, 0, 0, 0, 0 }, |
51 | | { 64, 64, 0, 0, 0, 0, 0, 0 }, { 62, 66, 0, 0, 0, 0, 0, 0 }, |
52 | | { 60, 68, 0, 0, 0, 0, 0, 0 }, { 58, 70, 0, 0, 0, 0, 0, 0 }, |
53 | | { 56, 72, 0, 0, 0, 0, 0, 0 }, { 54, 74, 0, 0, 0, 0, 0, 0 }, |
54 | | { 52, 76, 0, 0, 0, 0, 0, 0 }, { 50, 78, 0, 0, 0, 0, 0, 0 }, |
55 | | { 48, 80, 0, 0, 0, 0, 0, 0 }, { 46, 82, 0, 0, 0, 0, 0, 0 }, |
56 | | { 44, 84, 0, 0, 0, 0, 0, 0 }, { 42, 86, 0, 0, 0, 0, 0, 0 }, |
57 | | { 40, 88, 0, 0, 0, 0, 0, 0 }, { 38, 90, 0, 0, 0, 0, 0, 0 }, |
58 | | { 36, 92, 0, 0, 0, 0, 0, 0 }, { 34, 94, 0, 0, 0, 0, 0, 0 }, |
59 | | { 32, 96, 0, 0, 0, 0, 0, 0 }, { 30, 98, 0, 0, 0, 0, 0, 0 }, |
60 | | { 28, 100, 0, 0, 0, 0, 0, 0 }, { 26, 102, 0, 0, 0, 0, 0, 0 }, |
61 | | { 24, 104, 0, 0, 0, 0, 0, 0 }, { 22, 106, 0, 0, 0, 0, 0, 0 }, |
62 | | { 20, 108, 0, 0, 0, 0, 0, 0 }, { 18, 110, 0, 0, 0, 0, 0, 0 }, |
63 | | { 16, 112, 0, 0, 0, 0, 0, 0 }, { 14, 114, 0, 0, 0, 0, 0, 0 }, |
64 | | { 12, 116, 0, 0, 0, 0, 0, 0 }, { 10, 118, 0, 0, 0, 0, 0, 0 }, |
65 | | { 8, 120, 0, 0, 0, 0, 0, 0 }, { 6, 122, 0, 0, 0, 0, 0, 0 }, |
66 | | { 4, 124, 0, 0, 0, 0, 0, 0 }, { 2, 126, 0, 0, 0, 0, 0, 0 }, |
67 | | |
68 | | // [-2, -1) |
69 | | { 0, 127, 1, 0, 0, 0, 0, 0 }, { - 1, 127, 2, 0, 0, 0, 0, 0 }, |
70 | | { - 2, 127, 4, -1, 0, 0, 0, 0 }, { - 3, 126, 6, - 1, 0, 0, 0, 0 }, |
71 | | { - 3, 125, 8, -2, 0, 0, 0, 0 }, { - 4, 124, 11, - 3, 0, 0, 0, 0 }, |
72 | | { - 5, 123, 13, -3, 0, 0, 0, 0 }, { - 5, 121, 15, - 3, 0, 0, 0, 0 }, |
73 | | { - 6, 120, 18, -4, 0, 0, 0, 0 }, { - 7, 119, 20, - 4, 0, 0, 0, 0 }, |
74 | | { - 7, 118, 22, -5, 0, 0, 0, 0 }, { - 8, 116, 25, - 5, 0, 0, 0, 0 }, |
75 | | { - 8, 115, 27, -6, 0, 0, 0, 0 }, { - 9, 113, 30, - 6, 0, 0, 0, 0 }, |
76 | | { - 9, 112, 32, -7, 0, 0, 0, 0 }, { - 9, 110, 34, - 7, 0, 0, 0, 0 }, |
77 | | { -10, 108, 37, -7, 0, 0, 0, 0 }, { -10, 107, 39, - 8, 0, 0, 0, 0 }, |
78 | | { -10, 105, 41, -8, 0, 0, 0, 0 }, { -11, 103, 44, - 8, 0, 0, 0, 0 }, |
79 | | { -11, 101, 47, -9, 0, 0, 0, 0 }, { -11, 99, 49, - 9, 0, 0, 0, 0 }, |
80 | | { -11, 97, 51, -9, 0, 0, 0, 0 }, { -11, 95, 54, -10, 0, 0, 0, 0 }, |
81 | | { -11, 93, 56, -10, 0, 0, 0, 0 }, { -12, 91, 59, -10, 0, 0, 0, 0 }, |
82 | | { -12, 89, 61, -10, 0, 0, 0, 0 }, { -12, 87, 64, -11, 0, 0, 0, 0 }, |
83 | | { -12, 85, 66, -11, 0, 0, 0, 0 }, { -12, 82, 69, -11, 0, 0, 0, 0 }, |
84 | | { -12, 80, 71, -11, 0, 0, 0, 0 }, { -12, 78, 73, -11, 0, 0, 0, 0 }, |
85 | | { -11, 75, 75, -11, 0, 0, 0, 0 }, { -11, 73, 78, -12, 0, 0, 0, 0 }, |
86 | | { -11, 71, 80, -12, 0, 0, 0, 0 }, { -11, 69, 82, -12, 0, 0, 0, 0 }, |
87 | | { -11, 66, 85, -12, 0, 0, 0, 0 }, { -11, 64, 87, -12, 0, 0, 0, 0 }, |
88 | | { -10, 61, 89, -12, 0, 0, 0, 0 }, { -10, 59, 91, -12, 0, 0, 0, 0 }, |
89 | | { -10, 56, 93, -11, 0, 0, 0, 0 }, { -10, 54, 95, -11, 0, 0, 0, 0 }, |
90 | | { - 9, 51, 97, -11, 0, 0, 0, 0 }, { - 9, 49, 99, -11, 0, 0, 0, 0 }, |
91 | | { - 9, 47, 101, -11, 0, 0, 0, 0 }, { - 8, 44, 103, -11, 0, 0, 0, 0 }, |
92 | | { - 8, 41, 105, -10, 0, 0, 0, 0 }, { - 8, 39, 107, -10, 0, 0, 0, 0 }, |
93 | | { - 7, 37, 108, -10, 0, 0, 0, 0 }, { - 7, 34, 110, - 9, 0, 0, 0, 0 }, |
94 | | { - 7, 32, 112, - 9, 0, 0, 0, 0 }, { - 6, 30, 113, - 9, 0, 0, 0, 0 }, |
95 | | { - 6, 27, 115, - 8, 0, 0, 0, 0 }, { - 5, 25, 116, - 8, 0, 0, 0, 0 }, |
96 | | { - 5, 22, 118, - 7, 0, 0, 0, 0 }, { - 4, 20, 119, - 7, 0, 0, 0, 0 }, |
97 | | { - 4, 18, 120, - 6, 0, 0, 0, 0 }, { - 3, 15, 121, - 5, 0, 0, 0, 0 }, |
98 | | { - 3, 13, 123, - 5, 0, 0, 0, 0 }, { - 3, 11, 124, - 4, 0, 0, 0, 0 }, |
99 | | { - 2, 8, 125, - 3, 0, 0, 0, 0 }, { - 1, 6, 126, - 3, 0, 0, 0, 0 }, |
100 | | { - 1, 4, 127, - 2, 0, 0, 0, 0 }, { 0, 2, 127, - 1, 0, 0, 0, 0 }, |
101 | | // [-1, 0) |
102 | | { 0, 0, 127, 1, 0, 0, 0, 0 }, { 0, - 1, 127, 2, 0, 0, 0, 0 }, |
103 | | { 1, - 3, 127, 4, - 1, 0, 0, 0 }, { 1, - 4, 126, 6, - 2, 1, 0, 0 }, |
104 | | { 1, - 5, 126, 8, - 3, 1, 0, 0 }, { 1, - 6, 125, 11, - 4, 1, 0, 0 }, |
105 | | { 1, - 7, 124, 13, - 4, 1, 0, 0 }, { 2, - 8, 123, 15, - 5, 1, 0, 0 }, |
106 | | { 2, - 9, 122, 18, - 6, 1, 0, 0 }, { 2, -10, 121, 20, - 6, 1, 0, 0 }, |
107 | | { 2, -11, 120, 22, - 7, 2, 0, 0 }, { 2, -12, 119, 25, - 8, 2, 0, 0 }, |
108 | | { 3, -13, 117, 27, - 8, 2, 0, 0 }, { 3, -13, 116, 29, - 9, 2, 0, 0 }, |
109 | | { 3, -14, 114, 32, -10, 3, 0, 0 }, { 3, -15, 113, 35, -10, 2, 0, 0 }, |
110 | | { 3, -15, 111, 37, -11, 3, 0, 0 }, { 3, -16, 109, 40, -11, 3, 0, 0 }, |
111 | | { 3, -16, 108, 42, -12, 3, 0, 0 }, { 4, -17, 106, 45, -13, 3, 0, 0 }, |
112 | | { 4, -17, 104, 47, -13, 3, 0, 0 }, { 4, -17, 102, 50, -14, 3, 0, 0 }, |
113 | | { 4, -17, 100, 52, -14, 3, 0, 0 }, { 4, -18, 98, 55, -15, 4, 0, 0 }, |
114 | | { 4, -18, 96, 58, -15, 3, 0, 0 }, { 4, -18, 94, 60, -16, 4, 0, 0 }, |
115 | | { 4, -18, 91, 63, -16, 4, 0, 0 }, { 4, -18, 89, 65, -16, 4, 0, 0 }, |
116 | | { 4, -18, 87, 68, -17, 4, 0, 0 }, { 4, -18, 85, 70, -17, 4, 0, 0 }, |
117 | | { 4, -18, 82, 73, -17, 4, 0, 0 }, { 4, -18, 80, 75, -17, 4, 0, 0 }, |
118 | | { 4, -18, 78, 78, -18, 4, 0, 0 }, { 4, -17, 75, 80, -18, 4, 0, 0 }, |
119 | | { 4, -17, 73, 82, -18, 4, 0, 0 }, { 4, -17, 70, 85, -18, 4, 0, 0 }, |
120 | | { 4, -17, 68, 87, -18, 4, 0, 0 }, { 4, -16, 65, 89, -18, 4, 0, 0 }, |
121 | | { 4, -16, 63, 91, -18, 4, 0, 0 }, { 4, -16, 60, 94, -18, 4, 0, 0 }, |
122 | | { 3, -15, 58, 96, -18, 4, 0, 0 }, { 4, -15, 55, 98, -18, 4, 0, 0 }, |
123 | | { 3, -14, 52, 100, -17, 4, 0, 0 }, { 3, -14, 50, 102, -17, 4, 0, 0 }, |
124 | | { 3, -13, 47, 104, -17, 4, 0, 0 }, { 3, -13, 45, 106, -17, 4, 0, 0 }, |
125 | | { 3, -12, 42, 108, -16, 3, 0, 0 }, { 3, -11, 40, 109, -16, 3, 0, 0 }, |
126 | | { 3, -11, 37, 111, -15, 3, 0, 0 }, { 2, -10, 35, 113, -15, 3, 0, 0 }, |
127 | | { 3, -10, 32, 114, -14, 3, 0, 0 }, { 2, - 9, 29, 116, -13, 3, 0, 0 }, |
128 | | { 2, - 8, 27, 117, -13, 3, 0, 0 }, { 2, - 8, 25, 119, -12, 2, 0, 0 }, |
129 | | { 2, - 7, 22, 120, -11, 2, 0, 0 }, { 1, - 6, 20, 121, -10, 2, 0, 0 }, |
130 | | { 1, - 6, 18, 122, - 9, 2, 0, 0 }, { 1, - 5, 15, 123, - 8, 2, 0, 0 }, |
131 | | { 1, - 4, 13, 124, - 7, 1, 0, 0 }, { 1, - 4, 11, 125, - 6, 1, 0, 0 }, |
132 | | { 1, - 3, 8, 126, - 5, 1, 0, 0 }, { 1, - 2, 6, 126, - 4, 1, 0, 0 }, |
133 | | { 0, - 1, 4, 127, - 3, 1, 0, 0 }, { 0, 0, 2, 127, - 1, 0, 0, 0 }, |
134 | | |
135 | | // [0, 1) |
136 | | { 0, 0, 0, 127, 1, 0, 0, 0}, { 0, 0, -1, 127, 2, 0, 0, 0}, |
137 | | { 0, 1, -3, 127, 4, -2, 1, 0}, { 0, 1, -5, 127, 6, -2, 1, 0}, |
138 | | { 0, 2, -6, 126, 8, -3, 1, 0}, {-1, 2, -7, 126, 11, -4, 2, -1}, |
139 | | {-1, 3, -8, 125, 13, -5, 2, -1}, {-1, 3, -10, 124, 16, -6, 3, -1}, |
140 | | {-1, 4, -11, 123, 18, -7, 3, -1}, {-1, 4, -12, 122, 20, -7, 3, -1}, |
141 | | {-1, 4, -13, 121, 23, -8, 3, -1}, {-2, 5, -14, 120, 25, -9, 4, -1}, |
142 | | {-1, 5, -15, 119, 27, -10, 4, -1}, {-1, 5, -16, 118, 30, -11, 4, -1}, |
143 | | {-2, 6, -17, 116, 33, -12, 5, -1}, {-2, 6, -17, 114, 35, -12, 5, -1}, |
144 | | {-2, 6, -18, 113, 38, -13, 5, -1}, {-2, 7, -19, 111, 41, -14, 6, -2}, |
145 | | {-2, 7, -19, 110, 43, -15, 6, -2}, {-2, 7, -20, 108, 46, -15, 6, -2}, |
146 | | {-2, 7, -20, 106, 49, -16, 6, -2}, {-2, 7, -21, 104, 51, -16, 7, -2}, |
147 | | {-2, 7, -21, 102, 54, -17, 7, -2}, {-2, 8, -21, 100, 56, -18, 7, -2}, |
148 | | {-2, 8, -22, 98, 59, -18, 7, -2}, {-2, 8, -22, 96, 62, -19, 7, -2}, |
149 | | {-2, 8, -22, 94, 64, -19, 7, -2}, {-2, 8, -22, 91, 67, -20, 8, -2}, |
150 | | {-2, 8, -22, 89, 69, -20, 8, -2}, {-2, 8, -22, 87, 72, -21, 8, -2}, |
151 | | {-2, 8, -21, 84, 74, -21, 8, -2}, {-2, 8, -22, 82, 77, -21, 8, -2}, |
152 | | {-2, 8, -21, 79, 79, -21, 8, -2}, {-2, 8, -21, 77, 82, -22, 8, -2}, |
153 | | {-2, 8, -21, 74, 84, -21, 8, -2}, {-2, 8, -21, 72, 87, -22, 8, -2}, |
154 | | {-2, 8, -20, 69, 89, -22, 8, -2}, {-2, 8, -20, 67, 91, -22, 8, -2}, |
155 | | {-2, 7, -19, 64, 94, -22, 8, -2}, {-2, 7, -19, 62, 96, -22, 8, -2}, |
156 | | {-2, 7, -18, 59, 98, -22, 8, -2}, {-2, 7, -18, 56, 100, -21, 8, -2}, |
157 | | {-2, 7, -17, 54, 102, -21, 7, -2}, {-2, 7, -16, 51, 104, -21, 7, -2}, |
158 | | {-2, 6, -16, 49, 106, -20, 7, -2}, {-2, 6, -15, 46, 108, -20, 7, -2}, |
159 | | {-2, 6, -15, 43, 110, -19, 7, -2}, {-2, 6, -14, 41, 111, -19, 7, -2}, |
160 | | {-1, 5, -13, 38, 113, -18, 6, -2}, {-1, 5, -12, 35, 114, -17, 6, -2}, |
161 | | {-1, 5, -12, 33, 116, -17, 6, -2}, {-1, 4, -11, 30, 118, -16, 5, -1}, |
162 | | {-1, 4, -10, 27, 119, -15, 5, -1}, {-1, 4, -9, 25, 120, -14, 5, -2}, |
163 | | {-1, 3, -8, 23, 121, -13, 4, -1}, {-1, 3, -7, 20, 122, -12, 4, -1}, |
164 | | {-1, 3, -7, 18, 123, -11, 4, -1}, {-1, 3, -6, 16, 124, -10, 3, -1}, |
165 | | {-1, 2, -5, 13, 125, -8, 3, -1}, {-1, 2, -4, 11, 126, -7, 2, -1}, |
166 | | { 0, 1, -3, 8, 126, -6, 2, 0}, { 0, 1, -2, 6, 127, -5, 1, 0}, |
167 | | { 0, 1, -2, 4, 127, -3, 1, 0}, { 0, 0, 0, 2, 127, -1, 0, 0}, |
168 | | |
169 | | // [1, 2) |
170 | | { 0, 0, 0, 1, 127, 0, 0, 0 }, { 0, 0, 0, - 1, 127, 2, 0, 0 }, |
171 | | { 0, 0, 1, - 3, 127, 4, - 1, 0 }, { 0, 0, 1, - 4, 126, 6, - 2, 1 }, |
172 | | { 0, 0, 1, - 5, 126, 8, - 3, 1 }, { 0, 0, 1, - 6, 125, 11, - 4, 1 }, |
173 | | { 0, 0, 1, - 7, 124, 13, - 4, 1 }, { 0, 0, 2, - 8, 123, 15, - 5, 1 }, |
174 | | { 0, 0, 2, - 9, 122, 18, - 6, 1 }, { 0, 0, 2, -10, 121, 20, - 6, 1 }, |
175 | | { 0, 0, 2, -11, 120, 22, - 7, 2 }, { 0, 0, 2, -12, 119, 25, - 8, 2 }, |
176 | | { 0, 0, 3, -13, 117, 27, - 8, 2 }, { 0, 0, 3, -13, 116, 29, - 9, 2 }, |
177 | | { 0, 0, 3, -14, 114, 32, -10, 3 }, { 0, 0, 3, -15, 113, 35, -10, 2 }, |
178 | | { 0, 0, 3, -15, 111, 37, -11, 3 }, { 0, 0, 3, -16, 109, 40, -11, 3 }, |
179 | | { 0, 0, 3, -16, 108, 42, -12, 3 }, { 0, 0, 4, -17, 106, 45, -13, 3 }, |
180 | | { 0, 0, 4, -17, 104, 47, -13, 3 }, { 0, 0, 4, -17, 102, 50, -14, 3 }, |
181 | | { 0, 0, 4, -17, 100, 52, -14, 3 }, { 0, 0, 4, -18, 98, 55, -15, 4 }, |
182 | | { 0, 0, 4, -18, 96, 58, -15, 3 }, { 0, 0, 4, -18, 94, 60, -16, 4 }, |
183 | | { 0, 0, 4, -18, 91, 63, -16, 4 }, { 0, 0, 4, -18, 89, 65, -16, 4 }, |
184 | | { 0, 0, 4, -18, 87, 68, -17, 4 }, { 0, 0, 4, -18, 85, 70, -17, 4 }, |
185 | | { 0, 0, 4, -18, 82, 73, -17, 4 }, { 0, 0, 4, -18, 80, 75, -17, 4 }, |
186 | | { 0, 0, 4, -18, 78, 78, -18, 4 }, { 0, 0, 4, -17, 75, 80, -18, 4 }, |
187 | | { 0, 0, 4, -17, 73, 82, -18, 4 }, { 0, 0, 4, -17, 70, 85, -18, 4 }, |
188 | | { 0, 0, 4, -17, 68, 87, -18, 4 }, { 0, 0, 4, -16, 65, 89, -18, 4 }, |
189 | | { 0, 0, 4, -16, 63, 91, -18, 4 }, { 0, 0, 4, -16, 60, 94, -18, 4 }, |
190 | | { 0, 0, 3, -15, 58, 96, -18, 4 }, { 0, 0, 4, -15, 55, 98, -18, 4 }, |
191 | | { 0, 0, 3, -14, 52, 100, -17, 4 }, { 0, 0, 3, -14, 50, 102, -17, 4 }, |
192 | | { 0, 0, 3, -13, 47, 104, -17, 4 }, { 0, 0, 3, -13, 45, 106, -17, 4 }, |
193 | | { 0, 0, 3, -12, 42, 108, -16, 3 }, { 0, 0, 3, -11, 40, 109, -16, 3 }, |
194 | | { 0, 0, 3, -11, 37, 111, -15, 3 }, { 0, 0, 2, -10, 35, 113, -15, 3 }, |
195 | | { 0, 0, 3, -10, 32, 114, -14, 3 }, { 0, 0, 2, - 9, 29, 116, -13, 3 }, |
196 | | { 0, 0, 2, - 8, 27, 117, -13, 3 }, { 0, 0, 2, - 8, 25, 119, -12, 2 }, |
197 | | { 0, 0, 2, - 7, 22, 120, -11, 2 }, { 0, 0, 1, - 6, 20, 121, -10, 2 }, |
198 | | { 0, 0, 1, - 6, 18, 122, - 9, 2 }, { 0, 0, 1, - 5, 15, 123, - 8, 2 }, |
199 | | { 0, 0, 1, - 4, 13, 124, - 7, 1 }, { 0, 0, 1, - 4, 11, 125, - 6, 1 }, |
200 | | { 0, 0, 1, - 3, 8, 126, - 5, 1 }, { 0, 0, 1, - 2, 6, 126, - 4, 1 }, |
201 | | { 0, 0, 0, - 1, 4, 127, - 3, 1 }, { 0, 0, 0, 0, 2, 127, - 1, 0 }, |
202 | | |
203 | | // [2, 3) |
204 | | { 0, 0, 0, 0, 0, 127, 1, 0 }, { 0, 0, 0, 0, - 1, 127, 2, 0 }, |
205 | | { 0, 0, 0, 0, - 2, 127, 4, - 1 }, { 0, 0, 0, 0, - 3, 126, 6, - 1 }, |
206 | | { 0, 0, 0, 0, - 3, 125, 8, - 2 }, { 0, 0, 0, 0, - 4, 124, 11, - 3 }, |
207 | | { 0, 0, 0, 0, - 5, 123, 13, - 3 }, { 0, 0, 0, 0, - 5, 121, 15, - 3 }, |
208 | | { 0, 0, 0, 0, - 6, 120, 18, - 4 }, { 0, 0, 0, 0, - 7, 119, 20, - 4 }, |
209 | | { 0, 0, 0, 0, - 7, 118, 22, - 5 }, { 0, 0, 0, 0, - 8, 116, 25, - 5 }, |
210 | | { 0, 0, 0, 0, - 8, 115, 27, - 6 }, { 0, 0, 0, 0, - 9, 113, 30, - 6 }, |
211 | | { 0, 0, 0, 0, - 9, 112, 32, - 7 }, { 0, 0, 0, 0, - 9, 110, 34, - 7 }, |
212 | | { 0, 0, 0, 0, -10, 108, 37, - 7 }, { 0, 0, 0, 0, -10, 107, 39, - 8 }, |
213 | | { 0, 0, 0, 0, -10, 105, 41, - 8 }, { 0, 0, 0, 0, -11, 103, 44, - 8 }, |
214 | | { 0, 0, 0, 0, -11, 101, 47, - 9 }, { 0, 0, 0, 0, -11, 99, 49, - 9 }, |
215 | | { 0, 0, 0, 0, -11, 97, 51, - 9 }, { 0, 0, 0, 0, -11, 95, 54, -10 }, |
216 | | { 0, 0, 0, 0, -11, 93, 56, -10 }, { 0, 0, 0, 0, -12, 91, 59, -10 }, |
217 | | { 0, 0, 0, 0, -12, 89, 61, -10 }, { 0, 0, 0, 0, -12, 87, 64, -11 }, |
218 | | { 0, 0, 0, 0, -12, 85, 66, -11 }, { 0, 0, 0, 0, -12, 82, 69, -11 }, |
219 | | { 0, 0, 0, 0, -12, 80, 71, -11 }, { 0, 0, 0, 0, -12, 78, 73, -11 }, |
220 | | { 0, 0, 0, 0, -11, 75, 75, -11 }, { 0, 0, 0, 0, -11, 73, 78, -12 }, |
221 | | { 0, 0, 0, 0, -11, 71, 80, -12 }, { 0, 0, 0, 0, -11, 69, 82, -12 }, |
222 | | { 0, 0, 0, 0, -11, 66, 85, -12 }, { 0, 0, 0, 0, -11, 64, 87, -12 }, |
223 | | { 0, 0, 0, 0, -10, 61, 89, -12 }, { 0, 0, 0, 0, -10, 59, 91, -12 }, |
224 | | { 0, 0, 0, 0, -10, 56, 93, -11 }, { 0, 0, 0, 0, -10, 54, 95, -11 }, |
225 | | { 0, 0, 0, 0, - 9, 51, 97, -11 }, { 0, 0, 0, 0, - 9, 49, 99, -11 }, |
226 | | { 0, 0, 0, 0, - 9, 47, 101, -11 }, { 0, 0, 0, 0, - 8, 44, 103, -11 }, |
227 | | { 0, 0, 0, 0, - 8, 41, 105, -10 }, { 0, 0, 0, 0, - 8, 39, 107, -10 }, |
228 | | { 0, 0, 0, 0, - 7, 37, 108, -10 }, { 0, 0, 0, 0, - 7, 34, 110, - 9 }, |
229 | | { 0, 0, 0, 0, - 7, 32, 112, - 9 }, { 0, 0, 0, 0, - 6, 30, 113, - 9 }, |
230 | | { 0, 0, 0, 0, - 6, 27, 115, - 8 }, { 0, 0, 0, 0, - 5, 25, 116, - 8 }, |
231 | | { 0, 0, 0, 0, - 5, 22, 118, - 7 }, { 0, 0, 0, 0, - 4, 20, 119, - 7 }, |
232 | | { 0, 0, 0, 0, - 4, 18, 120, - 6 }, { 0, 0, 0, 0, - 3, 15, 121, - 5 }, |
233 | | { 0, 0, 0, 0, - 3, 13, 123, - 5 }, { 0, 0, 0, 0, - 3, 11, 124, - 4 }, |
234 | | { 0, 0, 0, 0, - 2, 8, 125, - 3 }, { 0, 0, 0, 0, - 1, 6, 126, - 3 }, |
235 | | { 0, 0, 0, 0, - 1, 4, 127, - 2 }, { 0, 0, 0, 0, 0, 2, 127, - 1 }, |
236 | | |
237 | | // [3, 4) |
238 | | {0, 0, 0, 0, 0, 0, 127, 1 }, {0, 0, 0, 0, 0, 0, 126, 2 }, |
239 | | {0, 0, 0, 0, 0, 0, 124, 4 }, {0, 0, 0, 0, 0, 0, 122, 6 }, |
240 | | {0, 0, 0, 0, 0, 0, 120, 8 }, {0, 0, 0, 0, 0, 0, 118, 10 }, |
241 | | {0, 0, 0, 0, 0, 0, 116, 12 }, {0, 0, 0, 0, 0, 0, 114, 14 }, |
242 | | {0, 0, 0, 0, 0, 0, 112, 16 }, {0, 0, 0, 0, 0, 0, 110, 18 }, |
243 | | {0, 0, 0, 0, 0, 0, 108, 20 }, {0, 0, 0, 0, 0, 0, 106, 22 }, |
244 | | {0, 0, 0, 0, 0, 0, 104, 24 }, {0, 0, 0, 0, 0, 0, 102, 26 }, |
245 | | {0, 0, 0, 0, 0, 0, 100, 28 }, {0, 0, 0, 0, 0, 0, 98, 30 }, |
246 | | {0, 0, 0, 0, 0, 0, 96, 32 }, {0, 0, 0, 0, 0, 0, 94, 34 }, |
247 | | {0, 0, 0, 0, 0, 0, 92, 36 }, {0, 0, 0, 0, 0, 0, 90, 38 }, |
248 | | {0, 0, 0, 0, 0, 0, 88, 40 }, {0, 0, 0, 0, 0, 0, 86, 42 }, |
249 | | {0, 0, 0, 0, 0, 0, 84, 44 }, {0, 0, 0, 0, 0, 0, 82, 46 }, |
250 | | {0, 0, 0, 0, 0, 0, 80, 48 }, {0, 0, 0, 0, 0, 0, 78, 50 }, |
251 | | {0, 0, 0, 0, 0, 0, 76, 52 }, {0, 0, 0, 0, 0, 0, 74, 54 }, |
252 | | {0, 0, 0, 0, 0, 0, 72, 56 }, {0, 0, 0, 0, 0, 0, 70, 58 }, |
253 | | {0, 0, 0, 0, 0, 0, 68, 60 }, {0, 0, 0, 0, 0, 0, 66, 62 }, |
254 | | {0, 0, 0, 0, 0, 0, 64, 64 }, {0, 0, 0, 0, 0, 0, 62, 66 }, |
255 | | {0, 0, 0, 0, 0, 0, 60, 68 }, {0, 0, 0, 0, 0, 0, 58, 70 }, |
256 | | {0, 0, 0, 0, 0, 0, 56, 72 }, {0, 0, 0, 0, 0, 0, 54, 74 }, |
257 | | {0, 0, 0, 0, 0, 0, 52, 76 }, {0, 0, 0, 0, 0, 0, 50, 78 }, |
258 | | {0, 0, 0, 0, 0, 0, 48, 80 }, {0, 0, 0, 0, 0, 0, 46, 82 }, |
259 | | {0, 0, 0, 0, 0, 0, 44, 84 }, {0, 0, 0, 0, 0, 0, 42, 86 }, |
260 | | {0, 0, 0, 0, 0, 0, 40, 88 }, {0, 0, 0, 0, 0, 0, 38, 90 }, |
261 | | {0, 0, 0, 0, 0, 0, 36, 92 }, {0, 0, 0, 0, 0, 0, 34, 94 }, |
262 | | {0, 0, 0, 0, 0, 0, 32, 96 }, {0, 0, 0, 0, 0, 0, 30, 98 }, |
263 | | {0, 0, 0, 0, 0, 0, 28, 100 }, {0, 0, 0, 0, 0, 0, 26, 102 }, |
264 | | {0, 0, 0, 0, 0, 0, 24, 104 }, {0, 0, 0, 0, 0, 0, 22, 106 }, |
265 | | {0, 0, 0, 0, 0, 0, 20, 108 }, {0, 0, 0, 0, 0, 0, 18, 110 }, |
266 | | {0, 0, 0, 0, 0, 0, 16, 112 }, {0, 0, 0, 0, 0, 0, 14, 114 }, |
267 | | {0, 0, 0, 0, 0, 0, 12, 116 }, {0, 0, 0, 0, 0, 0, 10, 118 }, |
268 | | {0, 0, 0, 0, 0, 0, 8, 120 }, {0, 0, 0, 0, 0, 0, 6, 122 }, |
269 | | {0, 0, 0, 0, 0, 0, 4, 124 }, {0, 0, 0, 0, 0, 0, 2, 126 }, |
270 | | |
271 | | // dummy (replicate row index 447) |
272 | | { 0, 0, 0, 0, 0, 0, 2, 126 }, |
273 | | #elif WARPEDPIXEL_PREC_BITS == 5 |
274 | | // The filters added below are taken from WARPEDPIXEL_PREC_BITS=6 case by |
275 | | // skipping alternate filters and the codec is not validated for this case. |
276 | | // [-3, -2) |
277 | | { 127, 1, 0, 0, 0, 0, 0, 0 }, { 124, 4, 0, 0, 0, 0, 0, 0 }, |
278 | | { 120, 8, 0, 0, 0, 0, 0, 0 }, { 116, 12, 0, 0, 0, 0, 0, 0 }, |
279 | | { 112, 16, 0, 0, 0, 0, 0, 0 }, { 108, 20, 0, 0, 0, 0, 0, 0 }, |
280 | | { 104, 24, 0, 0, 0, 0, 0, 0 }, { 100, 28, 0, 0, 0, 0, 0, 0 }, |
281 | | { 96, 32, 0, 0, 0, 0, 0, 0 }, { 92, 36, 0, 0, 0, 0, 0, 0 }, |
282 | | { 88, 40, 0, 0, 0, 0, 0, 0 }, { 84, 44, 0, 0, 0, 0, 0, 0 }, |
283 | | { 80, 48, 0, 0, 0, 0, 0, 0 }, { 76, 52, 0, 0, 0, 0, 0, 0 }, |
284 | | { 72, 56, 0, 0, 0, 0, 0, 0 }, { 68, 60, 0, 0, 0, 0, 0, 0 }, |
285 | | { 64, 64, 0, 0, 0, 0, 0, 0 }, { 60, 68, 0, 0, 0, 0, 0, 0 }, |
286 | | { 56, 72, 0, 0, 0, 0, 0, 0 }, { 52, 76, 0, 0, 0, 0, 0, 0 }, |
287 | | { 48, 80, 0, 0, 0, 0, 0, 0 }, { 44, 84, 0, 0, 0, 0, 0, 0 }, |
288 | | { 40, 88, 0, 0, 0, 0, 0, 0 }, { 36, 92, 0, 0, 0, 0, 0, 0 }, |
289 | | { 32, 96, 0, 0, 0, 0, 0, 0 }, { 28, 100, 0, 0, 0, 0, 0, 0 }, |
290 | | { 24, 104, 0, 0, 0, 0, 0, 0 }, { 20, 108, 0, 0, 0, 0, 0, 0 }, |
291 | | { 16, 112, 0, 0, 0, 0, 0, 0 }, { 12, 116, 0, 0, 0, 0, 0, 0 }, |
292 | | { 8, 120, 0, 0, 0, 0, 0, 0 }, { 4, 124, 0, 0, 0, 0, 0, 0 }, |
293 | | // [-2, -1) |
294 | | { 0, 127, 1, 0, 0, 0, 0, 0 }, { - 2, 127, 4, -1, 0, 0, 0, 0 }, |
295 | | { - 3, 125, 8, -2, 0, 0, 0, 0 }, { - 5, 123, 13, -3, 0, 0, 0, 0 }, |
296 | | { - 6, 120, 18, -4, 0, 0, 0, 0 }, { - 7, 118, 22, -5, 0, 0, 0, 0 }, |
297 | | { - 8, 115, 27, -6, 0, 0, 0, 0 }, { - 9, 112, 32, -7, 0, 0, 0, 0 }, |
298 | | { -10, 108, 37, -7, 0, 0, 0, 0 }, { -10, 105, 41, -8, 0, 0, 0, 0 }, |
299 | | { -11, 101, 47, -9, 0, 0, 0, 0 }, { -11, 97, 51, -9, 0, 0, 0, 0 }, |
300 | | { -11, 93, 56, -10, 0, 0, 0, 0 }, { -12, 89, 61, -10, 0, 0, 0, 0 }, |
301 | | { -12, 85, 66, -11, 0, 0, 0, 0 }, { -12, 80, 71, -11, 0, 0, 0, 0 }, |
302 | | { -11, 75, 75, -11, 0, 0, 0, 0 }, { -11, 71, 80, -12, 0, 0, 0, 0 }, |
303 | | { -11, 66, 85, -12, 0, 0, 0, 0 }, { -10, 61, 89, -12, 0, 0, 0, 0 }, |
304 | | { -10, 56, 93, -11, 0, 0, 0, 0 }, { - 9, 51, 97, -11, 0, 0, 0, 0 }, |
305 | | { - 9, 47, 101, -11, 0, 0, 0, 0 }, { - 8, 41, 105, -10, 0, 0, 0, 0 }, |
306 | | { - 7, 37, 108, -10, 0, 0, 0, 0 }, { - 7, 32, 112, - 9, 0, 0, 0, 0 }, |
307 | | { - 6, 27, 115, - 8, 0, 0, 0, 0 }, { - 5, 22, 118, - 7, 0, 0, 0, 0 }, |
308 | | { - 4, 18, 120, - 6, 0, 0, 0, 0 }, { - 3, 13, 123, - 5, 0, 0, 0, 0 }, |
309 | | { - 2, 8, 125, - 3, 0, 0, 0, 0 }, { - 1, 4, 127, - 2, 0, 0, 0, 0 }, |
310 | | // [-1, 0) |
311 | | {0, 0, 127, 1, 0, 0, 0, 0}, {1, -3, 127, 4, -1, 0, 0, 0}, |
312 | | {1, -5, 126, 8, -3, 1, 0, 0}, {1, -7, 124, 13, -4, 1, 0, 0}, |
313 | | {2, -9, 122, 18, -6, 1, 0, 0}, {2, -11, 120, 22, -7, 2, 0, 0}, |
314 | | {3, -13, 117, 27, -8, 2, 0, 0}, {3, -14, 114, 32, -10, 3, 0, 0}, |
315 | | {3, -15, 111, 37, -11, 3, 0, 0}, {3, -16, 108, 42, -12, 3, 0, 0}, |
316 | | {4, -17, 104, 47, -13, 3, 0, 0}, {4, -17, 100, 52, -14, 3, 0, 0}, |
317 | | {4, -18, 96, 58, -15, 3, 0, 0}, {4, -18, 91, 63, -16, 4, 0, 0}, |
318 | | {4, -18, 87, 68, -17, 4, 0, 0}, {4, -18, 82, 73, -17, 4, 0, 0}, |
319 | | {4, -18, 78, 78, -18, 4, 0, 0}, {4, -17, 73, 82, -18, 4, 0, 0}, |
320 | | {4, -17, 68, 87, -18, 4, 0, 0}, {4, -16, 63, 91, -18, 4, 0, 0}, |
321 | | {3, -15, 58, 96, -18, 4, 0, 0}, {3, -14, 52, 100, -17, 4, 0, 0}, |
322 | | {3, -13, 47, 104, -17, 4, 0, 0}, {3, -12, 42, 108, -16, 3, 0, 0}, |
323 | | {3, -11, 37, 111, -15, 3, 0, 0}, {3, -10, 32, 114, -14, 3, 0, 0}, |
324 | | {2, -8, 27, 117, -13, 3, 0, 0}, {2, -7, 22, 120, -11, 2, 0, 0}, |
325 | | {1, -6, 18, 122, -9, 2, 0, 0}, {1, -4, 13, 124, -7, 1, 0, 0}, |
326 | | {1, -3, 8, 126, -5, 1, 0, 0}, {0, -1, 4, 127, -3, 1, 0, 0}, |
327 | | // [0, 1) |
328 | | { 0, 0, 0, 127, 1, 0, 0, 0}, { 0, 1, -3, 127, 4, -2, 1, 0}, |
329 | | { 0, 2, -6, 126, 8, -3, 1, 0}, {-1, 3, -8, 125, 13, -5, 2, -1}, |
330 | | {-1, 4, -11, 123, 18, -7, 3, -1}, {-1, 4, -13, 121, 23, -8, 3, -1}, |
331 | | {-1, 5, -15, 119, 27, -10, 4, -1}, {-2, 6, -17, 116, 33, -12, 5, -1}, |
332 | | {-2, 6, -18, 113, 38, -13, 5, -1}, {-2, 7, -19, 110, 43, -15, 6, -2}, |
333 | | {-2, 7, -20, 106, 49, -16, 6, -2}, {-2, 7, -21, 102, 54, -17, 7, -2}, |
334 | | {-2, 8, -22, 98, 59, -18, 7, -2}, {-2, 8, -22, 94, 64, -19, 7, -2}, |
335 | | {-2, 8, -22, 89, 69, -20, 8, -2}, {-2, 8, -21, 84, 74, -21, 8, -2}, |
336 | | {-2, 8, -21, 79, 79, -21, 8, -2}, {-2, 8, -21, 74, 84, -21, 8, -2}, |
337 | | {-2, 8, -20, 69, 89, -22, 8, -2}, {-2, 7, -19, 64, 94, -22, 8, -2}, |
338 | | {-2, 7, -18, 59, 98, -22, 8, -2}, {-2, 7, -17, 54, 102, -21, 7, -2}, |
339 | | {-2, 6, -16, 49, 106, -20, 7, -2}, {-2, 6, -15, 43, 110, -19, 7, -2}, |
340 | | {-1, 5, -13, 38, 113, -18, 6, -2}, {-1, 5, -12, 33, 116, -17, 6, -2}, |
341 | | {-1, 4, -10, 27, 119, -15, 5, -1}, {-1, 3, -8, 23, 121, -13, 4, -1}, |
342 | | {-1, 3, -7, 18, 123, -11, 4, -1}, {-1, 2, -5, 13, 125, -8, 3, -1}, |
343 | | { 0, 1, -3, 8, 126, -6, 2, 0}, { 0, 1, -2, 4, 127, -3, 1, 0}, |
344 | | // [1, 2) |
345 | | {0, 0, 0, 1, 127, 0, 0, 0}, {0, 0, 1, -3, 127, 4, -1, 0}, |
346 | | {0, 0, 1, -5, 126, 8, -3, 1}, {0, 0, 1, -7, 124, 13, -4, 1}, |
347 | | {0, 0, 2, -9, 122, 18, -6, 1}, {0, 0, 2, -11, 120, 22, -7, 2}, |
348 | | {0, 0, 3, -13, 117, 27, -8, 2}, {0, 0, 3, -14, 114, 32, -10, 3}, |
349 | | {0, 0, 3, -15, 111, 37, -11, 3}, {0, 0, 3, -16, 108, 42, -12, 3}, |
350 | | {0, 0, 4, -17, 104, 47, -13, 3}, {0, 0, 4, -17, 100, 52, -14, 3}, |
351 | | {0, 0, 4, -18, 96, 58, -15, 3}, {0, 0, 4, -18, 91, 63, -16, 4}, |
352 | | {0, 0, 4, -18, 87, 68, -17, 4}, {0, 0, 4, -18, 82, 73, -17, 4}, |
353 | | {0, 0, 4, -18, 78, 78, -18, 4}, {0, 0, 4, -17, 73, 82, -18, 4}, |
354 | | {0, 0, 4, -17, 68, 87, -18, 4}, {0, 0, 4, -16, 63, 91, -18, 4}, |
355 | | {0, 0, 3, -15, 58, 96, -18, 4}, {0, 0, 3, -14, 52, 100, -17, 4}, |
356 | | {0, 0, 3, -13, 47, 104, -17, 4}, {0, 0, 3, -12, 42, 108, -16, 3}, |
357 | | {0, 0, 3, -11, 37, 111, -15, 3}, {0, 0, 3, -10, 32, 114, -14, 3}, |
358 | | {0, 0, 2, -8, 27, 117, -13, 3}, {0, 0, 2, -7, 22, 120, -11, 2}, |
359 | | {0, 0, 1, -6, 18, 122, -9, 2}, {0, 0, 1, -4, 13, 124, -7, 1}, |
360 | | {0, 0, 1, -3, 8, 126, -5, 1}, {0, 0, 0, -1, 4, 127, -3, 1}, |
361 | | // [2, 3) |
362 | | { 0, 0, 0, 0, 0, 127, 1, 0 }, { 0, 0, 0, 0, - 2, 127, 4, - 1 }, |
363 | | { 0, 0, 0, 0, - 3, 125, 8, - 2 }, { 0, 0, 0, 0, - 5, 123, 13, - 3 }, |
364 | | { 0, 0, 0, 0, - 6, 120, 18, - 4 }, { 0, 0, 0, 0, - 7, 118, 22, - 5 }, |
365 | | { 0, 0, 0, 0, - 8, 115, 27, - 6 }, { 0, 0, 0, 0, - 9, 112, 32, - 7 }, |
366 | | { 0, 0, 0, 0, -10, 108, 37, - 7 }, { 0, 0, 0, 0, -10, 105, 41, - 8 }, |
367 | | { 0, 0, 0, 0, -11, 101, 47, - 9 }, { 0, 0, 0, 0, -11, 97, 51, - 9 }, |
368 | | { 0, 0, 0, 0, -11, 93, 56, -10 }, { 0, 0, 0, 0, -12, 89, 61, -10 }, |
369 | | { 0, 0, 0, 0, -12, 85, 66, -11 }, { 0, 0, 0, 0, -12, 80, 71, -11 }, |
370 | | { 0, 0, 0, 0, -11, 75, 75, -11 }, { 0, 0, 0, 0, -11, 71, 80, -12 }, |
371 | | { 0, 0, 0, 0, -11, 66, 85, -12 }, { 0, 0, 0, 0, -10, 61, 89, -12 }, |
372 | | { 0, 0, 0, 0, -10, 56, 93, -11 }, { 0, 0, 0, 0, - 9, 51, 97, -11 }, |
373 | | { 0, 0, 0, 0, - 9, 47, 101, -11 }, { 0, 0, 0, 0, - 8, 41, 105, -10 }, |
374 | | { 0, 0, 0, 0, - 7, 37, 108, -10 }, { 0, 0, 0, 0, - 7, 32, 112, - 9 }, |
375 | | { 0, 0, 0, 0, - 6, 27, 115, - 8 }, { 0, 0, 0, 0, - 5, 22, 118, - 7 }, |
376 | | { 0, 0, 0, 0, - 4, 18, 120, - 6 }, { 0, 0, 0, 0, - 3, 13, 123, - 5 }, |
377 | | { 0, 0, 0, 0, - 2, 8, 125, - 3 }, { 0, 0, 0, 0, - 1, 4, 127, - 2 }, |
378 | | // [3, 4) |
379 | | {0, 0, 0, 0, 0, 0, 127, 1 }, {0, 0, 0, 0, 0, 0, 124, 4 }, |
380 | | {0, 0, 0, 0, 0, 0, 120, 8 }, {0, 0, 0, 0, 0, 0, 116, 12 }, |
381 | | {0, 0, 0, 0, 0, 0, 112, 16 }, {0, 0, 0, 0, 0, 0, 108, 20 }, |
382 | | {0, 0, 0, 0, 0, 0, 104, 24 }, {0, 0, 0, 0, 0, 0, 100, 28 }, |
383 | | {0, 0, 0, 0, 0, 0, 96, 32 }, {0, 0, 0, 0, 0, 0, 92, 36 }, |
384 | | {0, 0, 0, 0, 0, 0, 88, 40 }, {0, 0, 0, 0, 0, 0, 84, 44 }, |
385 | | {0, 0, 0, 0, 0, 0, 80, 48 }, {0, 0, 0, 0, 0, 0, 76, 52 }, |
386 | | {0, 0, 0, 0, 0, 0, 72, 56 }, {0, 0, 0, 0, 0, 0, 68, 60 }, |
387 | | {0, 0, 0, 0, 0, 0, 64, 64 }, {0, 0, 0, 0, 0, 0, 60, 68 }, |
388 | | {0, 0, 0, 0, 0, 0, 56, 72 }, {0, 0, 0, 0, 0, 0, 52, 76 }, |
389 | | {0, 0, 0, 0, 0, 0, 48, 80 }, {0, 0, 0, 0, 0, 0, 44, 84 }, |
390 | | {0, 0, 0, 0, 0, 0, 40, 88 }, {0, 0, 0, 0, 0, 0, 36, 92 }, |
391 | | {0, 0, 0, 0, 0, 0, 32, 96 }, {0, 0, 0, 0, 0, 0, 28, 100 }, |
392 | | {0, 0, 0, 0, 0, 0, 24, 104 }, {0, 0, 0, 0, 0, 0, 20, 108 }, |
393 | | {0, 0, 0, 0, 0, 0, 16, 112 }, {0, 0, 0, 0, 0, 0, 12, 116 }, |
394 | | {0, 0, 0, 0, 0, 0, 8, 120 }, {0, 0, 0, 0, 0, 0, 4, 124 }, |
395 | | // dummy (replicate row index 223) |
396 | | {0, 0, 0, 0, 0, 0, 4, 124 }, |
397 | | |
398 | | #endif // WARPEDPIXEL_PREC_BITS == 6 |
399 | | }; |
400 | | |
401 | | DECLARE_ALIGNED(16, const int16_t, |
402 | | av2_ext_warped_filter[EXT_WARP_PHASES + 1][EXT_WARP_STORAGE_TAPS]) = { |
403 | | // The extended warp filter is a 6-tap filter, but we store each kernel with |
404 | | // two extra zeros at the end so that each kernel is 16-byte aligned |
405 | | { 0, 0, 128, 0, 0, 0, 0, 0 }, |
406 | | { 0, -1, 127, 2, 0, 0, 0, 0 }, |
407 | | { 0, -2, 127, 4, -1, 0, 0, 0 }, |
408 | | { 0, -3, 126, 6, -1, 0, 0, 0 }, |
409 | | { 1, -4, 125, 8, -2, 0, 0, 0 }, |
410 | | { 1, -5, 124, 11, -3, 0, 0, 0 }, |
411 | | { 1, -6, 123, 13, -3, 0, 0, 0 }, |
412 | | { 1, -6, 122, 15, -4, 0, 0, 0 }, |
413 | | { 1, -7, 120, 17, -4, 1, 0, 0 }, |
414 | | { 1, -8, 119, 20, -5, 1, 0, 0 }, |
415 | | { 1, -9, 118, 22, -5, 1, 0, 0 }, |
416 | | { 1, -9, 117, 24, -6, 1, 0, 0 }, |
417 | | { 1, -10, 115, 27, -6, 1, 0, 0 }, |
418 | | { 1, -10, 114, 29, -7, 1, 0, 0 }, |
419 | | { 1, -11, 112, 32, -7, 1, 0, 0 }, |
420 | | { 1, -11, 111, 34, -8, 1, 0, 0 }, |
421 | | { 1, -11, 109, 36, -8, 1, 0, 0 }, |
422 | | { 2, -12, 107, 39, -9, 1, 0, 0 }, |
423 | | { 2, -12, 105, 41, -9, 1, 0, 0 }, |
424 | | { 2, -12, 103, 44, -10, 1, 0, 0 }, |
425 | | { 2, -13, 102, 46, -10, 1, 0, 0 }, |
426 | | { 2, -13, 99, 49, -10, 1, 0, 0 }, |
427 | | { 2, -13, 98, 51, -11, 1, 0, 0 }, |
428 | | { 2, -13, 95, 54, -11, 1, 0, 0 }, |
429 | | { 2, -14, 93, 56, -11, 2, 0, 0 }, |
430 | | { 2, -14, 91, 59, -12, 2, 0, 0 }, |
431 | | { 2, -14, 89, 61, -12, 2, 0, 0 }, |
432 | | { 2, -14, 87, 63, -12, 2, 0, 0 }, |
433 | | { 2, -14, 85, 66, -13, 2, 0, 0 }, |
434 | | { 2, -14, 83, 68, -13, 2, 0, 0 }, |
435 | | { 2, -14, 80, 71, -13, 2, 0, 0 }, |
436 | | { 2, -14, 78, 73, -13, 2, 0, 0 }, |
437 | | { 2, -13, 75, 75, -13, 2, 0, 0 }, |
438 | | { 2, -13, 73, 78, -14, 2, 0, 0 }, |
439 | | { 2, -13, 71, 80, -14, 2, 0, 0 }, |
440 | | { 2, -13, 68, 83, -14, 2, 0, 0 }, |
441 | | { 2, -13, 66, 85, -14, 2, 0, 0 }, |
442 | | { 2, -12, 63, 87, -14, 2, 0, 0 }, |
443 | | { 2, -12, 61, 89, -14, 2, 0, 0 }, |
444 | | { 2, -12, 59, 91, -14, 2, 0, 0 }, |
445 | | { 2, -11, 56, 93, -14, 2, 0, 0 }, |
446 | | { 1, -11, 54, 95, -13, 2, 0, 0 }, |
447 | | { 1, -11, 51, 98, -13, 2, 0, 0 }, |
448 | | { 1, -10, 49, 99, -13, 2, 0, 0 }, |
449 | | { 1, -10, 46, 102, -13, 2, 0, 0 }, |
450 | | { 1, -10, 44, 103, -12, 2, 0, 0 }, |
451 | | { 1, -9, 41, 105, -12, 2, 0, 0 }, |
452 | | { 1, -9, 39, 107, -12, 2, 0, 0 }, |
453 | | { 1, -8, 36, 109, -11, 1, 0, 0 }, |
454 | | { 1, -8, 34, 111, -11, 1, 0, 0 }, |
455 | | { 1, -7, 32, 112, -11, 1, 0, 0 }, |
456 | | { 1, -7, 29, 114, -10, 1, 0, 0 }, |
457 | | { 1, -6, 27, 115, -10, 1, 0, 0 }, |
458 | | { 1, -6, 24, 117, -9, 1, 0, 0 }, |
459 | | { 1, -5, 22, 118, -9, 1, 0, 0 }, |
460 | | { 1, -5, 20, 119, -8, 1, 0, 0 }, |
461 | | { 1, -4, 17, 120, -7, 1, 0, 0 }, |
462 | | { 0, -4, 15, 122, -6, 1, 0, 0 }, |
463 | | { 0, -3, 13, 123, -6, 1, 0, 0 }, |
464 | | { 0, -3, 11, 124, -5, 1, 0, 0 }, |
465 | | { 0, -2, 8, 125, -4, 1, 0, 0 }, |
466 | | { 0, -1, 6, 126, -3, 0, 0, 0 }, |
467 | | { 0, -1, 4, 127, -2, 0, 0, 0 }, |
468 | | { 0, 0, 2, 127, -1, 0, 0, 0 }, |
469 | | { 0, 0, 0, 128, 0, 0, 0, 0 }, |
470 | | }; |
471 | | /* clang-format on */ |
472 | | |
473 | | // Recompute the translational part of a warp model, so that the center |
474 | | // of the current block (determined by `mi_row`, `mi_col`, `bsize`) |
475 | | // has an induced motion vector of `mv` |
476 | | void av2_set_warp_translation(int mi_row, int mi_col, BLOCK_SIZE bsize, MV mv, |
477 | 0 | WarpedMotionParams *wm) { |
478 | 0 | const int center_x = mi_col * MI_SIZE + block_size_wide[bsize] / 2 - 1; |
479 | 0 | const int center_y = mi_row * MI_SIZE + block_size_high[bsize] / 2 - 1; |
480 | | |
481 | | // Note(rachelbarker): We subtract 1 from the diagonal part of the model here. |
482 | | // This is because the warp model M maps (current frame) pixel coordinates to |
483 | | // (ref frame) pixel coordinates. So, in order to calculate the induced |
484 | | // motion vector, we have to subtract the identity matrix. |
485 | 0 | int64_t wmmat0 = |
486 | 0 | (int64_t)mv.col * (1 << (WARPEDMODEL_PREC_BITS - 3)) - |
487 | 0 | ((int64_t)center_x * (wm->wmmat[2] - (1 << WARPEDMODEL_PREC_BITS)) + |
488 | 0 | (int64_t)center_y * wm->wmmat[3]); |
489 | 0 | int64_t wmmat1 = |
490 | 0 | (int64_t)mv.row * (1 << (WARPEDMODEL_PREC_BITS - 3)) - |
491 | 0 | ((int64_t)center_x * wm->wmmat[4] + |
492 | 0 | (int64_t)center_y * (wm->wmmat[5] - (1 << WARPEDMODEL_PREC_BITS))); |
493 | |
|
494 | 0 | wm->wmmat[0] = |
495 | 0 | (int32_t)clamp64(wmmat0, -WARPEDMODEL_TRANS_CLAMP, |
496 | 0 | WARPEDMODEL_TRANS_CLAMP - (1 << WARP_PARAM_REDUCE_BITS)); |
497 | 0 | wm->wmmat[1] = |
498 | 0 | (int32_t)clamp64(wmmat1, -WARPEDMODEL_TRANS_CLAMP, |
499 | 0 | WARPEDMODEL_TRANS_CLAMP - (1 << WARP_PARAM_REDUCE_BITS)); |
500 | 0 | wm->wmtype = get_wmtype(wm); |
501 | 0 | } |
502 | | |
503 | | static int is_affine_shear_allowed(int16_t alpha, int16_t beta, int16_t gamma, |
504 | 0 | int16_t delta) { |
505 | 0 | if ((4 * abs(alpha) + 7 * abs(beta) >= (3 << WARPEDMODEL_PREC_BITS)) || |
506 | 0 | (4 * abs(gamma) + 4 * abs(delta) >= (3 << WARPEDMODEL_PREC_BITS))) |
507 | 0 | return 0; |
508 | 0 | else |
509 | 0 | return 1; |
510 | 0 | } |
511 | | |
512 | | void av2_get_shear_params(WarpedMotionParams *wm, |
513 | 0 | const struct scale_factors *sf) { |
514 | 0 | const int16_t max_value = INT16_MAX - (1 << (WARP_PARAM_REDUCE_BITS - 1)); |
515 | | |
516 | | // Always use 4x4 warp in scale of across-scale |
517 | 0 | const int is_scaled = sf ? av2_is_scaled(sf) : 0; |
518 | 0 | const int32_t *mat = wm->wmmat; |
519 | |
|
520 | 0 | wm->alpha = |
521 | 0 | clamp(mat[2] - (1 << WARPEDMODEL_PREC_BITS), INT16_MIN, max_value); |
522 | 0 | wm->beta = clamp(mat[3], INT16_MIN, max_value); |
523 | 0 | int16_t shift; |
524 | 0 | int16_t y = resolve_divisor_32(abs(mat[2]), &shift) * (mat[2] < 0 ? -1 : 1); |
525 | 0 | int64_t v = ((int64_t)mat[4] * (1 << WARPEDMODEL_PREC_BITS)) * y; |
526 | 0 | wm->gamma = |
527 | 0 | clamp((int)ROUND_POWER_OF_TWO_SIGNED_64(v, shift), INT16_MIN, max_value); |
528 | 0 | v = ((int64_t)mat[3] * mat[4]) * y; |
529 | 0 | wm->delta = clamp(mat[5] - (int)ROUND_POWER_OF_TWO_SIGNED_64(v, shift) - |
530 | 0 | (1 << WARPEDMODEL_PREC_BITS), |
531 | 0 | INT16_MIN, max_value); |
532 | | |
533 | | // Note(rachelbarker): |
534 | | // In extreme cases, the `clamp` operations in the previous block can set |
535 | | // parameters equal to to INT16_MAX == 32767. |
536 | | // |
537 | | // The following round-then-multiply, which is intended to reduce the bit |
538 | | // storage requirement in hardware, then rounds to 32768, which is outside |
539 | | // the range of an int16_t. But casting to int16_t is okay - it will cause |
540 | | // this value to become -32768, and so the model will be rejected |
541 | | // by is_affine_shear_allowed(), so the outcome is the same. |
542 | | // |
543 | | // However, we must make this cast explicit, because otherwise the integer |
544 | | // sanitizer (correctly) complains about overflow during an implicit cast |
545 | 0 | wm->alpha = |
546 | 0 | (int16_t)(ROUND_POWER_OF_TWO_SIGNED(wm->alpha, WARP_PARAM_REDUCE_BITS) * |
547 | 0 | (1 << WARP_PARAM_REDUCE_BITS)); |
548 | 0 | wm->beta = |
549 | 0 | (int16_t)(ROUND_POWER_OF_TWO_SIGNED(wm->beta, WARP_PARAM_REDUCE_BITS) * |
550 | 0 | (1 << WARP_PARAM_REDUCE_BITS)); |
551 | 0 | wm->gamma = |
552 | 0 | (int16_t)(ROUND_POWER_OF_TWO_SIGNED(wm->gamma, WARP_PARAM_REDUCE_BITS) * |
553 | 0 | (1 << WARP_PARAM_REDUCE_BITS)); |
554 | 0 | wm->delta = |
555 | 0 | (int16_t)(ROUND_POWER_OF_TWO_SIGNED(wm->delta, WARP_PARAM_REDUCE_BITS) * |
556 | 0 | (1 << WARP_PARAM_REDUCE_BITS)); |
557 | |
|
558 | 0 | wm->use_affine_filter = |
559 | 0 | is_scaled |
560 | 0 | ? 0 |
561 | 0 | : is_affine_shear_allowed(wm->alpha, wm->beta, wm->gamma, wm->delta); |
562 | 0 | } |
563 | | |
564 | | // Reduce the precision of a warp model, ready for use in the warp filter |
565 | | // and for storage. This should be called after the non-translational parameters |
566 | | // are calculated, but before av2_set_warp_translation() or |
567 | | // av2_get_shear_params() are called |
568 | | // |
569 | | // This also clamps the values, ensuring that hardware can store each value |
570 | | // in a signed integer with (WARPEDMODEL_PREC_BITS - WARP_PARAM_REDUCE_BITS) |
571 | | // total bits |
572 | 0 | void av2_reduce_warp_model(WarpedMotionParams *wm) { |
573 | | // Constrain parameters so that they lie within the range of +/- 1/2 |
574 | | // relative to the identity model. |
575 | | // |
576 | | // In order to avoid needing one extra bit, we limit the maximum to one |
577 | | // unit less than 1/2, similarly to how an int<n> can only go up to |
578 | | // 2^(n-1) - 1. However, unlike an int<n>, the allowable range must |
579 | | // remain symmetric, so that ROTZOOM models can maintain the constraint |
580 | | // that wmmat[4] == -wmmat[3]. |
581 | 0 | const int max_value = |
582 | 0 | (1 << (WARPEDMODEL_PREC_BITS - 1)) - (1 << WARP_PARAM_REDUCE_BITS); |
583 | 0 | const int min_value = -max_value; |
584 | |
|
585 | 0 | for (int i = 2; i < 6; i++) { |
586 | 0 | int offset = (i == 2 || i == 5) ? (1 << WARPEDMODEL_PREC_BITS) : 0; |
587 | |
|
588 | 0 | int original = wm->wmmat[i] - offset; |
589 | 0 | int clamped = clamp(original, min_value, max_value); |
590 | 0 | int rounded = ROUND_POWER_OF_TWO_SIGNED(clamped, WARP_PARAM_REDUCE_BITS) * |
591 | 0 | (1 << WARP_PARAM_REDUCE_BITS); |
592 | |
|
593 | 0 | wm->wmmat[i] = rounded + offset; |
594 | 0 | } |
595 | 0 | } |
596 | | |
597 | | // Check if a model is already properly reduced, according to the same logic |
598 | | // used in av2_reduce_warp_model() |
599 | 0 | bool av2_is_warp_model_reduced(WarpedMotionParams *wm) { |
600 | | // Constrain parameters so that they lie within the range of +/- 1/2 |
601 | | // relative to the identity model. |
602 | | // |
603 | | // In order to avoid needing one extra bit, we limit the maximum to one |
604 | | // unit less than 1/2, similarly to how an int<n> can only go up to |
605 | | // 2^(n-1) - 1. However, unlike an int<n>, the allowable range must |
606 | | // remain symmetric, so that ROTZOOM models can maintain the constraint |
607 | | // that wmmat[4] == -wmmat[3]. |
608 | 0 | const int max_value = |
609 | 0 | (1 << (WARPEDMODEL_PREC_BITS - 1)) - (1 << WARP_PARAM_REDUCE_BITS); |
610 | 0 | const int min_value = -max_value; |
611 | |
|
612 | 0 | for (int i = 2; i < 6; i++) { |
613 | 0 | int offset = (i == 2 || i == 5) ? (1 << WARPEDMODEL_PREC_BITS) : 0; |
614 | |
|
615 | 0 | int original = wm->wmmat[i] - offset; |
616 | 0 | int rounded = ROUND_POWER_OF_TWO_SIGNED(original, WARP_PARAM_REDUCE_BITS) * |
617 | 0 | (1 << WARP_PARAM_REDUCE_BITS); |
618 | 0 | int clamped = clamp(rounded, min_value, max_value); |
619 | |
|
620 | 0 | if (clamped != original) return false; |
621 | 0 | } |
622 | | |
623 | 0 | return true; |
624 | 0 | } |
625 | | |
626 | | /* The warp filter for ROTZOOM and AFFINE models works as follows: |
627 | | * Split the input into 8x8 blocks |
628 | | * For each block, project the point (4, 4) within the block, to get the |
629 | | overall block position. Split into integer and fractional coordinates, |
630 | | maintaining full WARPEDMODEL precision |
631 | | * Filter horizontally: Generate 15 rows of 8 pixels each. Each pixel gets a |
632 | | variable horizontal offset. This means that, while the rows of the |
633 | | intermediate buffer align with the rows of the *reference* image, the |
634 | | columns align with the columns of the *destination* image. |
635 | | * Filter vertically: Generate the output block (up to 8x8 pixels, but if the |
636 | | destination is too small we crop the output at this stage). Each pixel has |
637 | | a variable vertical offset, so that the resulting rows are aligned with |
638 | | the rows of the destination image. |
639 | | |
640 | | To accomplish these alignments, we factor the warp matrix as a |
641 | | product of two shear / asymmetric zoom matrices: |
642 | | / a b \ = / 1 0 \ * / 1+alpha beta \ |
643 | | \ c d / \ gamma 1+delta / \ 0 1 / |
644 | | where a, b, c, d are wmmat[2], wmmat[3], wmmat[4], wmmat[5] respectively. |
645 | | The horizontal shear (with alpha and beta) is applied first, |
646 | | then the vertical shear (with gamma and delta) is applied second. |
647 | | |
648 | | The only limitation is that, to fit this in a fixed 8-tap filter size, |
649 | | the fractional pixel offsets must be at most +-1. Since the horizontal filter |
650 | | generates 15 rows of 8 columns, and the initial point we project is at (4, 4) |
651 | | within the block, the parameters must satisfy |
652 | | 4 * |alpha| + 7 * |beta| <= 1 and 4 * |gamma| + 4 * |delta| <= 1 |
653 | | for this filter to be applicable. |
654 | | |
655 | | Note: This function assumes that the caller has done all of the relevant |
656 | | checks, ie. that we have a ROTZOOM or AFFINE model, that wm[4] and wm[5] |
657 | | are set appropriately (if using a ROTZOOM model), and that alpha, beta, |
658 | | gamma, delta are all in range. |
659 | | |
660 | | TODO(rachelbarker): Maybe support scaled references? |
661 | | */ |
662 | | /* A note on hardware implementation: |
663 | | The warp filter is intended to be implementable using the same hardware as |
664 | | the high-precision convolve filters from the loop-restoration and |
665 | | convolve-round experiments. |
666 | | |
667 | | For a single filter stage, considering all of the coefficient sets for the |
668 | | warp filter and the regular convolution filter, an input in the range |
669 | | [0, 2^k - 1] is mapped into the range [-56 * (2^k - 1), 184 * (2^k - 1)] |
670 | | before rounding. |
671 | | |
672 | | Allowing for some changes to the filter coefficient sets, call the range |
673 | | [-64 * 2^k, 192 * 2^k]. Then, if we initialize the accumulator to 64 * 2^k, |
674 | | we can replace this by the range [0, 256 * 2^k], which can be stored in an |
675 | | unsigned value with 8 + k bits. |
676 | | |
677 | | This allows the derivation of the appropriate bit widths and offsets for |
678 | | the various intermediate values: If |
679 | | |
680 | | F := FILTER_BITS = 7 (or else the above ranges need adjusting) |
681 | | So a *single* filter stage maps a k-bit input to a (k + F + 1)-bit |
682 | | intermediate value. |
683 | | H := ROUND0_BITS |
684 | | V := VERSHEAR_REDUCE_PREC_BITS |
685 | | (and note that we must have H + V = 2*F for the output to have the same |
686 | | scale as the input) |
687 | | |
688 | | then we end up with the following offsets and ranges: |
689 | | Horizontal filter: Apply an offset of 1 << (bd + F - 1), sum fits into a |
690 | | uint{bd + F + 1} |
691 | | After rounding: The values stored in 'tmp' fit into a uint{bd + F + 1 - H}. |
692 | | Vertical filter: Apply an offset of 1 << (bd + 2*F - H), sum fits into a |
693 | | uint{bd + 2*F + 2 - H} |
694 | | After rounding: The final value, before undoing the offset, fits into a |
695 | | uint{bd + 2}. |
696 | | |
697 | | Then we need to undo the offsets before clamping to a pixel. Note that, |
698 | | if we do this at the end, the amount to subtract is actually independent |
699 | | of H and V: |
700 | | |
701 | | offset to subtract = (1 << ((bd + F - 1) - H + F - V)) + |
702 | | (1 << ((bd + 2*F - H) - V)) |
703 | | == (1 << (bd - 1)) + (1 << bd) |
704 | | |
705 | | This allows us to entirely avoid clamping in both the warp filter and |
706 | | the convolve-round experiment. As of the time of writing, the Wiener filter |
707 | | from loop-restoration can encode a central coefficient up to 216, which |
708 | | leads to a maximum value of about 282 * 2^k after applying the offset. |
709 | | So in that case we still need to clamp. |
710 | | */ |
711 | | |
712 | | void av2_highbd_warp_affine_c(const int32_t *mat, const uint16_t *ref, |
713 | | int width, int height, int stride, uint16_t *pred, |
714 | | int p_col, int p_row, int p_width, int p_height, |
715 | | int p_stride, int subsampling_x, |
716 | | int subsampling_y, int bd, |
717 | | ConvolveParams *conv_params, int16_t alpha, |
718 | 0 | int16_t beta, int16_t gamma, int16_t delta) { |
719 | 0 | const int left_limit = 0; |
720 | 0 | const int right_limit = width - 1; |
721 | 0 | const int top_limit = 0; |
722 | 0 | const int bottom_limit = height - 1; |
723 | 0 | int32_t tmp[15 * 8]; |
724 | 0 | const int reduce_bits_horiz = conv_params->round_0; |
725 | 0 | const int reduce_bits_vert = conv_params->is_compound |
726 | 0 | ? conv_params->round_1 |
727 | 0 | : 2 * FILTER_BITS - reduce_bits_horiz; |
728 | 0 | const int max_bits_horiz = bd + FILTER_BITS + 1 - reduce_bits_horiz; |
729 | 0 | const int offset_bits_horiz = bd + FILTER_BITS - 1; |
730 | 0 | const int offset_bits_vert = bd + 2 * FILTER_BITS - reduce_bits_horiz; |
731 | 0 | const int round_bits = |
732 | 0 | 2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1; |
733 | 0 | const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0; |
734 | 0 | const int use_wtd_comp_avg = is_uneven_wtd_comp_avg(conv_params); |
735 | 0 | (void)max_bits_horiz; |
736 | 0 | assert(IMPLIES(conv_params->is_compound, conv_params->dst != NULL)); |
737 | | |
738 | | // Check that, even with 12-bit input, the intermediate values will fit |
739 | | // into an unsigned 16-bit intermediate array. |
740 | 0 | assert(bd + FILTER_BITS + 2 - conv_params->round_0 <= 16); |
741 | 0 | const int taps = 8; |
742 | 0 | const int taps_half = taps >> 1; |
743 | |
|
744 | 0 | for (int i = p_row; i < p_row + p_height; i += 8) { |
745 | 0 | for (int j = p_col; j < p_col + p_width; j += 8) { |
746 | | // Calculate the center of this 8x8 block, |
747 | | // project to luma coordinates (if in a subsampled chroma plane), |
748 | | // apply the affine transformation, |
749 | | // then convert back to the original coordinates (if necessary) |
750 | 0 | const int32_t src_x = (j + 4) << subsampling_x; |
751 | 0 | const int32_t src_y = (i + 4) << subsampling_y; |
752 | 0 | const int64_t dst_x = |
753 | 0 | (int64_t)mat[2] * src_x + (int64_t)mat[3] * src_y + (int64_t)mat[0]; |
754 | 0 | const int64_t dst_y = |
755 | 0 | (int64_t)mat[4] * src_x + (int64_t)mat[5] * src_y + (int64_t)mat[1]; |
756 | 0 | const int64_t x4 = dst_x >> subsampling_x; |
757 | 0 | const int64_t y4 = dst_y >> subsampling_y; |
758 | |
|
759 | 0 | const int32_t ix4 = (int32_t)(x4 >> WARPEDMODEL_PREC_BITS); |
760 | 0 | int32_t sx4 = x4 & ((1 << WARPEDMODEL_PREC_BITS) - 1); |
761 | 0 | const int32_t iy4 = (int32_t)(y4 >> WARPEDMODEL_PREC_BITS); |
762 | 0 | int32_t sy4 = y4 & ((1 << WARPEDMODEL_PREC_BITS) - 1); |
763 | |
|
764 | 0 | sx4 += alpha * (-4) + beta * (-4); |
765 | 0 | sy4 += gamma * (-4) + delta * (-4); |
766 | |
|
767 | 0 | sx4 &= ~((1 << WARP_PARAM_REDUCE_BITS) - 1); |
768 | 0 | sy4 &= ~((1 << WARP_PARAM_REDUCE_BITS) - 1); |
769 | | |
770 | | // Horizontal filter |
771 | 0 | for (int k = -7; k < 8; ++k) { |
772 | 0 | const int iy = clamp(iy4 + k, top_limit, bottom_limit); |
773 | |
|
774 | 0 | int sx = sx4 + beta * (k + 4); |
775 | 0 | for (int l = -4; l < 4; ++l) { |
776 | 0 | int ix = ix4 + l - (taps_half - 1); |
777 | 0 | const int offs = ROUND_POWER_OF_TWO(sx, WARPEDDIFF_PREC_BITS) + |
778 | 0 | 3 * WARPEDPIXEL_PREC_SHIFTS; |
779 | 0 | assert(offs >= 0 && offs <= WARPEDPIXEL_PREC_SHIFTS * 7); |
780 | 0 | const int16_t *coeffs = av2_warped_filter[offs]; |
781 | 0 | int32_t sum = 1 << offset_bits_horiz; |
782 | 0 | for (int m = 0; m < taps; ++m) { |
783 | 0 | const int sample_x = clamp(ix + m, left_limit, right_limit); |
784 | 0 | sum += ref[iy * stride + sample_x] * coeffs[m]; |
785 | 0 | } |
786 | 0 | sum = ROUND_POWER_OF_TWO(sum, reduce_bits_horiz); |
787 | 0 | assert(0 <= sum && sum < (1 << max_bits_horiz)); |
788 | 0 | tmp[(k + 7) * 8 + (l + 4)] = sum; |
789 | 0 | sx += alpha; |
790 | 0 | } |
791 | 0 | } |
792 | | |
793 | | // Vertical filter |
794 | 0 | for (int k = -4; k < AVMMIN(4, p_row + p_height - i - 4); ++k) { |
795 | 0 | int sy = sy4 + delta * (k + 4); |
796 | 0 | for (int l = -4; l < AVMMIN(4, p_col + p_width - j - 4); ++l) { |
797 | 0 | const int offs = ROUND_POWER_OF_TWO(sy, WARPEDDIFF_PREC_BITS) + |
798 | 0 | 3 * WARPEDPIXEL_PREC_SHIFTS; |
799 | 0 | assert(offs >= 0 && offs <= WARPEDPIXEL_PREC_SHIFTS * 7); |
800 | 0 | const int16_t *coeffs = av2_warped_filter[offs]; |
801 | |
|
802 | 0 | int32_t sum = 1 << offset_bits_vert; |
803 | 0 | for (int m = 0; m < taps; ++m) { |
804 | 0 | sum += tmp[(k + m + 4) * 8 + (l + 4)] * coeffs[m]; |
805 | 0 | } |
806 | |
|
807 | 0 | if (conv_params->is_compound) { |
808 | 0 | CONV_BUF_TYPE *p = |
809 | 0 | &conv_params |
810 | 0 | ->dst[(i - p_row + k + 4) * conv_params->dst_stride + |
811 | 0 | (j - p_col + l + 4)]; |
812 | 0 | sum = ROUND_POWER_OF_TWO(sum, reduce_bits_vert); |
813 | 0 | if (conv_params->do_average) { |
814 | 0 | uint16_t *dst16 = |
815 | 0 | &pred[(i - p_row + k + 4) * p_stride + (j - p_col + l + 4)]; |
816 | 0 | int32_t tmp32 = *p; |
817 | 0 | if (use_wtd_comp_avg) { |
818 | 0 | tmp32 = tmp32 * conv_params->fwd_offset + |
819 | 0 | sum * conv_params->bck_offset; |
820 | 0 | tmp32 = tmp32 >> DIST_PRECISION_BITS; |
821 | 0 | } else { |
822 | 0 | tmp32 += sum; |
823 | 0 | tmp32 = tmp32 >> 1; |
824 | 0 | } |
825 | 0 | tmp32 = tmp32 - (1 << (offset_bits - conv_params->round_1)) - |
826 | 0 | (1 << (offset_bits - conv_params->round_1 - 1)); |
827 | 0 | *dst16 = |
828 | 0 | clip_pixel_highbd(ROUND_POWER_OF_TWO(tmp32, round_bits), bd); |
829 | 0 | } else { |
830 | 0 | *p = sum; |
831 | 0 | } |
832 | 0 | } else { |
833 | 0 | uint16_t *p = |
834 | 0 | &pred[(i - p_row + k + 4) * p_stride + (j - p_col + l + 4)]; |
835 | 0 | sum = ROUND_POWER_OF_TWO(sum, reduce_bits_vert); |
836 | 0 | assert(0 <= sum && sum < (1 << (bd + 2))); |
837 | 0 | *p = clip_pixel_highbd(sum - (1 << (bd - 1)) - (1 << bd), bd); |
838 | 0 | } |
839 | 0 | sy += gamma; |
840 | 0 | } |
841 | 0 | } |
842 | 0 | } |
843 | 0 | } |
844 | 0 | } |
845 | | |
846 | | /* Extended-range warp filter, used for strong warps where the regular |
847 | | affine filter (av2_highbd_warp_affine) is not usable. |
848 | | |
849 | | This filter operates by splitting the prediction unit into 4x4 pixel |
850 | | chunks. Then, for each chunk, the following process is applied: |
851 | | |
852 | | * Compute the effective motion vector at the center of the 4x4 chunk |
853 | | (actually at pixel offset (1, 1) into the chunk), at 1/64 pel precision |
854 | | |
855 | | * Translate the entire 4x4 pixel chunk by this compute motion vector |
856 | | |
857 | | This generates a prediction of intermediate quality - better than translating |
858 | | the prediction unit as a whole, but worse than a full affine shear. |
859 | | However, it is able to handle any encode-able warp model, and is not |
860 | | constrained in the same way as the regular warp filter. |
861 | | |
862 | | Note that this will produce blocking between adjacent 4x4 units, so we need |
863 | | apply some form of deblocking to the output of this function. This is handled |
864 | | separately. |
865 | | */ |
866 | | void av2_ext_highbd_warp_affine_c(const int32_t *mat, const uint16_t *ref, |
867 | | int width, int height, int stride, |
868 | | uint16_t *pred, int p_col, int p_row, |
869 | | int p_width, int p_height, int p_stride, |
870 | | int subsampling_x, int subsampling_y, int bd, |
871 | | ConvolveParams *conv_params, |
872 | 0 | int use_warp_bd_box, PadBlock *warp_bd_box) { |
873 | 0 | int32_t im_block[(4 + EXT_WARP_TAPS - 1) * 4]; |
874 | 0 | const int reduce_bits_horiz = conv_params->round_0; |
875 | 0 | const int reduce_bits_vert = conv_params->is_compound |
876 | 0 | ? conv_params->round_1 |
877 | 0 | : 2 * FILTER_BITS - reduce_bits_horiz; |
878 | 0 | const int max_bits_horiz = bd + FILTER_BITS + 1 - reduce_bits_horiz; |
879 | 0 | const int offset_bits_horiz = bd + FILTER_BITS - 1; |
880 | 0 | const int offset_bits_vert = bd + 2 * FILTER_BITS - reduce_bits_horiz; |
881 | 0 | const int round_bits = |
882 | 0 | 2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1; |
883 | 0 | const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0; |
884 | 0 | const int use_wtd_comp_avg = is_uneven_wtd_comp_avg(conv_params); |
885 | 0 | (void)max_bits_horiz; |
886 | 0 | assert(IMPLIES(conv_params->is_compound, conv_params->dst != NULL)); |
887 | | |
888 | | // Check that, even with 12-bit input, the intermediate values will fit |
889 | | // into an unsigned 16-bit intermediate array. |
890 | 0 | assert(bd + FILTER_BITS + 2 - conv_params->round_0 <= 16); |
891 | 0 | const int taps = EXT_WARP_TAPS; |
892 | 0 | const int taps_half = taps >> 1; |
893 | |
|
894 | 0 | int left_limit = 0; |
895 | 0 | int right_limit = width - 1; |
896 | 0 | int top_limit = 0; |
897 | 0 | int bottom_limit = height - 1; |
898 | 0 | int warp_bd_box_mem_stride = MAX_WARP_BD_SIZE; |
899 | 0 | int box_idx, x_loc, y_loc; |
900 | |
|
901 | 0 | for (int i = p_row; i < p_row + p_height; i += 4) { |
902 | 0 | for (int j = p_col; j < p_col + p_width; j += 4) { |
903 | 0 | if (use_warp_bd_box) { |
904 | 0 | x_loc = j - p_col; |
905 | 0 | y_loc = i - p_row; |
906 | 0 | box_idx = (x_loc >> 3) + (y_loc >> 3) * warp_bd_box_mem_stride; |
907 | 0 | left_limit = warp_bd_box[box_idx].x0; |
908 | 0 | right_limit = warp_bd_box[box_idx].x1 - 1; |
909 | 0 | top_limit = warp_bd_box[box_idx].y0; |
910 | 0 | bottom_limit = warp_bd_box[box_idx].y1 - 1; |
911 | 0 | } |
912 | | // Calculate the center of this 4x4 block, |
913 | | // project to luma coordinates (if in a subsampled chroma plane), |
914 | | // apply the affine transformation, |
915 | | // then convert back to the original coordinates (if necessary) |
916 | 0 | const int32_t src_x = (j + 2) << subsampling_x; |
917 | 0 | const int32_t src_y = (i + 2) << subsampling_y; |
918 | 0 | const int64_t dst_x = |
919 | 0 | (int64_t)mat[2] * src_x + (int64_t)mat[3] * src_y + (int64_t)mat[0]; |
920 | 0 | const int64_t dst_y = |
921 | 0 | (int64_t)mat[4] * src_x + (int64_t)mat[5] * src_y + (int64_t)mat[1]; |
922 | 0 | const int64_t x4 = dst_x >> subsampling_x; |
923 | 0 | const int64_t y4 = dst_y >> subsampling_y; |
924 | |
|
925 | 0 | const int32_t ix4 = (int32_t)(x4 >> WARPEDMODEL_PREC_BITS); |
926 | 0 | int32_t sx4 = x4 & ((1 << WARPEDMODEL_PREC_BITS) - 1); |
927 | 0 | const int32_t iy4 = (int32_t)(y4 >> WARPEDMODEL_PREC_BITS); |
928 | 0 | int32_t sy4 = y4 & ((1 << WARPEDMODEL_PREC_BITS) - 1); |
929 | | |
930 | | // Horizontal Filter |
931 | 0 | const int offs_x = ROUND_POWER_OF_TWO(sx4, EXT_WARP_ROUND_BITS); |
932 | 0 | assert(offs_x >= 0 && offs_x <= EXT_WARP_PHASES); |
933 | 0 | const int16_t *coeffs_x = av2_ext_warped_filter[offs_x]; |
934 | |
|
935 | 0 | for (int k = -(taps_half + 1); k < taps_half + 2; ++k) { |
936 | 0 | const int iy = clamp(iy4 + k, top_limit, bottom_limit); |
937 | |
|
938 | 0 | for (int l = -2; l < 2; ++l) { |
939 | 0 | int ix = ix4 + l - (taps_half - 1); |
940 | |
|
941 | 0 | int32_t sum = 1 << offset_bits_horiz; |
942 | 0 | for (int m = 0; m < taps; ++m) { |
943 | 0 | const int sample_x = clamp(ix + m, left_limit, right_limit); |
944 | 0 | sum += ref[iy * stride + sample_x] * coeffs_x[m]; |
945 | 0 | } |
946 | 0 | sum = ROUND_POWER_OF_TWO(sum, reduce_bits_horiz); |
947 | 0 | assert(0 <= sum && sum < (1 << max_bits_horiz)); |
948 | 0 | im_block[(k + (taps_half + 1)) * 4 + (l + 2)] = sum; |
949 | 0 | } |
950 | 0 | } |
951 | | |
952 | | // Vertical filter |
953 | 0 | const int offs_y = ROUND_POWER_OF_TWO(sy4, WARPEDDIFF_PREC_BITS); |
954 | 0 | assert(offs_y >= 0 && offs_y <= WARPEDPIXEL_PREC_SHIFTS); |
955 | 0 | const int16_t *coeffs_y = av2_ext_warped_filter[offs_y]; |
956 | |
|
957 | 0 | for (int k = -2; k < AVMMIN(2, p_row + p_height - i - 2); ++k) { |
958 | 0 | for (int l = -2; l < AVMMIN(2, p_col + p_width - j - 2); ++l) { |
959 | 0 | int32_t sum = 1 << offset_bits_vert; |
960 | 0 | for (int m = 0; m < taps; ++m) { |
961 | 0 | sum += im_block[(k + m + 2) * 4 + (l + 2)] * coeffs_y[m]; |
962 | 0 | } |
963 | |
|
964 | 0 | if (conv_params->is_compound) { |
965 | 0 | CONV_BUF_TYPE *p = |
966 | 0 | &conv_params |
967 | 0 | ->dst[(i - p_row + k + 2) * conv_params->dst_stride + |
968 | 0 | (j - p_col + l + 2)]; |
969 | 0 | sum = ROUND_POWER_OF_TWO(sum, reduce_bits_vert); |
970 | 0 | if (conv_params->do_average) { |
971 | 0 | uint16_t *dst16 = |
972 | 0 | &pred[(i - p_row + k + 2) * p_stride + (j - p_col + l + 2)]; |
973 | 0 | int32_t tmp32 = *p; |
974 | 0 | if (use_wtd_comp_avg) { |
975 | 0 | tmp32 = tmp32 * conv_params->fwd_offset + |
976 | 0 | sum * conv_params->bck_offset; |
977 | 0 | tmp32 = tmp32 >> DIST_PRECISION_BITS; |
978 | 0 | } else { |
979 | 0 | tmp32 += sum; |
980 | 0 | tmp32 = tmp32 >> 1; |
981 | 0 | } |
982 | 0 | tmp32 = tmp32 - (1 << (offset_bits - conv_params->round_1)) - |
983 | 0 | (1 << (offset_bits - conv_params->round_1 - 1)); |
984 | 0 | *dst16 = |
985 | 0 | clip_pixel_highbd(ROUND_POWER_OF_TWO(tmp32, round_bits), bd); |
986 | 0 | } else { |
987 | 0 | *p = sum; |
988 | 0 | } |
989 | 0 | } else { |
990 | 0 | uint16_t *p = |
991 | 0 | &pred[(i - p_row + k + 2) * p_stride + (j - p_col + l + 2)]; |
992 | 0 | sum = ROUND_POWER_OF_TWO(sum, reduce_bits_vert); |
993 | 0 | assert(0 <= sum && sum < (1 << (bd + 2))); |
994 | 0 | *p = clip_pixel_highbd(sum - (1 << (bd - 1)) - (1 << bd), bd); |
995 | 0 | } |
996 | 0 | } |
997 | 0 | } |
998 | 0 | } |
999 | 0 | } |
1000 | 0 | } |
1001 | | |
1002 | | void av2_ext_highbd_warp_affine_scaled_c( |
1003 | | const int32_t *mat, const uint16_t *ref, int width, int height, int stride, |
1004 | | uint16_t *pred, int p_col, int p_row, int p_width, int p_height, |
1005 | | int p_stride, int subsampling_x, int subsampling_y, int bd, |
1006 | | ConvolveParams *conv_params, const struct scale_factors *sf, |
1007 | 0 | int use_warp_bd_box, PadBlock *warp_bd_box) { |
1008 | | // int32_t im_block[(4 + EXT_WARP_TAPS - 1) * 4]; |
1009 | 0 | int32_t im_block[(2 * 4 + EXT_WARP_TAPS) * 4]; |
1010 | 0 | const int reduce_bits_horiz = conv_params->round_0; |
1011 | 0 | const int reduce_bits_vert = conv_params->is_compound |
1012 | 0 | ? conv_params->round_1 |
1013 | 0 | : 2 * FILTER_BITS - reduce_bits_horiz; |
1014 | 0 | const int max_bits_horiz = bd + FILTER_BITS + 1 - reduce_bits_horiz; |
1015 | 0 | const int offset_bits_horiz = bd + FILTER_BITS - 1; |
1016 | 0 | const int offset_bits_vert = bd + 2 * FILTER_BITS - reduce_bits_horiz; |
1017 | 0 | const int round_bits = |
1018 | 0 | 2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1; |
1019 | 0 | const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0; |
1020 | 0 | const int use_wtd_comp_avg = is_uneven_wtd_comp_avg(conv_params); |
1021 | 0 | (void)max_bits_horiz; |
1022 | 0 | assert(IMPLIES(conv_params->is_compound, conv_params->dst != NULL)); |
1023 | | |
1024 | | // Check that, even with 12-bit input, the intermediate values will fit |
1025 | | // into an unsigned 16-bit intermediate array. |
1026 | 0 | assert(bd + FILTER_BITS + 2 - conv_params->round_0 <= 16); |
1027 | 0 | const int taps = EXT_WARP_TAPS; |
1028 | 0 | const int taps_half = taps >> 1; |
1029 | 0 | const int fo_vert = taps_half - 1; |
1030 | 0 | const int fo_horiz = taps_half - 1; |
1031 | |
|
1032 | 0 | int left_limit = 0; |
1033 | 0 | int right_limit = width - 1; |
1034 | 0 | int top_limit = 0; |
1035 | 0 | int bottom_limit = height - 1; |
1036 | 0 | int warp_bd_box_mem_stride = MAX_WARP_BD_SIZE; |
1037 | 0 | int box_idx, x_loc, y_loc; |
1038 | 0 | assert(use_warp_bd_box); |
1039 | |
|
1040 | 0 | for (int i = p_row; i < p_row + p_height; i += 4) { |
1041 | 0 | for (int j = p_col; j < p_col + p_width; j += 4) { |
1042 | 0 | if (use_warp_bd_box) { |
1043 | 0 | x_loc = j - p_col; |
1044 | 0 | y_loc = i - p_row; |
1045 | 0 | box_idx = (x_loc >> 3) + (y_loc >> 3) * warp_bd_box_mem_stride; |
1046 | 0 | left_limit = warp_bd_box[box_idx].x0; |
1047 | 0 | right_limit = warp_bd_box[box_idx].x1 - 1; |
1048 | 0 | top_limit = warp_bd_box[box_idx].y0; |
1049 | 0 | bottom_limit = warp_bd_box[box_idx].y1 - 1; |
1050 | 0 | } |
1051 | | // Calculate the center of this 4x4 block, |
1052 | | // project to luma coordinates (if in a subsampled chroma plane), |
1053 | | // apply the affine transformation, |
1054 | | // then convert back to the original coordinates (if necessary) |
1055 | 0 | const int32_t src_x = (j + 2) << subsampling_x; |
1056 | 0 | const int32_t src_y = (i + 2) << subsampling_y; |
1057 | 0 | const int64_t dst_x = |
1058 | 0 | (int64_t)mat[2] * src_x + (int64_t)mat[3] * src_y + (int64_t)mat[0]; |
1059 | 0 | const int64_t dst_y = |
1060 | 0 | (int64_t)mat[4] * src_x + (int64_t)mat[5] * src_y + (int64_t)mat[1]; |
1061 | | |
1062 | | // Top left location in ref frame of a 4x4 block |
1063 | | // We need to do (- 2 * (1 << WARPEDMODEL_PREC_BITS)) becasue actual dst_x |
1064 | | // and dst_y is computed at the center of the 4x4 block |
1065 | 0 | const int64_t x4_org = |
1066 | 0 | (dst_x >> subsampling_x) - 2 * (1 << WARPEDMODEL_PREC_BITS); |
1067 | 0 | const int64_t y4_org = |
1068 | 0 | (dst_y >> subsampling_y) - 2 * (1 << WARPEDMODEL_PREC_BITS); |
1069 | |
|
1070 | 0 | const int64_t x4 = |
1071 | 0 | sf->scale_value_warp_x(x4_org, sf); // 16 bit sub-pel precision |
1072 | 0 | const int64_t y4 = |
1073 | 0 | sf->scale_value_warp_y(y4_org, sf); // 16 bit sub-pel precision |
1074 | |
|
1075 | 0 | const int32_t x_step_qn = sf->x_step_q4 |
1076 | 0 | << (WARPEDMODEL_PREC_BITS - SCALE_SUBPEL_BITS); |
1077 | 0 | const int32_t y_step_qn = sf->y_step_q4 |
1078 | 0 | << (WARPEDMODEL_PREC_BITS - SCALE_SUBPEL_BITS); |
1079 | |
|
1080 | 0 | const int32_t iy4 = (int32_t)(y4 >> WARPEDMODEL_PREC_BITS); |
1081 | 0 | int32_t subpel_y_qn = y4 & ((1 << WARPEDMODEL_PREC_BITS) - 1); |
1082 | | |
1083 | | // Horizontal Filter |
1084 | |
|
1085 | 0 | int im_h = |
1086 | 0 | (((4 - 1) * y_step_qn + subpel_y_qn) >> WARPEDMODEL_PREC_BITS) + taps; |
1087 | 0 | int im_stride = 4; |
1088 | 0 | int init_y = iy4 - fo_vert; |
1089 | |
|
1090 | 0 | for (int y = 0; y < im_h; ++y) { |
1091 | 0 | const int y_pos = init_y + y; |
1092 | 0 | const int iy = clamp(y_pos, top_limit, bottom_limit); |
1093 | 0 | int64_t x_qn = x4; |
1094 | 0 | for (int x = 0; x < 4; ++x, x_qn += x_step_qn) { |
1095 | | // Extract the filter parameters |
1096 | 0 | int32_t sx4 = x_qn & ((1 << WARPEDMODEL_PREC_BITS) - 1); |
1097 | 0 | const int offs_x = ROUND_POWER_OF_TWO(sx4, EXT_WARP_ROUND_BITS); |
1098 | 0 | assert(offs_x >= 0 && offs_x <= EXT_WARP_PHASES); |
1099 | 0 | const int16_t *coeffs_x = av2_ext_warped_filter[offs_x]; |
1100 | | |
1101 | | // position in the unit of integer pixel |
1102 | 0 | int ix = (int32_t)(x_qn >> WARPEDMODEL_PREC_BITS); // init_x + x; |
1103 | |
|
1104 | 0 | int32_t sum = 1 << offset_bits_horiz; |
1105 | 0 | for (int m = 0; m < taps; ++m) { |
1106 | 0 | const int sample_x = |
1107 | 0 | clamp(ix - fo_horiz + m, left_limit, right_limit); |
1108 | 0 | sum += ref[iy * stride + sample_x] * coeffs_x[m]; |
1109 | 0 | } |
1110 | 0 | sum = ROUND_POWER_OF_TWO(sum, reduce_bits_horiz); |
1111 | 0 | assert(0 <= sum && sum < (1 << max_bits_horiz)); |
1112 | 0 | im_block[y * im_stride + x] = sum; |
1113 | 0 | } |
1114 | 0 | } |
1115 | | |
1116 | | // Vertical filter |
1117 | 0 | int32_t *src_vert = im_block + fo_vert * im_stride; |
1118 | |
|
1119 | 0 | for (int x = 0; x < AVMMIN(4, p_col + p_width - j); ++x) { |
1120 | 0 | int64_t y_qn = subpel_y_qn; |
1121 | 0 | for (int y = 0; y < AVMMIN(4, p_row + p_height - i); |
1122 | 0 | ++y, y_qn += y_step_qn) { |
1123 | | // Extract the filter parameters |
1124 | 0 | int32_t sy4 = y_qn & ((1 << WARPEDMODEL_PREC_BITS) - 1); |
1125 | 0 | const int offs_y = ROUND_POWER_OF_TWO(sy4, EXT_WARP_ROUND_BITS); |
1126 | 0 | assert(offs_y >= 0 && offs_y <= EXT_WARP_PHASES); |
1127 | 0 | const int16_t *coeffs_y = av2_ext_warped_filter[offs_y]; |
1128 | |
|
1129 | 0 | const int32_t *src_vert_y = |
1130 | 0 | &src_vert[(y_qn >> WARPEDMODEL_PREC_BITS) * im_stride]; |
1131 | |
|
1132 | 0 | int32_t sum = 1 << offset_bits_vert; |
1133 | 0 | for (int m = 0; m < taps; ++m) { |
1134 | 0 | sum += src_vert_y[(m - fo_vert) * im_stride] * coeffs_y[m]; |
1135 | 0 | } |
1136 | |
|
1137 | 0 | if (conv_params->is_compound) { |
1138 | 0 | CONV_BUF_TYPE *p = |
1139 | 0 | &conv_params->dst[(i - p_row + y) * conv_params->dst_stride + |
1140 | 0 | (j - p_col + x)]; |
1141 | 0 | sum = ROUND_POWER_OF_TWO(sum, reduce_bits_vert); |
1142 | 0 | if (conv_params->do_average) { |
1143 | 0 | uint16_t *dst16 = |
1144 | 0 | &pred[(i - p_row + y) * p_stride + (j - p_col + x)]; |
1145 | 0 | int32_t tmp32 = *p; |
1146 | 0 | if (use_wtd_comp_avg) { |
1147 | 0 | tmp32 = tmp32 * conv_params->fwd_offset + |
1148 | 0 | sum * conv_params->bck_offset; |
1149 | 0 | tmp32 = tmp32 >> DIST_PRECISION_BITS; |
1150 | 0 | } else { |
1151 | 0 | tmp32 += sum; |
1152 | 0 | tmp32 = tmp32 >> 1; |
1153 | 0 | } |
1154 | 0 | tmp32 = tmp32 - (1 << (offset_bits - conv_params->round_1)) - |
1155 | 0 | (1 << (offset_bits - conv_params->round_1 - 1)); |
1156 | 0 | *dst16 = |
1157 | 0 | clip_pixel_highbd(ROUND_POWER_OF_TWO(tmp32, round_bits), bd); |
1158 | 0 | } else { |
1159 | 0 | *p = sum; |
1160 | 0 | } |
1161 | 0 | } else { |
1162 | 0 | uint16_t *p = &pred[(i - p_row + y) * p_stride + (j - p_col + x)]; |
1163 | 0 | sum = ROUND_POWER_OF_TWO(sum, reduce_bits_vert); |
1164 | 0 | assert(0 <= sum && sum < (1 << (bd + 2))); |
1165 | 0 | *p = clip_pixel_highbd(sum - (1 << (bd - 1)) - (1 << bd), bd); |
1166 | 0 | } |
1167 | 0 | } |
1168 | 0 | src_vert++; |
1169 | 0 | } |
1170 | 0 | } |
1171 | 0 | } |
1172 | 0 | } |
1173 | | |
1174 | | void av2_highbd_warp_plane(WarpedMotionParams *wm, const uint16_t *const ref, |
1175 | | int width, int height, int stride, |
1176 | | uint16_t *const pred, int p_col, int p_row, |
1177 | | int p_width, int p_height, int p_stride, |
1178 | | int subsampling_x, int subsampling_y, int bd, |
1179 | | ConvolveParams *conv_params, |
1180 | | const struct scale_factors *sf, int use_warp_bd_box, |
1181 | 0 | PadBlock *warp_bd_box) { |
1182 | 0 | const int is_scaled = sf ? av2_is_scaled(sf) : 0; |
1183 | 0 | assert(wm->wmtype <= AFFINE); |
1184 | 0 | if (wm->wmtype == ROTZOOM) { |
1185 | 0 | wm->wmmat[5] = wm->wmmat[2]; |
1186 | 0 | wm->wmmat[4] = -wm->wmmat[3]; |
1187 | 0 | } |
1188 | 0 | const int32_t *const mat = wm->wmmat; |
1189 | 0 | const int16_t alpha = wm->alpha; |
1190 | 0 | const int16_t beta = wm->beta; |
1191 | 0 | const int16_t gamma = wm->gamma; |
1192 | 0 | const int16_t delta = wm->delta; |
1193 | |
|
1194 | 0 | assert(IMPLIES(!is_scaled, |
1195 | 0 | wm->use_affine_filter == |
1196 | 0 | is_affine_shear_allowed(alpha, beta, gamma, delta))); |
1197 | 0 | assert(IMPLIES(is_scaled, !wm->use_affine_filter)); |
1198 | |
|
1199 | 0 | if (!wm->use_affine_filter || p_width < 8 || p_height < 8 || is_scaled) { |
1200 | 0 | WarpedMotionParams wm_scaled = *wm; |
1201 | 0 | if (is_scaled) { |
1202 | 0 | av2_ext_highbd_warp_affine_scaled_c( |
1203 | 0 | &wm_scaled.wmmat[0], ref, width, height, stride, pred, p_col, p_row, |
1204 | 0 | p_width, p_height, p_stride, subsampling_x, subsampling_y, bd, |
1205 | 0 | conv_params, sf, use_warp_bd_box, warp_bd_box); |
1206 | 0 | } else { |
1207 | 0 | av2_ext_highbd_warp_affine(&wm_scaled.wmmat[0], ref, width, height, |
1208 | 0 | stride, pred, p_col, p_row, p_width, p_height, |
1209 | 0 | p_stride, subsampling_x, subsampling_y, bd, |
1210 | 0 | conv_params, use_warp_bd_box, warp_bd_box); |
1211 | 0 | } |
1212 | 0 | } else { |
1213 | 0 | av2_highbd_warp_affine(mat, ref, width, height, stride, pred, p_col, p_row, |
1214 | 0 | p_width, p_height, p_stride, subsampling_x, |
1215 | 0 | subsampling_y, bd, conv_params, alpha, beta, gamma, |
1216 | 0 | delta); |
1217 | 0 | } |
1218 | 0 | } |
1219 | | |
1220 | | void av2_warp_plane(WarpedMotionParams *wm, int bd, const uint16_t *ref, |
1221 | | int width, int height, int stride, uint16_t *pred, |
1222 | | int p_col, int p_row, int p_width, int p_height, |
1223 | | int p_stride, int subsampling_x, int subsampling_y, |
1224 | | ConvolveParams *conv_params, const struct scale_factors *sf, |
1225 | 0 | int use_warp_bd_box, PadBlock *warp_bd_box) { |
1226 | 0 | av2_highbd_warp_plane(wm, ref, width, height, stride, pred, p_col, p_row, |
1227 | 0 | p_width, p_height, p_stride, subsampling_x, |
1228 | 0 | subsampling_y, bd, conv_params, sf, use_warp_bd_box, |
1229 | 0 | warp_bd_box); |
1230 | 0 | } |
1231 | | |
1232 | 0 | #define LS_MV_MAX 256 // max mv in 1/8-pel |
1233 | | // Use LS_STEP = 8 so that 2 less bits needed for A, Bx, By. |
1234 | 0 | #define LS_STEP 8 |
1235 | | |
1236 | | // Assuming LS_MV_MAX is < MAX_SB_SIZE * 8, |
1237 | | // the precision needed is: |
1238 | | // (MAX_SB_SIZE_LOG2 + 3) [for sx * sx magnitude] + |
1239 | | // (MAX_SB_SIZE_LOG2 + 4) [for sx * dx magnitude] + |
1240 | | // 1 [for sign] + |
1241 | | // LEAST_SQUARES_SAMPLES_MAX_BITS |
1242 | | // [for adding up to LEAST_SQUARES_SAMPLES_MAX samples] |
1243 | | // The value is 23 |
1244 | | #define LS_MAT_RANGE_BITS \ |
1245 | | ((MAX_SB_SIZE_LOG2 + 4) * 2 + LEAST_SQUARES_SAMPLES_MAX_BITS) |
1246 | | |
1247 | | // Bit-depth reduction from the full-range |
1248 | 0 | #define LS_MAT_DOWN_BITS 2 |
1249 | | |
1250 | | // bits range of A, Bx and By after downshifting |
1251 | | #define LS_MAT_BITS (LS_MAT_RANGE_BITS - LS_MAT_DOWN_BITS) |
1252 | | #define LS_MAT_MIN (-(1 << (LS_MAT_BITS - 1))) |
1253 | | #define LS_MAT_MAX ((1 << (LS_MAT_BITS - 1)) - 1) |
1254 | | |
1255 | | // By setting LS_STEP = 8, the least 2 bits of every elements in A, Bx, By are |
1256 | | // 0. So, we can reduce LS_MAT_RANGE_BITS(2) bits here. |
1257 | | #define LS_SQUARE(a) \ |
1258 | 0 | (((a) * (a) * 4 + (a) * 4 * LS_STEP + LS_STEP * LS_STEP * 2) >> \ |
1259 | 0 | (2 + LS_MAT_DOWN_BITS)) |
1260 | | #define LS_PRODUCT1(a, b) \ |
1261 | 0 | (((a) * (b) * 4 + ((a) + (b)) * 2 * LS_STEP + LS_STEP * LS_STEP) >> \ |
1262 | 0 | (2 + LS_MAT_DOWN_BITS)) |
1263 | | #define LS_PRODUCT2(a, b) \ |
1264 | 0 | (((a) * (b) * 4 + ((a) + (b)) * 2 * LS_STEP + LS_STEP * LS_STEP * 2) >> \ |
1265 | 0 | (2 + LS_MAT_DOWN_BITS)) |
1266 | | |
1267 | | #define USE_LIMITED_PREC_MULT 0 |
1268 | | |
1269 | | #if USE_LIMITED_PREC_MULT |
1270 | | |
1271 | | #define MUL_PREC_BITS 16 |
1272 | | static uint16_t resolve_multiplier_64(uint64_t D, int16_t *shift) { |
1273 | | int msb = 0; |
1274 | | uint16_t mult = 0; |
1275 | | *shift = 0; |
1276 | | if (D != 0) { |
1277 | | msb = (int16_t)((D >> 32) ? get_msb((unsigned int)(D >> 32)) + 32 |
1278 | | : get_msb((unsigned int)D)); |
1279 | | if (msb >= MUL_PREC_BITS) { |
1280 | | mult = (uint16_t)ROUND_POWER_OF_TWO_64(D, msb + 1 - MUL_PREC_BITS); |
1281 | | *shift = msb + 1 - MUL_PREC_BITS; |
1282 | | } else { |
1283 | | mult = (uint16_t)D; |
1284 | | *shift = 0; |
1285 | | } |
1286 | | } |
1287 | | return mult; |
1288 | | } |
1289 | | |
1290 | | static int32_t get_mult_shift_ndiag(int64_t Px, int16_t iDet, int shift) { |
1291 | | int32_t ret; |
1292 | | int16_t mshift; |
1293 | | uint16_t Mul = resolve_multiplier_64(llabs(Px), &mshift); |
1294 | | int32_t v = (int32_t)Mul * (int32_t)iDet * (Px < 0 ? -1 : 1); |
1295 | | shift -= mshift; |
1296 | | if (shift > 0) { |
1297 | | return (int32_t)clamp(ROUND_POWER_OF_TWO_SIGNED(v, shift), |
1298 | | -WARPEDMODEL_NONDIAGAFFINE_CLAMP + 1, |
1299 | | WARPEDMODEL_NONDIAGAFFINE_CLAMP - 1); |
1300 | | } else { |
1301 | | return (int32_t)clamp(v * (1 << (-shift)), |
1302 | | -WARPEDMODEL_NONDIAGAFFINE_CLAMP + 1, |
1303 | | WARPEDMODEL_NONDIAGAFFINE_CLAMP - 1); |
1304 | | } |
1305 | | return ret; |
1306 | | } |
1307 | | |
1308 | | static int32_t get_mult_shift_diag(int64_t Px, int16_t iDet, int shift) { |
1309 | | int16_t mshift; |
1310 | | uint16_t Mul = resolve_multiplier_64(llabs(Px), &mshift); |
1311 | | int32_t v = (int32_t)Mul * (int32_t)iDet * (Px < 0 ? -1 : 1); |
1312 | | shift -= mshift; |
1313 | | if (shift > 0) { |
1314 | | return (int32_t)clamp( |
1315 | | ROUND_POWER_OF_TWO_SIGNED(v, shift), |
1316 | | (1 << WARPEDMODEL_PREC_BITS) - WARPEDMODEL_NONDIAGAFFINE_CLAMP + 1, |
1317 | | (1 << WARPEDMODEL_PREC_BITS) + WARPEDMODEL_NONDIAGAFFINE_CLAMP - 1); |
1318 | | } else { |
1319 | | return (int32_t)clamp( |
1320 | | v * (1 << (-shift)), |
1321 | | (1 << WARPEDMODEL_PREC_BITS) - WARPEDMODEL_NONDIAGAFFINE_CLAMP + 1, |
1322 | | (1 << WARPEDMODEL_PREC_BITS) + WARPEDMODEL_NONDIAGAFFINE_CLAMP - 1); |
1323 | | } |
1324 | | } |
1325 | | #endif // USE_LIMITED_PREC_MULT |
1326 | | |
1327 | | static void find_affine_int(int np, const int *pts1, const int *pts2, |
1328 | | BLOCK_SIZE bsize, MV mv, WarpedMotionParams *wm, |
1329 | | int mi_row, int mi_col, |
1330 | 0 | const struct scale_factors *sf) { |
1331 | 0 | int32_t A[2][2] = { { 0, 0 }, { 0, 0 } }; |
1332 | 0 | int32_t Bx[2] = { 0, 0 }; |
1333 | 0 | int32_t By[2] = { 0, 0 }; |
1334 | |
|
1335 | 0 | const int bw = block_size_wide[bsize]; |
1336 | 0 | const int bh = block_size_high[bsize]; |
1337 | 0 | const int rsuy = bh / 2 - 1; |
1338 | 0 | const int rsux = bw / 2 - 1; |
1339 | 0 | const int suy = rsuy * 8; |
1340 | 0 | const int sux = rsux * 8; |
1341 | 0 | const int duy = suy + mv.row; |
1342 | 0 | const int dux = sux + mv.col; |
1343 | | |
1344 | | // Assume the center pixel of the block has exactly the same motion vector |
1345 | | // as transmitted for the block. First shift the origin of the source |
1346 | | // points to the block center, and the origin of the destination points to |
1347 | | // the block center added to the motion vector transmitted. |
1348 | | // Let (xi, yi) denote the source points and (xi', yi') denote destination |
1349 | | // points after origin shfifting, for i = 0, 1, 2, .... n-1. |
1350 | | // Then if P = [x0, y0, |
1351 | | // x1, y1 |
1352 | | // x2, y1, |
1353 | | // .... |
1354 | | // ] |
1355 | | // q = [x0', x1', x2', ... ]' |
1356 | | // r = [y0', y1', y2', ... ]' |
1357 | | // the least squares problems that need to be solved are: |
1358 | | // [h1, h2]' = inv(P'P)P'q and |
1359 | | // [h3, h4]' = inv(P'P)P'r |
1360 | | // where the affine transformation is given by: |
1361 | | // x' = h1.x + h2.y |
1362 | | // y' = h3.x + h4.y |
1363 | | // |
1364 | | // The loop below computes: A = P'P, Bx = P'q, By = P'r |
1365 | | // We need to just compute inv(A).Bx and inv(A).By for the solutions. |
1366 | | // Contribution from neighbor block |
1367 | 0 | for (int i = 0; i < np; i++) { |
1368 | 0 | const int dx = pts2[i * 2] - dux; |
1369 | 0 | const int dy = pts2[i * 2 + 1] - duy; |
1370 | 0 | const int sx = pts1[i * 2] - sux; |
1371 | 0 | const int sy = pts1[i * 2 + 1] - suy; |
1372 | | // (TODO)yunqing: This comparison wouldn't be necessary if the sample |
1373 | | // selection is done in find_samples(). Also, global offset can be removed |
1374 | | // while collecting samples. |
1375 | 0 | if (abs(sx - dx) < LS_MV_MAX && abs(sy - dy) < LS_MV_MAX) { |
1376 | 0 | A[0][0] += LS_SQUARE(sx); |
1377 | 0 | A[0][1] += LS_PRODUCT1(sx, sy); |
1378 | 0 | A[1][1] += LS_SQUARE(sy); |
1379 | 0 | Bx[0] += LS_PRODUCT2(sx, dx); |
1380 | 0 | Bx[1] += LS_PRODUCT1(sy, dx); |
1381 | 0 | By[0] += LS_PRODUCT1(sx, dy); |
1382 | 0 | By[1] += LS_PRODUCT2(sy, dy); |
1383 | 0 | } |
1384 | 0 | } |
1385 | | |
1386 | | // Just for debugging, and can be removed later. |
1387 | 0 | assert(A[0][0] >= LS_MAT_MIN && A[0][0] <= LS_MAT_MAX); |
1388 | 0 | assert(A[0][1] >= LS_MAT_MIN && A[0][1] <= LS_MAT_MAX); |
1389 | 0 | assert(A[1][1] >= LS_MAT_MIN && A[1][1] <= LS_MAT_MAX); |
1390 | 0 | assert(Bx[0] >= LS_MAT_MIN && Bx[0] <= LS_MAT_MAX); |
1391 | 0 | assert(Bx[1] >= LS_MAT_MIN && Bx[1] <= LS_MAT_MAX); |
1392 | 0 | assert(By[0] >= LS_MAT_MIN && By[0] <= LS_MAT_MAX); |
1393 | 0 | assert(By[1] >= LS_MAT_MIN && By[1] <= LS_MAT_MAX); |
1394 | | |
1395 | | // Compute Determinant of A |
1396 | 0 | const int64_t Det = (int64_t)A[0][0] * A[1][1] - (int64_t)A[0][1] * A[0][1]; |
1397 | 0 | if (Det == 0) { |
1398 | 0 | wm->wmmat[2] = (1 << WARPEDMODEL_PREC_BITS); |
1399 | 0 | wm->wmmat[3] = 0; |
1400 | 0 | wm->wmmat[4] = 0; |
1401 | 0 | wm->wmmat[5] = (1 << WARPEDMODEL_PREC_BITS); |
1402 | 0 | wm->wmmat[6] = 0; |
1403 | 0 | wm->wmmat[7] = 0; |
1404 | 0 | av2_get_shear_params(wm, sf); |
1405 | 0 | av2_set_warp_translation(mi_row, mi_col, bsize, mv, wm); |
1406 | 0 | return; |
1407 | 0 | } |
1408 | | |
1409 | 0 | int16_t shift; |
1410 | 0 | int16_t iDet = resolve_divisor_64(llabs(Det), &shift) * (Det < 0 ? -1 : 1); |
1411 | 0 | shift -= WARPEDMODEL_PREC_BITS; |
1412 | 0 | if (shift < 0) { |
1413 | 0 | iDet <<= (-shift); |
1414 | 0 | shift = 0; |
1415 | 0 | } |
1416 | |
|
1417 | 0 | int64_t Px[2], Py[2]; |
1418 | | // These divided by the Det, are the least squares solutions |
1419 | 0 | Px[0] = (int64_t)A[1][1] * Bx[0] - (int64_t)A[0][1] * Bx[1]; |
1420 | 0 | Px[1] = -(int64_t)A[0][1] * Bx[0] + (int64_t)A[0][0] * Bx[1]; |
1421 | 0 | Py[0] = (int64_t)A[1][1] * By[0] - (int64_t)A[0][1] * By[1]; |
1422 | 0 | Py[1] = -(int64_t)A[0][1] * By[0] + (int64_t)A[0][0] * By[1]; |
1423 | |
|
1424 | 0 | wm->wmmat[2] = |
1425 | 0 | clamp64_to_32(ROUND_POWER_OF_TWO_SIGNED_64(Px[0] * iDet, shift)); |
1426 | 0 | wm->wmmat[3] = |
1427 | 0 | clamp64_to_32(ROUND_POWER_OF_TWO_SIGNED_64(Px[1] * iDet, shift)); |
1428 | 0 | wm->wmmat[4] = |
1429 | 0 | clamp64_to_32(ROUND_POWER_OF_TWO_SIGNED_64(Py[0] * iDet, shift)); |
1430 | 0 | wm->wmmat[5] = |
1431 | 0 | clamp64_to_32(ROUND_POWER_OF_TWO_SIGNED_64(Py[1] * iDet, shift)); |
1432 | |
|
1433 | 0 | av2_reduce_warp_model(wm); |
1434 | 0 | av2_get_shear_params(wm, sf); |
1435 | 0 | av2_set_warp_translation(mi_row, mi_col, bsize, mv, wm); |
1436 | 0 | wm->wmmat[6] = wm->wmmat[7] = 0; |
1437 | 0 | } |
1438 | | |
1439 | | void av2_find_projection(int np, const int *pts1, const int *pts2, |
1440 | | BLOCK_SIZE bsize, MV mv, WarpedMotionParams *wm_params, |
1441 | | int mi_row, int mi_col, |
1442 | 0 | const struct scale_factors *sf) { |
1443 | 0 | assert(wm_params->wmtype <= AFFINE); |
1444 | 0 | find_affine_int(np, pts1, pts2, bsize, mv, wm_params, mi_row, mi_col, sf); |
1445 | 0 | wm_params->invalid = 0; |
1446 | 0 | } |
1447 | | |
1448 | | /* Given a neighboring block's warp model and the motion vector at the center |
1449 | | of the current block, construct a new warp model which is continuous with |
1450 | | the neighbor at the common edge but which has the given motion vector at |
1451 | | the center of the block. |
1452 | | |
1453 | | The `neighbor_is_above` parameter should be true if the neighboring block |
1454 | | is above the current block, or false if it is to the left of the current |
1455 | | block. |
1456 | | |
1457 | | Returns 0 if the resulting model can be used with the warp filter, |
1458 | | 1 if not. |
1459 | | */ |
1460 | | int av2_extend_warp_model(const bool neighbor_is_above, const BLOCK_SIZE bsize, |
1461 | | const MV *center_mv, const int mi_row, |
1462 | | const int mi_col, |
1463 | | const WarpedMotionParams *neighbor_wm, |
1464 | | WarpedMotionParams *wm_params, |
1465 | 0 | const struct scale_factors *sf) { |
1466 | 0 | const int half_width_log2 = mi_size_wide_log2[bsize] + MI_SIZE_LOG2 - 1; |
1467 | 0 | const int half_height_log2 = mi_size_high_log2[bsize] + MI_SIZE_LOG2 - 1; |
1468 | 0 | const int center_x = (mi_col * MI_SIZE) + (1 << half_width_log2) - 1; |
1469 | 0 | const int center_y = (mi_row * MI_SIZE) + (1 << half_height_log2) - 1; |
1470 | | // Calculate the point (at warp model precision) where the center of the |
1471 | | // current block should be mapped to |
1472 | 0 | int64_t proj_center_x = ((int64_t)center_x * (1 << WARPEDMODEL_PREC_BITS)) + |
1473 | 0 | (center_mv->col * (1 << (WARPEDMODEL_PREC_BITS - 3))); |
1474 | 0 | int64_t proj_center_y = ((int64_t)center_y * (1 << WARPEDMODEL_PREC_BITS)) + |
1475 | 0 | (center_mv->row * (1 << (WARPEDMODEL_PREC_BITS - 3))); |
1476 | |
|
1477 | 0 | *wm_params = default_warp_params; |
1478 | 0 | wm_params->wmtype = AFFINE; |
1479 | |
|
1480 | 0 | if (neighbor_is_above) { |
1481 | | // We want to construct a model which will project the block center |
1482 | | // according to the signaled motion vector, and which matches the |
1483 | | // neighbor's warp model along the top edge of the block. |
1484 | | // |
1485 | | // We do this in three steps: |
1486 | | // 1) Since the models should match along the whole top edge of the block, |
1487 | | // the coefficients of x in the warp model must be the same as for the |
1488 | | // neighboring block |
1489 | | // |
1490 | | // 2) The coefficients of y in the warp model can then be determined from |
1491 | | // the difference in projected positions between a point on the edge |
1492 | | // and the block center |
1493 | | // |
1494 | | // 3) The translational part can be derived (outside of this `if`) |
1495 | | // by subtracting the linear part of the model from the signaled MV. |
1496 | |
|
1497 | 0 | wm_params->wmmat[2] = neighbor_wm->wmmat[2]; |
1498 | 0 | wm_params->wmmat[4] = neighbor_wm->wmmat[4]; |
1499 | | |
1500 | | // Project above point |
1501 | 0 | int64_t above_x = center_x; |
1502 | 0 | int64_t above_y = center_y - (1 << half_height_log2); |
1503 | 0 | int64_t proj_above_x = neighbor_wm->wmmat[2] * above_x + |
1504 | 0 | neighbor_wm->wmmat[3] * above_y + |
1505 | 0 | neighbor_wm->wmmat[0]; |
1506 | 0 | int64_t proj_above_y = neighbor_wm->wmmat[4] * above_x + |
1507 | 0 | neighbor_wm->wmmat[5] * above_y + |
1508 | 0 | neighbor_wm->wmmat[1]; |
1509 | | |
1510 | | // y coefficients are (project(center) - project(above)) / (center.y - |
1511 | | // above.y), which simplifies to (project(center) - project(above)) / |
1512 | | // 2^(half_height_log2) |
1513 | 0 | wm_params->wmmat[3] = clamp64_to_32( |
1514 | 0 | ROUND_POWER_OF_TWO_64(proj_center_x - proj_above_x, half_height_log2)); |
1515 | 0 | wm_params->wmmat[5] = clamp64_to_32( |
1516 | 0 | ROUND_POWER_OF_TWO_64(proj_center_y - proj_above_y, half_height_log2)); |
1517 | 0 | } else { |
1518 | | // If the neighboring block is to the left of the current block, we do the |
1519 | | // same thing as for the above case, but with x and y axes interchanged |
1520 | |
|
1521 | 0 | wm_params->wmmat[3] = neighbor_wm->wmmat[3]; |
1522 | 0 | wm_params->wmmat[5] = neighbor_wm->wmmat[5]; |
1523 | | |
1524 | | // Project left point |
1525 | 0 | int64_t left_x = center_x - (1 << half_width_log2); |
1526 | 0 | int64_t left_y = center_y; |
1527 | 0 | int64_t proj_left_x = neighbor_wm->wmmat[2] * left_x + |
1528 | 0 | neighbor_wm->wmmat[3] * left_y + |
1529 | 0 | neighbor_wm->wmmat[0]; |
1530 | 0 | int64_t proj_left_y = neighbor_wm->wmmat[4] * left_x + |
1531 | 0 | neighbor_wm->wmmat[5] * left_y + |
1532 | 0 | neighbor_wm->wmmat[1]; |
1533 | | |
1534 | | // y coefficients are |
1535 | | // (project(center) - project(left)) / (center.y - left.y) |
1536 | | // which simplifies to |
1537 | | // (project(center) - project(left)) / 2^(half_width_log2) |
1538 | 0 | wm_params->wmmat[2] = clamp64_to_32( |
1539 | 0 | ROUND_POWER_OF_TWO_64(proj_center_x - proj_left_x, half_width_log2)); |
1540 | 0 | wm_params->wmmat[4] = clamp64_to_32( |
1541 | 0 | ROUND_POWER_OF_TWO_64(proj_center_y - proj_left_y, half_width_log2)); |
1542 | 0 | } |
1543 | |
|
1544 | 0 | av2_reduce_warp_model(wm_params); |
1545 | | // check compatibility with the fast warp filter |
1546 | 0 | av2_get_shear_params(wm_params, sf); |
1547 | | |
1548 | | // Derive translational part from signaled MV |
1549 | 0 | av2_set_warp_translation(mi_row, mi_col, bsize, *center_mv, wm_params); |
1550 | 0 | wm_params->invalid = 0; |
1551 | 0 | return 0; |
1552 | 0 | } |
1553 | | |
1554 | | // From the warp model, derive the MV in (x,y) position. |
1555 | | // (x,y) is the horizontal and vertical position of the frame |
1556 | | //(0,0) is the top-left co-ordinate of the frame |
1557 | | int_mv get_warp_motion_vector_xy_pos(const MACROBLOCKD *xd, |
1558 | | const WarpedMotionParams *model, |
1559 | | const int x, const int y, |
1560 | 0 | MvSubpelPrecision precision) { |
1561 | 0 | int_mv res; |
1562 | 0 | int tx, ty; |
1563 | |
|
1564 | 0 | if (model->wmtype == IDENTITY) { |
1565 | 0 | res.as_int = 0; |
1566 | 0 | return res; |
1567 | 0 | } |
1568 | | |
1569 | 0 | if (model->wmtype == TRANSLATION) { |
1570 | 0 | tx = convert_to_trans_prec(precision, model->wmmat[0]); |
1571 | 0 | ty = convert_to_trans_prec(precision, model->wmmat[1]); |
1572 | |
|
1573 | 0 | res.as_mv.row = clamp(ty, MV_LOW + 1, MV_UPP - 1); |
1574 | 0 | res.as_mv.col = clamp(tx, MV_LOW + 1, MV_UPP - 1); |
1575 | |
|
1576 | 0 | clamp_mv_ref(&res.as_mv, xd->width << MI_SIZE_LOG2, |
1577 | 0 | xd->height << MI_SIZE_LOG2, xd); |
1578 | |
|
1579 | 0 | if (precision < MV_PRECISION_HALF_PEL) |
1580 | 0 | lower_mv_precision(&res.as_mv, precision); |
1581 | 0 | return res; |
1582 | 0 | } |
1583 | | |
1584 | 0 | const int32_t *mat = model->wmmat; |
1585 | |
|
1586 | 0 | if (model->wmtype == ROTZOOM) { |
1587 | 0 | assert(model->wmmat[5] == model->wmmat[2]); |
1588 | 0 | assert(model->wmmat[4] == -model->wmmat[3]); |
1589 | 0 | } |
1590 | |
|
1591 | 0 | int xc = get_subblk_offset_x_hp(mat, x, y, (1 << WARPEDMODEL_PREC_BITS)); |
1592 | 0 | int yc = get_subblk_offset_y_hp(mat, x, y, (1 << WARPEDMODEL_PREC_BITS)); |
1593 | |
|
1594 | 0 | tx = convert_to_trans_prec(precision, xc); |
1595 | 0 | ty = convert_to_trans_prec(precision, yc); |
1596 | |
|
1597 | 0 | res.as_mv.row = clamp(ty, MV_LOW + 1, MV_UPP - 1); |
1598 | 0 | res.as_mv.col = clamp(tx, MV_LOW + 1, MV_UPP - 1); |
1599 | |
|
1600 | 0 | clamp_mv_ref(&res.as_mv, xd->width << MI_SIZE_LOG2, |
1601 | 0 | xd->height << MI_SIZE_LOG2, xd); |
1602 | |
|
1603 | 0 | if (precision < MV_PRECISION_HALF_PEL) |
1604 | 0 | lower_mv_precision(&res.as_mv, precision); |
1605 | 0 | return res; |
1606 | 0 | } |
1607 | | |
1608 | | // return 0 if the model is invalid |
1609 | | // pts (col, row) is the array of source points in the unit of integer pixel |
1610 | | // mvs are the array of the MVs corresponding to the source points |
1611 | | // for nth point, |
1612 | | // pts[2*n] is the col value of the source position. pts[2*n + 1] is the row |
1613 | | // value of the source position mvs[2*n] is the col value of mv. mvs[2*n + 1] |
1614 | | // is the row value of mv pts_inref[2*n] is the col value of the projected |
1615 | | // position. pts_inref[2*n + 1] is the row value of the projected position |
1616 | | int get_model_from_corner_mvs(WarpedMotionParams *derive_model, int *pts, |
1617 | | int np, int *mvs, const BLOCK_SIZE bsize, |
1618 | 0 | const struct scale_factors *sf) { |
1619 | | // In order to derive the warp model we need 3 projected points |
1620 | | // If the number of projected points (np) is not equal to 3, model is not |
1621 | | // valid. |
1622 | 0 | if (np != 3) { |
1623 | 0 | derive_model->invalid = 1; |
1624 | 0 | return 0; |
1625 | 0 | } |
1626 | | |
1627 | 0 | int x0, y0; |
1628 | 0 | int64_t ref_x0, ref_x1, ref_x2, ref_y0, ref_y1, ref_y2; |
1629 | 0 | int64_t pts_inref[2 * 3]; |
1630 | 0 | const int width_log2 = mi_size_wide_log2[bsize] + MI_SIZE_LOG2; |
1631 | 0 | const int height_log2 = mi_size_high_log2[bsize] + MI_SIZE_LOG2; |
1632 | |
|
1633 | 0 | assert(derive_model != NULL); |
1634 | |
|
1635 | 0 | for (int n = 0; n < np; n++) { |
1636 | 0 | pts_inref[2 * n] = (int64_t)pts[2 * n] * (1 << WARPEDMODEL_PREC_BITS) + |
1637 | 0 | (int64_t)mvs[2 * n] * (1 << GM_TRANS_ONLY_PREC_DIFF); |
1638 | 0 | pts_inref[2 * n + 1] = |
1639 | 0 | (int64_t)pts[2 * n + 1] * (1 << WARPEDMODEL_PREC_BITS) + |
1640 | 0 | (int64_t)mvs[2 * n + 1] * (1 << GM_TRANS_ONLY_PREC_DIFF); |
1641 | 0 | int valid_point = |
1642 | 0 | ((int64_t)pts[2 * n] >= 0 && (int64_t)pts[2 * n + 1] >= 0 && |
1643 | 0 | pts_inref[2 * n] >= 0 && pts_inref[2 * n + 1] >= 0); |
1644 | 0 | if (!valid_point) return 0; |
1645 | 0 | } |
1646 | | |
1647 | 0 | int all_mvs_same = 1; |
1648 | 0 | for (int k = 1; k < np; k++) { |
1649 | 0 | all_mvs_same &= (mvs[0] == mvs[2 * k]) & (mvs[1] == mvs[2 * k + 1]); |
1650 | 0 | } |
1651 | 0 | if (all_mvs_same) { |
1652 | 0 | derive_model->invalid = 1; |
1653 | 0 | return 0; |
1654 | 0 | } |
1655 | | |
1656 | | // Top-left point |
1657 | 0 | x0 = pts[2 * 0]; |
1658 | 0 | y0 = pts[2 * 0 + 1]; |
1659 | 0 | ref_x0 = pts_inref[2 * 0]; |
1660 | 0 | ref_y0 = pts_inref[2 * 0 + 1]; |
1661 | | |
1662 | | // Top-right point |
1663 | 0 | ref_x1 = pts_inref[2 * 1]; |
1664 | 0 | ref_y1 = pts_inref[2 * 1 + 1]; |
1665 | | |
1666 | | // Bottom-left point |
1667 | 0 | ref_x2 = pts_inref[2 * 2]; |
1668 | 0 | ref_y2 = pts_inref[2 * 2 + 1]; |
1669 | |
|
1670 | 0 | derive_model->wmmat[2] = clamp64_to_32((ref_x1 - ref_x0) >> width_log2); |
1671 | 0 | derive_model->wmmat[4] = clamp64_to_32((ref_y1 - ref_y0) >> width_log2); |
1672 | |
|
1673 | 0 | derive_model->wmmat[3] = clamp64_to_32((ref_x2 - ref_x0) >> height_log2); |
1674 | 0 | derive_model->wmmat[5] = clamp64_to_32((ref_y2 - ref_y0) >> height_log2); |
1675 | |
|
1676 | 0 | int64_t wmmat0 = (int64_t)ref_x0 - |
1677 | 0 | (int64_t)derive_model->wmmat[2] * (int64_t)x0 - |
1678 | 0 | (int64_t)derive_model->wmmat[3] * (int64_t)y0; |
1679 | 0 | int64_t wmmat1 = (int64_t)ref_y0 - |
1680 | 0 | (int64_t)derive_model->wmmat[4] * (int64_t)x0 - |
1681 | 0 | (int64_t)derive_model->wmmat[5] * (int64_t)y0; |
1682 | |
|
1683 | 0 | derive_model->wmtype = AFFINE; |
1684 | 0 | derive_model->invalid = 0; |
1685 | |
|
1686 | 0 | av2_reduce_warp_model(derive_model); |
1687 | | |
1688 | | // check compatibility with the fast warp filter |
1689 | 0 | av2_get_shear_params(derive_model, sf); |
1690 | |
|
1691 | 0 | derive_model->wmmat[0] = |
1692 | 0 | (int32_t)clamp64(wmmat0, -WARPEDMODEL_TRANS_CLAMP, |
1693 | 0 | WARPEDMODEL_TRANS_CLAMP - (1 << WARP_PARAM_REDUCE_BITS)); |
1694 | 0 | derive_model->wmmat[1] = |
1695 | 0 | (int32_t)clamp64(wmmat1, -WARPEDMODEL_TRANS_CLAMP, |
1696 | 0 | WARPEDMODEL_TRANS_CLAMP - (1 << WARP_PARAM_REDUCE_BITS)); |
1697 | |
|
1698 | 0 | derive_model->wmmat[6] = derive_model->wmmat[7] = 0; |
1699 | |
|
1700 | 0 | return 1; |
1701 | 0 | } |