Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * This file is part of FFmpeg. | |
3 | * | |
4 | * FFmpeg is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU Lesser General Public | |
6 | * License as published by the Free Software Foundation; either | |
7 | * version 2.1 of the License, or (at your option) any later version. | |
8 | * | |
9 | * FFmpeg is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | * Lesser General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU Lesser General Public | |
15 | * License along with FFmpeg; if not, write to the Free Software | |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | ||
19 | #include "config.h" | |
20 | #include "common.h" | |
21 | #include "pixelutils.h" | |
22 | ||
23 | #if CONFIG_PIXELUTILS | |
24 | ||
25 | #include "x86/pixelutils.h" | |
26 | ||
27 | static av_always_inline int sad_wxh(const uint8_t *src1, ptrdiff_t stride1, | |
28 | const uint8_t *src2, ptrdiff_t stride2, | |
29 | int w, int h) | |
30 | { | |
31 | int x, y, sum = 0; | |
32 | ||
33 | for (y = 0; y < h; y++) { | |
34 | for (x = 0; x < w; x++) | |
35 | sum += abs(src1[x] - src2[x]); | |
36 | src1 += stride1; | |
37 | src2 += stride2; | |
38 | } | |
39 | return sum; | |
40 | } | |
41 | ||
42 | #define DECLARE_BLOCK_FUNCTIONS(size) \ | |
43 | static int block_sad_##size##x##size##_c(const uint8_t *src1, ptrdiff_t stride1, \ | |
44 | const uint8_t *src2, ptrdiff_t stride2) \ | |
45 | { \ | |
46 | return sad_wxh(src1, stride1, src2, stride2, size, size); \ | |
47 | } | |
48 | ||
49 | DECLARE_BLOCK_FUNCTIONS(2) | |
50 | DECLARE_BLOCK_FUNCTIONS(4) | |
51 | DECLARE_BLOCK_FUNCTIONS(8) | |
52 | DECLARE_BLOCK_FUNCTIONS(16) | |
53 | ||
54 | static const av_pixelutils_sad_fn sad_c[] = { | |
55 | block_sad_2x2_c, | |
56 | block_sad_4x4_c, | |
57 | block_sad_8x8_c, | |
58 | block_sad_16x16_c, | |
59 | }; | |
60 | ||
61 | #endif /* CONFIG_PIXELUTILS */ | |
62 | ||
63 | av_pixelutils_sad_fn av_pixelutils_get_sad_fn(int w_bits, int h_bits, int aligned, void *log_ctx) | |
64 | { | |
65 | #if !CONFIG_PIXELUTILS | |
66 | av_log(log_ctx, AV_LOG_ERROR, "pixelutils support is required " | |
67 | "but libavutil is not compiled with it\n"); | |
68 | return NULL; | |
69 | #else | |
70 | av_pixelutils_sad_fn sad[FF_ARRAY_ELEMS(sad_c)]; | |
71 | ||
72 | memcpy(sad, sad_c, sizeof(sad)); | |
73 | ||
74 | if (w_bits < 1 || w_bits > FF_ARRAY_ELEMS(sad) || | |
75 | h_bits < 1 || h_bits > FF_ARRAY_ELEMS(sad)) | |
76 | return NULL; | |
77 | if (w_bits != h_bits) // only squared sad for now | |
78 | return NULL; | |
79 | ||
80 | #if ARCH_X86 | |
81 | ff_pixelutils_sad_init_x86(sad, aligned); | |
82 | #endif | |
83 | ||
84 | return sad[w_bits - 1]; | |
85 | #endif | |
86 | } | |
87 | ||
88 | #ifdef TEST | |
89 | #define W1 320 | |
90 | #define H1 240 | |
91 | #define W2 640 | |
92 | #define H2 480 | |
93 | ||
94 | static int run_single_test(const char *test, | |
95 | const uint8_t *block1, ptrdiff_t stride1, | |
96 | const uint8_t *block2, ptrdiff_t stride2, | |
97 | int align, int n) | |
98 | { | |
99 | int out, ref; | |
100 | av_pixelutils_sad_fn f_ref = sad_c[n - 1]; | |
101 | av_pixelutils_sad_fn f_out = av_pixelutils_get_sad_fn(n, n, align, NULL); | |
102 | ||
103 | switch (align) { | |
104 | case 0: block1++; block2++; break; | |
105 | case 1: block2++; break; | |
106 | case 2: break; | |
107 | } | |
108 | ||
109 | out = f_out(block1, stride1, block2, stride2); | |
110 | ref = f_ref(block1, stride1, block2, stride2); | |
111 | printf("[%s] [%c%c] SAD [%s] %dx%d=%d ref=%d\n", | |
112 | out == ref ? "OK" : "FAIL", | |
113 | align ? 'A' : 'U', align == 2 ? 'A' : 'U', | |
114 | test, 1<<n, 1<<n, out, ref); | |
115 | return out != ref; | |
116 | } | |
117 | ||
118 | static int run_test(const char *test, | |
119 | const uint8_t *b1, const uint8_t *b2) | |
120 | { | |
121 | int i, a, ret = 0; | |
122 | ||
123 | for (a = 0; a < 3; a++) { | |
124 | const uint8_t *block1 = b1; | |
125 | const uint8_t *block2 = b2; | |
126 | ||
127 | switch (a) { | |
128 | case 0: block1++; block2++; break; | |
129 | case 1: block2++; break; | |
130 | case 2: break; | |
131 | } | |
132 | for (i = 1; i <= FF_ARRAY_ELEMS(sad_c); i++) { | |
133 | int r = run_single_test(test, b1, W1, b2, W2, a, i); | |
134 | if (r) | |
135 | ret = r; | |
136 | } | |
137 | } | |
138 | return ret; | |
139 | } | |
140 | ||
141 | int main(void) | |
142 | { | |
143 | int i, align, ret; | |
144 | uint8_t *buf1 = av_malloc(W1*H1); | |
145 | uint8_t *buf2 = av_malloc(W2*H2); | |
146 | uint32_t state = 0; | |
147 | ||
148 | if (!buf1 || !buf2) { | |
149 | fprintf(stderr, "malloc failure\n"); | |
150 | ret = 1; | |
151 | goto end; | |
152 | } | |
153 | ||
154 | #define RANDOM_INIT(buf, size) do { \ | |
155 | int k; \ | |
156 | for (k = 0; k < size; k++) { \ | |
157 | state = state * 1664525 + 1013904223; \ | |
158 | buf[k] = state>>24; \ | |
159 | } \ | |
160 | } while (0) | |
161 | ||
162 | /* Normal test with different strides */ | |
163 | RANDOM_INIT(buf1, W1*H1); | |
164 | RANDOM_INIT(buf2, W2*H2); | |
165 | ret = run_test("random", buf1, buf2); | |
166 | if (ret < 0) | |
167 | goto end; | |
168 | ||
169 | /* Check for maximum SAD */ | |
170 | memset(buf1, 0xff, W1*H1); | |
171 | memset(buf2, 0x00, W2*H2); | |
172 | ret = run_test("max", buf1, buf2); | |
173 | if (ret < 0) | |
174 | goto end; | |
175 | ||
176 | /* Check for minimum SAD */ | |
177 | memset(buf1, 0x90, W1*H1); | |
178 | memset(buf2, 0x90, W2*H2); | |
179 | ret = run_test("min", buf1, buf2); | |
180 | if (ret < 0) | |
181 | goto end; | |
182 | ||
183 | /* Exact buffer sizes, to check for overreads */ | |
184 | for (i = 1; i <= 4; i++) { | |
185 | for (align = 0; align < 3; align++) { | |
186 | int size1, size2; | |
187 | ||
188 | av_freep(&buf1); | |
189 | av_freep(&buf2); | |
190 | ||
191 | size1 = size2 = 1 << (i << 1); | |
192 | ||
193 | switch (align) { | |
194 | case 0: size1++; size2++; break; | |
195 | case 1: size2++; break; | |
196 | case 2: break; | |
197 | } | |
198 | ||
199 | buf1 = av_malloc(size1); | |
200 | buf2 = av_malloc(size2); | |
201 | if (!buf1 || !buf2) { | |
202 | fprintf(stderr, "malloc failure\n"); | |
203 | ret = 1; | |
204 | goto end; | |
205 | } | |
206 | RANDOM_INIT(buf1, size1); | |
207 | RANDOM_INIT(buf2, size2); | |
208 | ret = run_single_test("small", buf1, 1<<i, buf2, 1<<i, align, i); | |
209 | if (ret < 0) | |
210 | goto end; | |
211 | } | |
212 | } | |
213 | ||
214 | end: | |
215 | av_free(buf1); | |
216 | av_free(buf2); | |
217 | return ret; | |
218 | } | |
219 | #endif /* TEST */ |