1 /*
2 * Copyright 2011 The LibYuv Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <stdlib.h>
12 #include <time.h>
13
14 #include "libyuv/basic_types.h"
15 #include "libyuv/compare.h"
16 #include "libyuv/convert.h"
17 #include "libyuv/convert_argb.h"
18 #include "libyuv/convert_from.h"
19 #include "libyuv/convert_from_argb.h"
20 #include "libyuv/cpu_id.h"
21 #ifdef HAVE_JPEG
22 #include "libyuv/mjpeg_decoder.h"
23 #endif
24 #include "../unit_test/unit_test.h"
25 #include "libyuv/planar_functions.h"
26 #include "libyuv/rotate.h"
27 #include "libyuv/video_common.h"
28
29 namespace libyuv {
30
31 #define SUBSAMPLE(v, a) ((((v) + (a)-1)) / (a))
32
33 #define TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
34 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF) \
35 TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) { \
36 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
37 const int kHeight = benchmark_height_; \
38 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
39 align_buffer_page_end(src_u, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * \
40 SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + \
41 OFF); \
42 align_buffer_page_end(src_v, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * \
43 SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + \
44 OFF); \
45 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
46 align_buffer_page_end(dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
47 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
48 align_buffer_page_end(dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
49 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
50 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
51 align_buffer_page_end(dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
52 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
53 align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
54 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
55 for (int i = 0; i < kHeight; ++i) \
56 for (int j = 0; j < kWidth; ++j) \
57 src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \
58 for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) { \
59 for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) { \
60 src_u[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] = \
61 (fastrand() & 0xff); \
62 src_v[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] = \
63 (fastrand() & 0xff); \
64 } \
65 } \
66 memset(dst_y_c, 1, kWidth* kHeight); \
67 memset(dst_u_c, 2, \
68 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
69 memset(dst_v_c, 3, \
70 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
71 memset(dst_y_opt, 101, kWidth* kHeight); \
72 memset(dst_u_opt, 102, \
73 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
74 memset(dst_v_opt, 103, \
75 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
76 MaskCpuFlags(disable_cpu_flags_); \
77 SRC_FMT_PLANAR##To##FMT_PLANAR( \
78 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
79 src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_c, kWidth, \
80 dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_c, \
81 SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
82 MaskCpuFlags(benchmark_cpu_info_); \
83 for (int i = 0; i < benchmark_iterations_; ++i) { \
84 SRC_FMT_PLANAR##To##FMT_PLANAR( \
85 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
86 src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_opt, kWidth, \
87 dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_opt, \
88 SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
89 } \
90 int max_diff = 0; \
91 for (int i = 0; i < kHeight; ++i) { \
92 for (int j = 0; j < kWidth; ++j) { \
93 int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
94 static_cast<int>(dst_y_opt[i * kWidth + j])); \
95 if (abs_diff > max_diff) { \
96 max_diff = abs_diff; \
97 } \
98 } \
99 } \
100 EXPECT_EQ(0, max_diff); \
101 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
102 for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
103 int abs_diff = abs( \
104 static_cast<int>(dst_u_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
105 static_cast<int>( \
106 dst_u_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
107 if (abs_diff > max_diff) { \
108 max_diff = abs_diff; \
109 } \
110 } \
111 } \
112 EXPECT_LE(max_diff, 3); \
113 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
114 for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
115 int abs_diff = abs( \
116 static_cast<int>(dst_v_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
117 static_cast<int>( \
118 dst_v_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
119 if (abs_diff > max_diff) { \
120 max_diff = abs_diff; \
121 } \
122 } \
123 } \
124 EXPECT_LE(max_diff, 3); \
125 free_aligned_buffer_page_end(dst_y_c); \
126 free_aligned_buffer_page_end(dst_u_c); \
127 free_aligned_buffer_page_end(dst_v_c); \
128 free_aligned_buffer_page_end(dst_y_opt); \
129 free_aligned_buffer_page_end(dst_u_opt); \
130 free_aligned_buffer_page_end(dst_v_opt); \
131 free_aligned_buffer_page_end(src_y); \
132 free_aligned_buffer_page_end(src_u); \
133 free_aligned_buffer_page_end(src_v); \
134 }
135
136 #define TESTPLANARTOP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
137 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \
138 TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
139 SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0) \
140 TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
141 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Unaligned, +, 1) \
142 TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
143 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0) \
144 TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
145 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0)
146
147 TESTPLANARTOP(I420, 2, 2, I420, 2, 2)
148 TESTPLANARTOP(I422, 2, 1, I420, 2, 2)
149 TESTPLANARTOP(I444, 1, 1, I420, 2, 2)
150 TESTPLANARTOP(I420, 2, 2, I422, 2, 1)
151 TESTPLANARTOP(I420, 2, 2, I444, 1, 1)
152 TESTPLANARTOP(I420, 2, 2, I420Mirror, 2, 2)
153 TESTPLANARTOP(I422, 2, 1, I422, 2, 1)
154 TESTPLANARTOP(I444, 1, 1, I444, 1, 1)
155
156 // Test Android 420 to I420
157 #define TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, \
158 SRC_SUBSAMP_Y, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
159 W1280, N, NEG, OFF, PN, OFF_U, OFF_V) \
160 TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##_##PN##N) { \
161 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
162 const int kHeight = benchmark_height_; \
163 const int kSizeUV = \
164 SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); \
165 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
166 align_buffer_page_end(src_uv, \
167 kSizeUV*((PIXEL_STRIDE == 3) ? 3 : 2) + OFF); \
168 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
169 align_buffer_page_end(dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
170 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
171 align_buffer_page_end(dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
172 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
173 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
174 align_buffer_page_end(dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
175 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
176 align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
177 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
178 uint8* src_u = src_uv + OFF_U; \
179 uint8* src_v = src_uv + (PIXEL_STRIDE == 1 ? kSizeUV : OFF_V); \
180 int src_stride_uv = SUBSAMPLE(kWidth, SUBSAMP_X) * PIXEL_STRIDE; \
181 for (int i = 0; i < kHeight; ++i) \
182 for (int j = 0; j < kWidth; ++j) \
183 src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \
184 for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) { \
185 for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) { \
186 src_u[(i * src_stride_uv) + j * PIXEL_STRIDE + OFF] = \
187 (fastrand() & 0xff); \
188 src_v[(i * src_stride_uv) + j * PIXEL_STRIDE + OFF] = \
189 (fastrand() & 0xff); \
190 } \
191 } \
192 memset(dst_y_c, 1, kWidth* kHeight); \
193 memset(dst_u_c, 2, \
194 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
195 memset(dst_v_c, 3, \
196 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
197 memset(dst_y_opt, 101, kWidth* kHeight); \
198 memset(dst_u_opt, 102, \
199 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
200 memset(dst_v_opt, 103, \
201 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
202 MaskCpuFlags(disable_cpu_flags_); \
203 SRC_FMT_PLANAR##To##FMT_PLANAR( \
204 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
205 src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), PIXEL_STRIDE, dst_y_c, \
206 kWidth, dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_c, \
207 SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
208 MaskCpuFlags(benchmark_cpu_info_); \
209 for (int i = 0; i < benchmark_iterations_; ++i) { \
210 SRC_FMT_PLANAR##To##FMT_PLANAR( \
211 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
212 src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), PIXEL_STRIDE, \
213 dst_y_opt, kWidth, dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X), \
214 dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
215 } \
216 int max_diff = 0; \
217 for (int i = 0; i < kHeight; ++i) { \
218 for (int j = 0; j < kWidth; ++j) { \
219 int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
220 static_cast<int>(dst_y_opt[i * kWidth + j])); \
221 if (abs_diff > max_diff) { \
222 max_diff = abs_diff; \
223 } \
224 } \
225 } \
226 EXPECT_EQ(0, max_diff); \
227 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
228 for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
229 int abs_diff = abs( \
230 static_cast<int>(dst_u_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
231 static_cast<int>( \
232 dst_u_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
233 if (abs_diff > max_diff) { \
234 max_diff = abs_diff; \
235 } \
236 } \
237 } \
238 EXPECT_LE(max_diff, 3); \
239 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
240 for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
241 int abs_diff = abs( \
242 static_cast<int>(dst_v_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
243 static_cast<int>( \
244 dst_v_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
245 if (abs_diff > max_diff) { \
246 max_diff = abs_diff; \
247 } \
248 } \
249 } \
250 EXPECT_LE(max_diff, 3); \
251 free_aligned_buffer_page_end(dst_y_c); \
252 free_aligned_buffer_page_end(dst_u_c); \
253 free_aligned_buffer_page_end(dst_v_c); \
254 free_aligned_buffer_page_end(dst_y_opt); \
255 free_aligned_buffer_page_end(dst_u_opt); \
256 free_aligned_buffer_page_end(dst_v_opt); \
257 free_aligned_buffer_page_end(src_y); \
258 free_aligned_buffer_page_end(src_uv); \
259 }
260
261 #define TESTAPLANARTOP(SRC_FMT_PLANAR, PN, PIXEL_STRIDE, OFF_U, OFF_V, \
262 SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, SUBSAMP_X, \
263 SUBSAMP_Y) \
264 TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
265 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, \
266 _Any, +, 0, PN, OFF_U, OFF_V) \
267 TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
268 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_, \
269 _Unaligned, +, 1, PN, OFF_U, OFF_V) \
270 TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
271 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, \
272 -, 0, PN, OFF_U, OFF_V) \
273 TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
274 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, \
275 0, PN, OFF_U, OFF_V)
276
277 TESTAPLANARTOP(Android420, I420, 1, 0, 0, 2, 2, I420, 2, 2)
278 TESTAPLANARTOP(Android420, NV12, 2, 0, 1, 2, 2, I420, 2, 2)
279 TESTAPLANARTOP(Android420, NV21, 2, 1, 0, 2, 2, I420, 2, 2)
280
281 #define TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
282 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF) \
283 TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) { \
284 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
285 const int kHeight = benchmark_height_; \
286 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
287 align_buffer_page_end(src_u, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * \
288 SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + \
289 OFF); \
290 align_buffer_page_end(src_v, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * \
291 SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + \
292 OFF); \
293 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
294 align_buffer_page_end(dst_uv_c, SUBSAMPLE(kWidth * 2, SUBSAMP_X) * \
295 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
296 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
297 align_buffer_page_end(dst_uv_opt, SUBSAMPLE(kWidth * 2, SUBSAMP_X) * \
298 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
299 for (int i = 0; i < kHeight; ++i) \
300 for (int j = 0; j < kWidth; ++j) \
301 src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \
302 for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) { \
303 for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) { \
304 src_u[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] = \
305 (fastrand() & 0xff); \
306 src_v[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] = \
307 (fastrand() & 0xff); \
308 } \
309 } \
310 memset(dst_y_c, 1, kWidth* kHeight); \
311 memset(dst_uv_c, 2, \
312 SUBSAMPLE(kWidth * 2, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
313 memset(dst_y_opt, 101, kWidth* kHeight); \
314 memset(dst_uv_opt, 102, \
315 SUBSAMPLE(kWidth * 2, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
316 MaskCpuFlags(disable_cpu_flags_); \
317 SRC_FMT_PLANAR##To##FMT_PLANAR( \
318 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
319 src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_c, kWidth, \
320 dst_uv_c, SUBSAMPLE(kWidth * 2, SUBSAMP_X), kWidth, NEG kHeight); \
321 MaskCpuFlags(benchmark_cpu_info_); \
322 for (int i = 0; i < benchmark_iterations_; ++i) { \
323 SRC_FMT_PLANAR##To##FMT_PLANAR( \
324 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
325 src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_opt, kWidth, \
326 dst_uv_opt, SUBSAMPLE(kWidth * 2, SUBSAMP_X), kWidth, NEG kHeight); \
327 } \
328 int max_diff = 0; \
329 for (int i = 0; i < kHeight; ++i) { \
330 for (int j = 0; j < kWidth; ++j) { \
331 int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
332 static_cast<int>(dst_y_opt[i * kWidth + j])); \
333 if (abs_diff > max_diff) { \
334 max_diff = abs_diff; \
335 } \
336 } \
337 } \
338 EXPECT_LE(max_diff, 1); \
339 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
340 for (int j = 0; j < SUBSAMPLE(kWidth * 2, SUBSAMP_X); ++j) { \
341 int abs_diff = \
342 abs(static_cast<int>( \
343 dst_uv_c[i * SUBSAMPLE(kWidth * 2, SUBSAMP_X) + j]) - \
344 static_cast<int>( \
345 dst_uv_opt[i * SUBSAMPLE(kWidth * 2, SUBSAMP_X) + j])); \
346 if (abs_diff > max_diff) { \
347 max_diff = abs_diff; \
348 } \
349 } \
350 } \
351 EXPECT_LE(max_diff, 1); \
352 free_aligned_buffer_page_end(dst_y_c); \
353 free_aligned_buffer_page_end(dst_uv_c); \
354 free_aligned_buffer_page_end(dst_y_opt); \
355 free_aligned_buffer_page_end(dst_uv_opt); \
356 free_aligned_buffer_page_end(src_y); \
357 free_aligned_buffer_page_end(src_u); \
358 free_aligned_buffer_page_end(src_v); \
359 }
360
361 #define TESTPLANARTOBP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
362 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \
363 TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
364 SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0) \
365 TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
366 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Unaligned, +, 1) \
367 TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
368 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0) \
369 TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
370 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0)
371
372 TESTPLANARTOBP(I420, 2, 2, NV12, 2, 2)
373 TESTPLANARTOBP(I420, 2, 2, NV21, 2, 2)
374
375 #define TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
376 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF, \
377 DOY) \
378 TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) { \
379 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
380 const int kHeight = benchmark_height_; \
381 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
382 align_buffer_page_end(src_uv, 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * \
383 SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + \
384 OFF); \
385 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
386 align_buffer_page_end(dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
387 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
388 align_buffer_page_end(dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
389 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
390 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
391 align_buffer_page_end(dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
392 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
393 align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
394 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
395 for (int i = 0; i < kHeight; ++i) \
396 for (int j = 0; j < kWidth; ++j) \
397 src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \
398 for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) { \
399 for (int j = 0; j < 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) { \
400 src_uv[(i * 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] = \
401 (fastrand() & 0xff); \
402 } \
403 } \
404 memset(dst_y_c, 1, kWidth* kHeight); \
405 memset(dst_u_c, 2, \
406 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
407 memset(dst_v_c, 3, \
408 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
409 memset(dst_y_opt, 101, kWidth* kHeight); \
410 memset(dst_u_opt, 102, \
411 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
412 memset(dst_v_opt, 103, \
413 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
414 MaskCpuFlags(disable_cpu_flags_); \
415 SRC_FMT_PLANAR##To##FMT_PLANAR( \
416 src_y + OFF, kWidth, src_uv + OFF, \
417 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X), DOY ? dst_y_c : NULL, kWidth, \
418 dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_c, \
419 SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
420 MaskCpuFlags(benchmark_cpu_info_); \
421 for (int i = 0; i < benchmark_iterations_; ++i) { \
422 SRC_FMT_PLANAR##To##FMT_PLANAR( \
423 src_y + OFF, kWidth, src_uv + OFF, \
424 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X), DOY ? dst_y_opt : NULL, \
425 kWidth, dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_opt, \
426 SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
427 } \
428 int max_diff = 0; \
429 if (DOY) { \
430 for (int i = 0; i < kHeight; ++i) { \
431 for (int j = 0; j < kWidth; ++j) { \
432 int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
433 static_cast<int>(dst_y_opt[i * kWidth + j])); \
434 if (abs_diff > max_diff) { \
435 max_diff = abs_diff; \
436 } \
437 } \
438 } \
439 EXPECT_LE(max_diff, 1); \
440 } \
441 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
442 for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
443 int abs_diff = abs( \
444 static_cast<int>(dst_u_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
445 static_cast<int>( \
446 dst_u_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
447 if (abs_diff > max_diff) { \
448 max_diff = abs_diff; \
449 } \
450 } \
451 } \
452 EXPECT_LE(max_diff, 1); \
453 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
454 for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
455 int abs_diff = abs( \
456 static_cast<int>(dst_v_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
457 static_cast<int>( \
458 dst_v_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
459 if (abs_diff > max_diff) { \
460 max_diff = abs_diff; \
461 } \
462 } \
463 } \
464 EXPECT_LE(max_diff, 1); \
465 free_aligned_buffer_page_end(dst_y_c); \
466 free_aligned_buffer_page_end(dst_u_c); \
467 free_aligned_buffer_page_end(dst_v_c); \
468 free_aligned_buffer_page_end(dst_y_opt); \
469 free_aligned_buffer_page_end(dst_u_opt); \
470 free_aligned_buffer_page_end(dst_v_opt); \
471 free_aligned_buffer_page_end(src_y); \
472 free_aligned_buffer_page_end(src_uv); \
473 }
474
475 #define TESTBIPLANARTOP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
476 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \
477 TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
478 SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0, 1) \
479 TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
480 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Unaligned, +, 1, \
481 1) \
482 TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
483 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0, 1) \
484 TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
485 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0, 1) \
486 TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
487 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _NullY, +, 0, 0)
488
489 TESTBIPLANARTOP(NV12, 2, 2, I420, 2, 2)
490 TESTBIPLANARTOP(NV21, 2, 2, I420, 2, 2)
491
492 #define ALIGNINT(V, ALIGN) (((V) + (ALIGN)-1) / (ALIGN) * (ALIGN))
493
494 #define TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
495 YALIGN, W1280, DIFF, N, NEG, OFF, FMT_C, BPP_C) \
496 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) { \
497 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
498 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
499 const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN); \
500 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
501 const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
502 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
503 align_buffer_page_end(src_u, kSizeUV + OFF); \
504 align_buffer_page_end(src_v, kSizeUV + OFF); \
505 align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF); \
506 align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF); \
507 for (int i = 0; i < kWidth * kHeight; ++i) { \
508 src_y[i + OFF] = (fastrand() & 0xff); \
509 } \
510 for (int i = 0; i < kSizeUV; ++i) { \
511 src_u[i + OFF] = (fastrand() & 0xff); \
512 src_v[i + OFF] = (fastrand() & 0xff); \
513 } \
514 memset(dst_argb_c + OFF, 1, kStrideB * kHeight); \
515 memset(dst_argb_opt + OFF, 101, kStrideB * kHeight); \
516 MaskCpuFlags(disable_cpu_flags_); \
517 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
518 src_v + OFF, kStrideUV, dst_argb_c + OFF, kStrideB, \
519 kWidth, NEG kHeight); \
520 MaskCpuFlags(benchmark_cpu_info_); \
521 for (int i = 0; i < benchmark_iterations_; ++i) { \
522 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
523 src_v + OFF, kStrideUV, dst_argb_opt + OFF, \
524 kStrideB, kWidth, NEG kHeight); \
525 } \
526 int max_diff = 0; \
527 /* Convert to ARGB so 565 is expanded to bytes that can be compared. */ \
528 align_buffer_page_end(dst_argb32_c, kWidth* BPP_C* kHeight); \
529 align_buffer_page_end(dst_argb32_opt, kWidth* BPP_C* kHeight); \
530 memset(dst_argb32_c, 2, kWidth* BPP_C* kHeight); \
531 memset(dst_argb32_opt, 102, kWidth* BPP_C* kHeight); \
532 FMT_B##To##FMT_C(dst_argb_c + OFF, kStrideB, dst_argb32_c, kWidth * BPP_C, \
533 kWidth, kHeight); \
534 FMT_B##To##FMT_C(dst_argb_opt + OFF, kStrideB, dst_argb32_opt, \
535 kWidth * BPP_C, kWidth, kHeight); \
536 for (int i = 0; i < kWidth * BPP_C * kHeight; ++i) { \
537 int abs_diff = abs(static_cast<int>(dst_argb32_c[i]) - \
538 static_cast<int>(dst_argb32_opt[i])); \
539 if (abs_diff > max_diff) { \
540 max_diff = abs_diff; \
541 } \
542 } \
543 EXPECT_LE(max_diff, DIFF); \
544 free_aligned_buffer_page_end(src_y); \
545 free_aligned_buffer_page_end(src_u); \
546 free_aligned_buffer_page_end(src_v); \
547 free_aligned_buffer_page_end(dst_argb_c); \
548 free_aligned_buffer_page_end(dst_argb_opt); \
549 free_aligned_buffer_page_end(dst_argb32_c); \
550 free_aligned_buffer_page_end(dst_argb32_opt); \
551 }
552
553 #define TESTPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
554 YALIGN, DIFF, FMT_C, BPP_C) \
555 TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
556 YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, FMT_C, BPP_C) \
557 TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
558 YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, FMT_C, \
559 BPP_C) \
560 TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
561 YALIGN, benchmark_width_, DIFF, _Invert, -, 0, FMT_C, BPP_C) \
562 TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
563 YALIGN, benchmark_width_, DIFF, _Opt, +, 0, FMT_C, BPP_C)
564
565 TESTPLANARTOB(I420, 2, 2, ARGB, 4, 4, 1, 2, ARGB, 4)
566 TESTPLANARTOB(J420, 2, 2, ARGB, 4, 4, 1, 2, ARGB, 4)
567 TESTPLANARTOB(J420, 2, 2, ABGR, 4, 4, 1, 2, ARGB, 4)
568 TESTPLANARTOB(H420, 2, 2, ARGB, 4, 4, 1, 2, ARGB, 4)
569 TESTPLANARTOB(H420, 2, 2, ABGR, 4, 4, 1, 2, ARGB, 4)
570 TESTPLANARTOB(I420, 2, 2, BGRA, 4, 4, 1, 2, ARGB, 4)
571 TESTPLANARTOB(I420, 2, 2, ABGR, 4, 4, 1, 2, ARGB, 4)
572 TESTPLANARTOB(I420, 2, 2, RGBA, 4, 4, 1, 2, ARGB, 4)
573 TESTPLANARTOB(I420, 2, 2, RAW, 3, 3, 1, 2, ARGB, 4)
574 TESTPLANARTOB(I420, 2, 2, RGB24, 3, 3, 1, 2, ARGB, 4)
575 TESTPLANARTOB(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4)
576 TESTPLANARTOB(I420, 2, 2, ARGB1555, 2, 2, 1, 9, ARGB, 4)
577 TESTPLANARTOB(I420, 2, 2, ARGB4444, 2, 2, 1, 17, ARGB, 4)
578 TESTPLANARTOB(I422, 2, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
579 TESTPLANARTOB(J422, 2, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
580 TESTPLANARTOB(J422, 2, 1, ABGR, 4, 4, 1, 2, ARGB, 4)
581 TESTPLANARTOB(H422, 2, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
582 TESTPLANARTOB(H422, 2, 1, ABGR, 4, 4, 1, 2, ARGB, 4)
583 TESTPLANARTOB(I422, 2, 1, BGRA, 4, 4, 1, 2, ARGB, 4)
584 TESTPLANARTOB(I422, 2, 1, ABGR, 4, 4, 1, 2, ARGB, 4)
585 TESTPLANARTOB(I422, 2, 1, RGBA, 4, 4, 1, 2, ARGB, 4)
586 TESTPLANARTOB(I444, 1, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
587 TESTPLANARTOB(J444, 1, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
588 TESTPLANARTOB(I444, 1, 1, ABGR, 4, 4, 1, 2, ARGB, 4)
589 TESTPLANARTOB(I420, 2, 2, YUY2, 2, 4, 1, 1, ARGB, 4)
590 TESTPLANARTOB(I420, 2, 2, UYVY, 2, 4, 1, 1, ARGB, 4)
591 TESTPLANARTOB(I422, 2, 1, YUY2, 2, 4, 1, 0, ARGB, 4)
592 TESTPLANARTOB(I422, 2, 1, UYVY, 2, 4, 1, 0, ARGB, 4)
593 TESTPLANARTOB(I420, 2, 2, I400, 1, 1, 1, 0, ARGB, 4)
594 TESTPLANARTOB(J420, 2, 2, J400, 1, 1, 1, 0, ARGB, 4)
595
596 #define TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
597 YALIGN, W1280, DIFF, N, NEG, OFF, ATTEN) \
598 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) { \
599 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
600 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
601 const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN); \
602 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
603 const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
604 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
605 align_buffer_page_end(src_u, kSizeUV + OFF); \
606 align_buffer_page_end(src_v, kSizeUV + OFF); \
607 align_buffer_page_end(src_a, kWidth* kHeight + OFF); \
608 align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF); \
609 align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF); \
610 for (int i = 0; i < kWidth * kHeight; ++i) { \
611 src_y[i + OFF] = (fastrand() & 0xff); \
612 src_a[i + OFF] = (fastrand() & 0xff); \
613 } \
614 for (int i = 0; i < kSizeUV; ++i) { \
615 src_u[i + OFF] = (fastrand() & 0xff); \
616 src_v[i + OFF] = (fastrand() & 0xff); \
617 } \
618 memset(dst_argb_c + OFF, 1, kStrideB * kHeight); \
619 memset(dst_argb_opt + OFF, 101, kStrideB * kHeight); \
620 MaskCpuFlags(disable_cpu_flags_); \
621 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
622 src_v + OFF, kStrideUV, src_a + OFF, kWidth, \
623 dst_argb_c + OFF, kStrideB, kWidth, NEG kHeight, \
624 ATTEN); \
625 MaskCpuFlags(benchmark_cpu_info_); \
626 for (int i = 0; i < benchmark_iterations_; ++i) { \
627 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
628 src_v + OFF, kStrideUV, src_a + OFF, kWidth, \
629 dst_argb_opt + OFF, kStrideB, kWidth, NEG kHeight, \
630 ATTEN); \
631 } \
632 int max_diff = 0; \
633 for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) { \
634 int abs_diff = abs(static_cast<int>(dst_argb_c[i + OFF]) - \
635 static_cast<int>(dst_argb_opt[i + OFF])); \
636 if (abs_diff > max_diff) { \
637 max_diff = abs_diff; \
638 } \
639 } \
640 EXPECT_LE(max_diff, DIFF); \
641 free_aligned_buffer_page_end(src_y); \
642 free_aligned_buffer_page_end(src_u); \
643 free_aligned_buffer_page_end(src_v); \
644 free_aligned_buffer_page_end(src_a); \
645 free_aligned_buffer_page_end(dst_argb_c); \
646 free_aligned_buffer_page_end(dst_argb_opt); \
647 }
648
649 #define TESTQPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
650 YALIGN, DIFF) \
651 TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
652 YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, 0) \
653 TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
654 YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, 0) \
655 TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
656 YALIGN, benchmark_width_, DIFF, _Invert, -, 0, 0) \
657 TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
658 YALIGN, benchmark_width_, DIFF, _Opt, +, 0, 0) \
659 TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
660 YALIGN, benchmark_width_, DIFF, _Premult, +, 0, 1)
661
662 TESTQPLANARTOB(I420Alpha, 2, 2, ARGB, 4, 4, 1, 2)
663 TESTQPLANARTOB(I420Alpha, 2, 2, ABGR, 4, 4, 1, 2)
664
665 #define TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
666 W1280, DIFF, N, NEG, OFF) \
667 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) { \
668 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
669 const int kHeight = benchmark_height_; \
670 const int kStrideB = kWidth * BPP_B; \
671 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
672 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
673 align_buffer_page_end(src_uv, \
674 kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y) * 2 + OFF); \
675 align_buffer_page_end(dst_argb_c, kStrideB* kHeight); \
676 align_buffer_page_end(dst_argb_opt, kStrideB* kHeight); \
677 for (int i = 0; i < kHeight; ++i) \
678 for (int j = 0; j < kWidth; ++j) \
679 src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \
680 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
681 for (int j = 0; j < kStrideUV * 2; ++j) { \
682 src_uv[i * kStrideUV * 2 + j + OFF] = (fastrand() & 0xff); \
683 } \
684 } \
685 memset(dst_argb_c, 1, kStrideB* kHeight); \
686 memset(dst_argb_opt, 101, kStrideB* kHeight); \
687 MaskCpuFlags(disable_cpu_flags_); \
688 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_uv + OFF, kStrideUV * 2, \
689 dst_argb_c, kWidth * BPP_B, kWidth, NEG kHeight); \
690 MaskCpuFlags(benchmark_cpu_info_); \
691 for (int i = 0; i < benchmark_iterations_; ++i) { \
692 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_uv + OFF, kStrideUV * 2, \
693 dst_argb_opt, kWidth * BPP_B, kWidth, \
694 NEG kHeight); \
695 } \
696 /* Convert to ARGB so 565 is expanded to bytes that can be compared. */ \
697 align_buffer_page_end(dst_argb32_c, kWidth * 4 * kHeight); \
698 align_buffer_page_end(dst_argb32_opt, kWidth * 4 * kHeight); \
699 memset(dst_argb32_c, 2, kWidth * 4 * kHeight); \
700 memset(dst_argb32_opt, 102, kWidth * 4 * kHeight); \
701 FMT_B##ToARGB(dst_argb_c, kStrideB, dst_argb32_c, kWidth * 4, kWidth, \
702 kHeight); \
703 FMT_B##ToARGB(dst_argb_opt, kStrideB, dst_argb32_opt, kWidth * 4, kWidth, \
704 kHeight); \
705 int max_diff = 0; \
706 for (int i = 0; i < kHeight; ++i) { \
707 for (int j = 0; j < kWidth * 4; ++j) { \
708 int abs_diff = \
709 abs(static_cast<int>(dst_argb32_c[i * kWidth * 4 + j]) - \
710 static_cast<int>(dst_argb32_opt[i * kWidth * 4 + j])); \
711 if (abs_diff > max_diff) { \
712 max_diff = abs_diff; \
713 } \
714 } \
715 } \
716 EXPECT_LE(max_diff, DIFF); \
717 free_aligned_buffer_page_end(src_y); \
718 free_aligned_buffer_page_end(src_uv); \
719 free_aligned_buffer_page_end(dst_argb_c); \
720 free_aligned_buffer_page_end(dst_argb_opt); \
721 free_aligned_buffer_page_end(dst_argb32_c); \
722 free_aligned_buffer_page_end(dst_argb32_opt); \
723 }
724
725 #define TESTBIPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, DIFF) \
726 TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
727 benchmark_width_ - 4, DIFF, _Any, +, 0) \
728 TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
729 benchmark_width_, DIFF, _Unaligned, +, 1) \
730 TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
731 benchmark_width_, DIFF, _Invert, -, 0) \
732 TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
733 benchmark_width_, DIFF, _Opt, +, 0)
734
735 TESTBIPLANARTOB(NV12, 2, 2, ARGB, 4, 2)
736 TESTBIPLANARTOB(NV21, 2, 2, ARGB, 4, 2)
737 TESTBIPLANARTOB(NV12, 2, 2, RGB565, 2, 9)
738
739 #ifdef DO_THREE_PLANES
740 // Do 3 allocations for yuv. conventional but slower.
741 #define TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
742 W1280, DIFF, N, NEG, OFF) \
743 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) { \
744 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
745 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
746 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
747 const int kStride = (kStrideUV * SUBSAMP_X * 8 * BPP_A + 7) / 8; \
748 align_buffer_page_end(src_argb, kStride* kHeight + OFF); \
749 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
750 align_buffer_page_end(dst_u_c, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
751 align_buffer_page_end(dst_v_c, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
752 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
753 align_buffer_page_end(dst_u_opt, \
754 kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
755 align_buffer_page_end(dst_v_opt, \
756 kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
757 memset(dst_y_c, 1, kWidth* kHeight); \
758 memset(dst_u_c, 2, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
759 memset(dst_v_c, 3, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
760 memset(dst_y_opt, 101, kWidth* kHeight); \
761 memset(dst_u_opt, 102, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
762 memset(dst_v_opt, 103, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
763 for (int i = 0; i < kHeight; ++i) \
764 for (int j = 0; j < kStride; ++j) \
765 src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff); \
766 MaskCpuFlags(disable_cpu_flags_); \
767 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_c, kWidth, dst_u_c, \
768 kStrideUV, dst_v_c, kStrideUV, kWidth, NEG kHeight); \
769 MaskCpuFlags(benchmark_cpu_info_); \
770 for (int i = 0; i < benchmark_iterations_; ++i) { \
771 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_opt, kWidth, \
772 dst_u_opt, kStrideUV, dst_v_opt, kStrideUV, \
773 kWidth, NEG kHeight); \
774 } \
775 for (int i = 0; i < kHeight; ++i) { \
776 for (int j = 0; j < kWidth; ++j) { \
777 EXPECT_NEAR(static_cast<int>(dst_y_c[i * kWidth + j]), \
778 static_cast<int>(dst_y_opt[i * kWidth + j]), DIFF); \
779 } \
780 } \
781 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
782 for (int j = 0; j < kStrideUV; ++j) { \
783 EXPECT_NEAR(static_cast<int>(dst_u_c[i * kStrideUV + j]), \
784 static_cast<int>(dst_u_opt[i * kStrideUV + j]), DIFF); \
785 } \
786 } \
787 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
788 for (int j = 0; j < kStrideUV; ++j) { \
789 EXPECT_NEAR(static_cast<int>(dst_v_c[i * kStrideUV + j]), \
790 static_cast<int>(dst_v_opt[i * kStrideUV + j]), DIFF); \
791 } \
792 } \
793 free_aligned_buffer_page_end(dst_y_c); \
794 free_aligned_buffer_page_end(dst_u_c); \
795 free_aligned_buffer_page_end(dst_v_c); \
796 free_aligned_buffer_page_end(dst_y_opt); \
797 free_aligned_buffer_page_end(dst_u_opt); \
798 free_aligned_buffer_page_end(dst_v_opt); \
799 free_aligned_buffer_page_end(src_argb); \
800 }
801 #else
802 #define TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
803 W1280, DIFF, N, NEG, OFF) \
804 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) { \
805 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
806 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
807 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
808 const int kStride = (kStrideUV * SUBSAMP_X * 8 * BPP_A + 7) / 8; \
809 align_buffer_page_end(src_argb, kStride* kHeight + OFF); \
810 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
811 align_buffer_page_end(dst_uv_c, \
812 kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
813 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
814 align_buffer_page_end(dst_uv_opt, \
815 kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
816 memset(dst_y_c, 1, kWidth* kHeight); \
817 memset(dst_uv_c, 2, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
818 memset(dst_y_opt, 101, kWidth* kHeight); \
819 memset(dst_uv_opt, 102, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
820 for (int i = 0; i < kHeight; ++i) \
821 for (int j = 0; j < kStride; ++j) \
822 src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff); \
823 MaskCpuFlags(disable_cpu_flags_); \
824 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_c, kWidth, dst_uv_c, \
825 kStrideUV * 2, dst_uv_c + kStrideUV, kStrideUV * 2, \
826 kWidth, NEG kHeight); \
827 MaskCpuFlags(benchmark_cpu_info_); \
828 for (int i = 0; i < benchmark_iterations_; ++i) { \
829 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_opt, kWidth, \
830 dst_uv_opt, kStrideUV * 2, dst_uv_opt + kStrideUV, \
831 kStrideUV * 2, kWidth, NEG kHeight); \
832 } \
833 for (int i = 0; i < kHeight; ++i) { \
834 for (int j = 0; j < kWidth; ++j) { \
835 EXPECT_NEAR(static_cast<int>(dst_y_c[i * kWidth + j]), \
836 static_cast<int>(dst_y_opt[i * kWidth + j]), DIFF); \
837 } \
838 } \
839 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y) * 2; ++i) { \
840 for (int j = 0; j < kStrideUV; ++j) { \
841 EXPECT_NEAR(static_cast<int>(dst_uv_c[i * kStrideUV + j]), \
842 static_cast<int>(dst_uv_opt[i * kStrideUV + j]), DIFF); \
843 } \
844 } \
845 free_aligned_buffer_page_end(dst_y_c); \
846 free_aligned_buffer_page_end(dst_uv_c); \
847 free_aligned_buffer_page_end(dst_y_opt); \
848 free_aligned_buffer_page_end(dst_uv_opt); \
849 free_aligned_buffer_page_end(src_argb); \
850 }
851 #endif
852
853 #define TESTATOPLANAR(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
854 DIFF) \
855 TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
856 benchmark_width_ - 4, DIFF, _Any, +, 0) \
857 TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
858 benchmark_width_, DIFF, _Unaligned, +, 1) \
859 TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
860 benchmark_width_, DIFF, _Invert, -, 0) \
861 TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
862 benchmark_width_, DIFF, _Opt, +, 0)
863
864 TESTATOPLANAR(ARGB, 4, 1, I420, 2, 2, 4)
865 #if defined(__arm__) || defined(__aarch64__)
866 // arm version subsamples by summing 4 pixels then multiplying by matrix with
867 // 4x smaller coefficients which are rounded to nearest integer.
868 TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2, 4)
869 TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1, 4)
870 #else
871 TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2, 0)
872 TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1, 0)
873 #endif
874 TESTATOPLANAR(BGRA, 4, 1, I420, 2, 2, 4)
875 TESTATOPLANAR(ABGR, 4, 1, I420, 2, 2, 4)
876 TESTATOPLANAR(RGBA, 4, 1, I420, 2, 2, 4)
877 TESTATOPLANAR(RAW, 3, 1, I420, 2, 2, 4)
878 TESTATOPLANAR(RGB24, 3, 1, I420, 2, 2, 4)
879 TESTATOPLANAR(RGB565, 2, 1, I420, 2, 2, 5)
880 // TODO(fbarchard): Make 1555 neon work same as C code, reduce to diff 9.
881 TESTATOPLANAR(ARGB1555, 2, 1, I420, 2, 2, 15)
882 TESTATOPLANAR(ARGB4444, 2, 1, I420, 2, 2, 17)
883 TESTATOPLANAR(ARGB, 4, 1, I422, 2, 1, 2)
884 TESTATOPLANAR(ARGB, 4, 1, I444, 1, 1, 2)
885 TESTATOPLANAR(YUY2, 2, 1, I420, 2, 2, 2)
886 TESTATOPLANAR(UYVY, 2, 1, I420, 2, 2, 2)
887 TESTATOPLANAR(YUY2, 2, 1, I422, 2, 1, 2)
888 TESTATOPLANAR(UYVY, 2, 1, I422, 2, 1, 2)
889 TESTATOPLANAR(I400, 1, 1, I420, 2, 2, 2)
890 TESTATOPLANAR(J400, 1, 1, J420, 2, 2, 2)
891
892 #define TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, \
893 SUBSAMP_Y, W1280, N, NEG, OFF) \
894 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) { \
895 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
896 const int kHeight = benchmark_height_; \
897 const int kStride = SUBSAMPLE(kWidth, SUB_A) * BPP_A; \
898 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
899 align_buffer_page_end(src_argb, kStride* kHeight + OFF); \
900 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
901 align_buffer_page_end(dst_uv_c, \
902 kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
903 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
904 align_buffer_page_end(dst_uv_opt, \
905 kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
906 for (int i = 0; i < kHeight; ++i) \
907 for (int j = 0; j < kStride; ++j) \
908 src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff); \
909 memset(dst_y_c, 1, kWidth* kHeight); \
910 memset(dst_uv_c, 2, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
911 memset(dst_y_opt, 101, kWidth* kHeight); \
912 memset(dst_uv_opt, 102, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
913 MaskCpuFlags(disable_cpu_flags_); \
914 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_c, kWidth, dst_uv_c, \
915 kStrideUV * 2, kWidth, NEG kHeight); \
916 MaskCpuFlags(benchmark_cpu_info_); \
917 for (int i = 0; i < benchmark_iterations_; ++i) { \
918 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_opt, kWidth, \
919 dst_uv_opt, kStrideUV * 2, kWidth, NEG kHeight); \
920 } \
921 int max_diff = 0; \
922 for (int i = 0; i < kHeight; ++i) { \
923 for (int j = 0; j < kWidth; ++j) { \
924 int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
925 static_cast<int>(dst_y_opt[i * kWidth + j])); \
926 if (abs_diff > max_diff) { \
927 max_diff = abs_diff; \
928 } \
929 } \
930 } \
931 EXPECT_LE(max_diff, 4); \
932 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
933 for (int j = 0; j < kStrideUV * 2; ++j) { \
934 int abs_diff = \
935 abs(static_cast<int>(dst_uv_c[i * kStrideUV * 2 + j]) - \
936 static_cast<int>(dst_uv_opt[i * kStrideUV * 2 + j])); \
937 if (abs_diff > max_diff) { \
938 max_diff = abs_diff; \
939 } \
940 } \
941 } \
942 EXPECT_LE(max_diff, 4); \
943 free_aligned_buffer_page_end(dst_y_c); \
944 free_aligned_buffer_page_end(dst_uv_c); \
945 free_aligned_buffer_page_end(dst_y_opt); \
946 free_aligned_buffer_page_end(dst_uv_opt); \
947 free_aligned_buffer_page_end(src_argb); \
948 }
949
950 #define TESTATOBIPLANAR(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \
951 TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
952 benchmark_width_ - 4, _Any, +, 0) \
953 TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
954 benchmark_width_, _Unaligned, +, 1) \
955 TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
956 benchmark_width_, _Invert, -, 0) \
957 TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
958 benchmark_width_, _Opt, +, 0)
959
960 TESTATOBIPLANAR(ARGB, 1, 4, NV12, 2, 2)
961 TESTATOBIPLANAR(ARGB, 1, 4, NV21, 2, 2)
962 TESTATOBIPLANAR(YUY2, 2, 4, NV12, 2, 2)
963 TESTATOBIPLANAR(UYVY, 2, 4, NV12, 2, 2)
964
965 #define TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
966 HEIGHT_B, W1280, DIFF, N, NEG, OFF) \
967 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##N) { \
968 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
969 const int kHeight = benchmark_height_; \
970 const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
971 const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B; \
972 const int kStrideA = \
973 (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
974 const int kStrideB = \
975 (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B; \
976 align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF); \
977 align_buffer_page_end(dst_argb_c, kStrideB* kHeightB); \
978 align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB); \
979 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
980 src_argb[i + OFF] = (fastrand() & 0xff); \
981 } \
982 memset(dst_argb_c, 1, kStrideB* kHeightB); \
983 memset(dst_argb_opt, 101, kStrideB* kHeightB); \
984 MaskCpuFlags(disable_cpu_flags_); \
985 FMT_A##To##FMT_B(src_argb + OFF, kStrideA, dst_argb_c, kStrideB, kWidth, \
986 NEG kHeight); \
987 MaskCpuFlags(benchmark_cpu_info_); \
988 for (int i = 0; i < benchmark_iterations_; ++i) { \
989 FMT_A##To##FMT_B(src_argb + OFF, kStrideA, dst_argb_opt, kStrideB, \
990 kWidth, NEG kHeight); \
991 } \
992 int max_diff = 0; \
993 for (int i = 0; i < kStrideB * kHeightB; ++i) { \
994 int abs_diff = abs(static_cast<int>(dst_argb_c[i]) - \
995 static_cast<int>(dst_argb_opt[i])); \
996 if (abs_diff > max_diff) { \
997 max_diff = abs_diff; \
998 } \
999 } \
1000 EXPECT_LE(max_diff, DIFF); \
1001 free_aligned_buffer_page_end(src_argb); \
1002 free_aligned_buffer_page_end(dst_argb_c); \
1003 free_aligned_buffer_page_end(dst_argb_opt); \
1004 }
1005
1006 #define TESTATOBRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, \
1007 STRIDE_B, HEIGHT_B, DIFF) \
1008 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##_Random) { \
1009 for (int times = 0; times < benchmark_iterations_; ++times) { \
1010 const int kWidth = (fastrand() & 63) + 1; \
1011 const int kHeight = (fastrand() & 31) + 1; \
1012 const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
1013 const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B; \
1014 const int kStrideA = \
1015 (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
1016 const int kStrideB = \
1017 (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B; \
1018 align_buffer_page_end(src_argb, kStrideA* kHeightA); \
1019 align_buffer_page_end(dst_argb_c, kStrideB* kHeightB); \
1020 align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB); \
1021 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
1022 src_argb[i] = (fastrand() & 0xff); \
1023 } \
1024 memset(dst_argb_c, 123, kStrideB* kHeightB); \
1025 memset(dst_argb_opt, 123, kStrideB* kHeightB); \
1026 MaskCpuFlags(disable_cpu_flags_); \
1027 FMT_A##To##FMT_B(src_argb, kStrideA, dst_argb_c, kStrideB, kWidth, \
1028 kHeight); \
1029 MaskCpuFlags(benchmark_cpu_info_); \
1030 FMT_A##To##FMT_B(src_argb, kStrideA, dst_argb_opt, kStrideB, kWidth, \
1031 kHeight); \
1032 int max_diff = 0; \
1033 for (int i = 0; i < kStrideB * kHeightB; ++i) { \
1034 int abs_diff = abs(static_cast<int>(dst_argb_c[i]) - \
1035 static_cast<int>(dst_argb_opt[i])); \
1036 if (abs_diff > max_diff) { \
1037 max_diff = abs_diff; \
1038 } \
1039 } \
1040 EXPECT_LE(max_diff, DIFF); \
1041 free_aligned_buffer_page_end(src_argb); \
1042 free_aligned_buffer_page_end(dst_argb_c); \
1043 free_aligned_buffer_page_end(dst_argb_opt); \
1044 } \
1045 }
1046
1047 #define TESTATOB(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1048 HEIGHT_B, DIFF) \
1049 TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1050 HEIGHT_B, benchmark_width_ - 4, DIFF, _Any, +, 0) \
1051 TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1052 HEIGHT_B, benchmark_width_, DIFF, _Unaligned, +, 1) \
1053 TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1054 HEIGHT_B, benchmark_width_, DIFF, _Invert, -, 0) \
1055 TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1056 HEIGHT_B, benchmark_width_, DIFF, _Opt, +, 0) \
1057 TESTATOBRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1058 HEIGHT_B, DIFF)
1059
1060 TESTATOB(ARGB, 4, 4, 1, ARGB, 4, 4, 1, 0)
1061 TESTATOB(ARGB, 4, 4, 1, BGRA, 4, 4, 1, 0)
1062 TESTATOB(ARGB, 4, 4, 1, ABGR, 4, 4, 1, 0)
1063 TESTATOB(ARGB, 4, 4, 1, RGBA, 4, 4, 1, 0)
1064 TESTATOB(ARGB, 4, 4, 1, RAW, 3, 3, 1, 0)
1065 TESTATOB(ARGB, 4, 4, 1, RGB24, 3, 3, 1, 0)
1066 TESTATOB(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0)
1067 TESTATOB(ARGB, 4, 4, 1, ARGB1555, 2, 2, 1, 0)
1068 TESTATOB(ARGB, 4, 4, 1, ARGB4444, 2, 2, 1, 0)
1069 TESTATOB(ARGB, 4, 4, 1, YUY2, 2, 4, 1, 4)
1070 TESTATOB(ARGB, 4, 4, 1, UYVY, 2, 4, 1, 4)
1071 TESTATOB(ARGB, 4, 4, 1, I400, 1, 1, 1, 2)
1072 TESTATOB(ARGB, 4, 4, 1, J400, 1, 1, 1, 2)
1073 TESTATOB(BGRA, 4, 4, 1, ARGB, 4, 4, 1, 0)
1074 TESTATOB(ABGR, 4, 4, 1, ARGB, 4, 4, 1, 0)
1075 TESTATOB(RGBA, 4, 4, 1, ARGB, 4, 4, 1, 0)
1076 TESTATOB(RAW, 3, 3, 1, ARGB, 4, 4, 1, 0)
1077 TESTATOB(RAW, 3, 3, 1, RGB24, 3, 3, 1, 0)
1078 TESTATOB(RGB24, 3, 3, 1, ARGB, 4, 4, 1, 0)
1079 TESTATOB(RGB565, 2, 2, 1, ARGB, 4, 4, 1, 0)
1080 TESTATOB(ARGB1555, 2, 2, 1, ARGB, 4, 4, 1, 0)
1081 TESTATOB(ARGB4444, 2, 2, 1, ARGB, 4, 4, 1, 0)
1082 TESTATOB(YUY2, 2, 4, 1, ARGB, 4, 4, 1, 4)
1083 TESTATOB(UYVY, 2, 4, 1, ARGB, 4, 4, 1, 4)
1084 TESTATOB(YUY2, 2, 4, 1, Y, 1, 1, 1, 0)
1085 TESTATOB(I400, 1, 1, 1, ARGB, 4, 4, 1, 0)
1086 TESTATOB(J400, 1, 1, 1, ARGB, 4, 4, 1, 0)
1087 TESTATOB(I400, 1, 1, 1, I400, 1, 1, 1, 0)
1088 TESTATOB(J400, 1, 1, 1, J400, 1, 1, 1, 0)
1089 TESTATOB(I400, 1, 1, 1, I400Mirror, 1, 1, 1, 0)
1090 TESTATOB(ARGB, 4, 4, 1, ARGBMirror, 4, 4, 1, 0)
1091
1092 #define TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1093 HEIGHT_B, W1280, DIFF, N, NEG, OFF) \
1094 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##Dither##N) { \
1095 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1096 const int kHeight = benchmark_height_; \
1097 const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
1098 const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B; \
1099 const int kStrideA = \
1100 (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
1101 const int kStrideB = \
1102 (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B; \
1103 align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF); \
1104 align_buffer_page_end(dst_argb_c, kStrideB* kHeightB); \
1105 align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB); \
1106 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
1107 src_argb[i + OFF] = (fastrand() & 0xff); \
1108 } \
1109 memset(dst_argb_c, 1, kStrideB* kHeightB); \
1110 memset(dst_argb_opt, 101, kStrideB* kHeightB); \
1111 MaskCpuFlags(disable_cpu_flags_); \
1112 FMT_A##To##FMT_B##Dither(src_argb + OFF, kStrideA, dst_argb_c, kStrideB, \
1113 NULL, kWidth, NEG kHeight); \
1114 MaskCpuFlags(benchmark_cpu_info_); \
1115 for (int i = 0; i < benchmark_iterations_; ++i) { \
1116 FMT_A##To##FMT_B##Dither(src_argb + OFF, kStrideA, dst_argb_opt, \
1117 kStrideB, NULL, kWidth, NEG kHeight); \
1118 } \
1119 int max_diff = 0; \
1120 for (int i = 0; i < kStrideB * kHeightB; ++i) { \
1121 int abs_diff = abs(static_cast<int>(dst_argb_c[i]) - \
1122 static_cast<int>(dst_argb_opt[i])); \
1123 if (abs_diff > max_diff) { \
1124 max_diff = abs_diff; \
1125 } \
1126 } \
1127 EXPECT_LE(max_diff, DIFF); \
1128 free_aligned_buffer_page_end(src_argb); \
1129 free_aligned_buffer_page_end(dst_argb_c); \
1130 free_aligned_buffer_page_end(dst_argb_opt); \
1131 }
1132
1133 #define TESTATOBDRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, \
1134 STRIDE_B, HEIGHT_B, DIFF) \
1135 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##Dither_Random) { \
1136 for (int times = 0; times < benchmark_iterations_; ++times) { \
1137 const int kWidth = (fastrand() & 63) + 1; \
1138 const int kHeight = (fastrand() & 31) + 1; \
1139 const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
1140 const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B; \
1141 const int kStrideA = \
1142 (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
1143 const int kStrideB = \
1144 (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B; \
1145 align_buffer_page_end(src_argb, kStrideA* kHeightA); \
1146 align_buffer_page_end(dst_argb_c, kStrideB* kHeightB); \
1147 align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB); \
1148 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
1149 src_argb[i] = (fastrand() & 0xff); \
1150 } \
1151 memset(dst_argb_c, 123, kStrideB* kHeightB); \
1152 memset(dst_argb_opt, 123, kStrideB* kHeightB); \
1153 MaskCpuFlags(disable_cpu_flags_); \
1154 FMT_A##To##FMT_B##Dither(src_argb, kStrideA, dst_argb_c, kStrideB, NULL, \
1155 kWidth, kHeight); \
1156 MaskCpuFlags(benchmark_cpu_info_); \
1157 FMT_A##To##FMT_B##Dither(src_argb, kStrideA, dst_argb_opt, kStrideB, \
1158 NULL, kWidth, kHeight); \
1159 int max_diff = 0; \
1160 for (int i = 0; i < kStrideB * kHeightB; ++i) { \
1161 int abs_diff = abs(static_cast<int>(dst_argb_c[i]) - \
1162 static_cast<int>(dst_argb_opt[i])); \
1163 if (abs_diff > max_diff) { \
1164 max_diff = abs_diff; \
1165 } \
1166 } \
1167 EXPECT_LE(max_diff, DIFF); \
1168 free_aligned_buffer_page_end(src_argb); \
1169 free_aligned_buffer_page_end(dst_argb_c); \
1170 free_aligned_buffer_page_end(dst_argb_opt); \
1171 } \
1172 }
1173
1174 #define TESTATOBD(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1175 HEIGHT_B, DIFF) \
1176 TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1177 HEIGHT_B, benchmark_width_ - 4, DIFF, _Any, +, 0) \
1178 TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1179 HEIGHT_B, benchmark_width_, DIFF, _Unaligned, +, 1) \
1180 TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1181 HEIGHT_B, benchmark_width_, DIFF, _Invert, -, 0) \
1182 TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1183 HEIGHT_B, benchmark_width_, DIFF, _Opt, +, 0) \
1184 TESTATOBDRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1185 HEIGHT_B, DIFF)
1186
1187 TESTATOBD(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0)
1188
1189 #define TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, W1280, N, NEG, OFF) \
1190 TEST_F(LibYUVConvertTest, FMT_ATOB##_Symetric##N) { \
1191 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1192 const int kHeight = benchmark_height_; \
1193 const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
1194 const int kStrideA = \
1195 (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
1196 align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF); \
1197 align_buffer_page_end(dst_argb_c, kStrideA* kHeightA); \
1198 align_buffer_page_end(dst_argb_opt, kStrideA* kHeightA); \
1199 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
1200 src_argb[i + OFF] = (fastrand() & 0xff); \
1201 } \
1202 memset(dst_argb_c, 1, kStrideA* kHeightA); \
1203 memset(dst_argb_opt, 101, kStrideA* kHeightA); \
1204 MaskCpuFlags(disable_cpu_flags_); \
1205 FMT_ATOB(src_argb + OFF, kStrideA, dst_argb_c, kStrideA, kWidth, \
1206 NEG kHeight); \
1207 MaskCpuFlags(benchmark_cpu_info_); \
1208 for (int i = 0; i < benchmark_iterations_; ++i) { \
1209 FMT_ATOB(src_argb + OFF, kStrideA, dst_argb_opt, kStrideA, kWidth, \
1210 NEG kHeight); \
1211 } \
1212 MaskCpuFlags(disable_cpu_flags_); \
1213 FMT_ATOB(dst_argb_c, kStrideA, dst_argb_c, kStrideA, kWidth, NEG kHeight); \
1214 MaskCpuFlags(benchmark_cpu_info_); \
1215 FMT_ATOB(dst_argb_opt, kStrideA, dst_argb_opt, kStrideA, kWidth, \
1216 NEG kHeight); \
1217 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
1218 EXPECT_EQ(src_argb[i + OFF], dst_argb_opt[i]); \
1219 EXPECT_EQ(dst_argb_c[i], dst_argb_opt[i]); \
1220 } \
1221 free_aligned_buffer_page_end(src_argb); \
1222 free_aligned_buffer_page_end(dst_argb_c); \
1223 free_aligned_buffer_page_end(dst_argb_opt); \
1224 }
1225
1226 #define TESTSYM(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A) \
1227 TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_ - 4, _Any, +, \
1228 0) \
1229 TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_, _Unaligned, \
1230 +, 1) \
1231 TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_, _Opt, +, 0)
1232
1233 TESTSYM(ARGBToARGB, 4, 4, 1)
1234 TESTSYM(ARGBToBGRA, 4, 4, 1)
1235 TESTSYM(ARGBToABGR, 4, 4, 1)
1236 TESTSYM(BGRAToARGB, 4, 4, 1)
1237 TESTSYM(ABGRToARGB, 4, 4, 1)
1238
TEST_F(LibYUVConvertTest,Test565)1239 TEST_F(LibYUVConvertTest, Test565) {
1240 SIMD_ALIGNED(uint8 orig_pixels[256][4]);
1241 SIMD_ALIGNED(uint8 pixels565[256][2]);
1242
1243 for (int i = 0; i < 256; ++i) {
1244 for (int j = 0; j < 4; ++j) {
1245 orig_pixels[i][j] = i;
1246 }
1247 }
1248 ARGBToRGB565(&orig_pixels[0][0], 0, &pixels565[0][0], 0, 256, 1);
1249 uint32 checksum = HashDjb2(&pixels565[0][0], sizeof(pixels565), 5381);
1250 EXPECT_EQ(610919429u, checksum);
1251 }
1252
1253 #ifdef HAVE_JPEG
TEST_F(LibYUVConvertTest,ValidateJpeg)1254 TEST_F(LibYUVConvertTest, ValidateJpeg) {
1255 const int kOff = 10;
1256 const int kMinJpeg = 64;
1257 const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1258 ? benchmark_width_ * benchmark_height_
1259 : kMinJpeg;
1260 const int kSize = kImageSize + kOff;
1261 align_buffer_page_end(orig_pixels, kSize);
1262
1263 // No SOI or EOI. Expect fail.
1264 memset(orig_pixels, 0, kSize);
1265 EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1266
1267 // Test special value that matches marker start.
1268 memset(orig_pixels, 0xff, kSize);
1269 EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1270
1271 // EOI, SOI. Expect pass.
1272 orig_pixels[0] = 0xff;
1273 orig_pixels[1] = 0xd8; // SOI.
1274 orig_pixels[kSize - kOff + 0] = 0xff;
1275 orig_pixels[kSize - kOff + 1] = 0xd9; // EOI.
1276 for (int times = 0; times < benchmark_iterations_; ++times) {
1277 EXPECT_TRUE(ValidateJpeg(orig_pixels, kSize));
1278 }
1279 free_aligned_buffer_page_end(orig_pixels);
1280 }
1281
TEST_F(LibYUVConvertTest,ValidateJpegLarge)1282 TEST_F(LibYUVConvertTest, ValidateJpegLarge) {
1283 const int kOff = 10;
1284 const int kMinJpeg = 64;
1285 const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1286 ? benchmark_width_ * benchmark_height_
1287 : kMinJpeg;
1288 const int kSize = kImageSize + kOff;
1289 const int kMultiple = 10;
1290 const int kBufSize = kImageSize * kMultiple + kOff;
1291 align_buffer_page_end(orig_pixels, kBufSize);
1292
1293 // No SOI or EOI. Expect fail.
1294 memset(orig_pixels, 0, kBufSize);
1295 EXPECT_FALSE(ValidateJpeg(orig_pixels, kBufSize));
1296
1297 // EOI, SOI. Expect pass.
1298 orig_pixels[0] = 0xff;
1299 orig_pixels[1] = 0xd8; // SOI.
1300 orig_pixels[kSize - kOff + 0] = 0xff;
1301 orig_pixels[kSize - kOff + 1] = 0xd9; // EOI.
1302 for (int times = 0; times < benchmark_iterations_; ++times) {
1303 EXPECT_TRUE(ValidateJpeg(orig_pixels, kBufSize));
1304 }
1305 free_aligned_buffer_page_end(orig_pixels);
1306 }
1307
TEST_F(LibYUVConvertTest,InvalidateJpeg)1308 TEST_F(LibYUVConvertTest, InvalidateJpeg) {
1309 const int kOff = 10;
1310 const int kMinJpeg = 64;
1311 const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1312 ? benchmark_width_ * benchmark_height_
1313 : kMinJpeg;
1314 const int kSize = kImageSize + kOff;
1315 align_buffer_page_end(orig_pixels, kSize);
1316
1317 // NULL pointer. Expect fail.
1318 EXPECT_FALSE(ValidateJpeg(NULL, kSize));
1319
1320 // Negative size. Expect fail.
1321 EXPECT_FALSE(ValidateJpeg(orig_pixels, -1));
1322
1323 // Too large size. Expect fail.
1324 EXPECT_FALSE(ValidateJpeg(orig_pixels, 0xfb000000ull));
1325
1326 // No SOI or EOI. Expect fail.
1327 memset(orig_pixels, 0, kSize);
1328 EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1329
1330 // SOI but no EOI. Expect fail.
1331 orig_pixels[0] = 0xff;
1332 orig_pixels[1] = 0xd8; // SOI.
1333 for (int times = 0; times < benchmark_iterations_; ++times) {
1334 EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1335 }
1336
1337 // EOI but no SOI. Expect fail.
1338 orig_pixels[0] = 0;
1339 orig_pixels[1] = 0;
1340 orig_pixels[kSize - kOff + 0] = 0xff;
1341 orig_pixels[kSize - kOff + 1] = 0xd9; // EOI.
1342 EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1343
1344 free_aligned_buffer_page_end(orig_pixels);
1345 }
1346
TEST_F(LibYUVConvertTest,FuzzJpeg)1347 TEST_F(LibYUVConvertTest, FuzzJpeg) {
1348 // SOI but no EOI. Expect fail.
1349 for (int times = 0; times < benchmark_iterations_; ++times) {
1350 const int kSize = fastrand() % 5000 + 2;
1351 align_buffer_page_end(orig_pixels, kSize);
1352 MemRandomize(orig_pixels, kSize);
1353
1354 // Add SOI so frame will be scanned.
1355 orig_pixels[0] = 0xff;
1356 orig_pixels[1] = 0xd8; // SOI.
1357 orig_pixels[kSize - 1] = 0xff;
1358 ValidateJpeg(orig_pixels, kSize); // Failure normally expected.
1359 free_aligned_buffer_page_end(orig_pixels);
1360 }
1361 }
1362
TEST_F(LibYUVConvertTest,MJPGToI420)1363 TEST_F(LibYUVConvertTest, MJPGToI420) {
1364 const int kOff = 10;
1365 const int kMinJpeg = 64;
1366 const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1367 ? benchmark_width_ * benchmark_height_
1368 : kMinJpeg;
1369 const int kSize = kImageSize + kOff;
1370 align_buffer_page_end(orig_pixels, kSize);
1371 align_buffer_page_end(dst_y_opt, benchmark_width_ * benchmark_height_);
1372 align_buffer_page_end(dst_u_opt, SUBSAMPLE(benchmark_width_, 2) *
1373 SUBSAMPLE(benchmark_height_, 2));
1374 align_buffer_page_end(dst_v_opt, SUBSAMPLE(benchmark_width_, 2) *
1375 SUBSAMPLE(benchmark_height_, 2));
1376
1377 // EOI, SOI to make MJPG appear valid.
1378 memset(orig_pixels, 0, kSize);
1379 orig_pixels[0] = 0xff;
1380 orig_pixels[1] = 0xd8; // SOI.
1381 orig_pixels[kSize - kOff + 0] = 0xff;
1382 orig_pixels[kSize - kOff + 1] = 0xd9; // EOI.
1383
1384 for (int times = 0; times < benchmark_iterations_; ++times) {
1385 int ret =
1386 MJPGToI420(orig_pixels, kSize, dst_y_opt, benchmark_width_, dst_u_opt,
1387 SUBSAMPLE(benchmark_width_, 2), dst_v_opt,
1388 SUBSAMPLE(benchmark_width_, 2), benchmark_width_,
1389 benchmark_height_, benchmark_width_, benchmark_height_);
1390 // Expect failure because image is not really valid.
1391 EXPECT_EQ(1, ret);
1392 }
1393
1394 free_aligned_buffer_page_end(dst_y_opt);
1395 free_aligned_buffer_page_end(dst_u_opt);
1396 free_aligned_buffer_page_end(dst_v_opt);
1397 free_aligned_buffer_page_end(orig_pixels);
1398 }
1399
TEST_F(LibYUVConvertTest,MJPGToARGB)1400 TEST_F(LibYUVConvertTest, MJPGToARGB) {
1401 const int kOff = 10;
1402 const int kMinJpeg = 64;
1403 const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1404 ? benchmark_width_ * benchmark_height_
1405 : kMinJpeg;
1406 const int kSize = kImageSize + kOff;
1407 align_buffer_page_end(orig_pixels, kSize);
1408 align_buffer_page_end(dst_argb_opt, benchmark_width_ * benchmark_height_ * 4);
1409
1410 // EOI, SOI to make MJPG appear valid.
1411 memset(orig_pixels, 0, kSize);
1412 orig_pixels[0] = 0xff;
1413 orig_pixels[1] = 0xd8; // SOI.
1414 orig_pixels[kSize - kOff + 0] = 0xff;
1415 orig_pixels[kSize - kOff + 1] = 0xd9; // EOI.
1416
1417 for (int times = 0; times < benchmark_iterations_; ++times) {
1418 int ret = MJPGToARGB(orig_pixels, kSize, dst_argb_opt, benchmark_width_ * 4,
1419 benchmark_width_, benchmark_height_, benchmark_width_,
1420 benchmark_height_);
1421 // Expect failure because image is not really valid.
1422 EXPECT_EQ(1, ret);
1423 }
1424
1425 free_aligned_buffer_page_end(dst_argb_opt);
1426 free_aligned_buffer_page_end(orig_pixels);
1427 }
1428
1429 #endif // HAVE_JPEG
1430
TEST_F(LibYUVConvertTest,NV12Crop)1431 TEST_F(LibYUVConvertTest, NV12Crop) {
1432 const int SUBSAMP_X = 2;
1433 const int SUBSAMP_Y = 2;
1434 const int kWidth = benchmark_width_;
1435 const int kHeight = benchmark_height_;
1436 const int crop_y =
1437 ((benchmark_height_ - (benchmark_height_ * 360 / 480)) / 2 + 1) & ~1;
1438 const int kDestWidth = benchmark_width_;
1439 const int kDestHeight = benchmark_height_ - crop_y * 2;
1440 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);
1441 const int sample_size =
1442 kWidth * kHeight + kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y) * 2;
1443 align_buffer_page_end(src_y, sample_size);
1444 uint8* src_uv = src_y + kWidth * kHeight;
1445
1446 align_buffer_page_end(dst_y, kDestWidth * kDestHeight);
1447 align_buffer_page_end(dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1448 SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1449 align_buffer_page_end(dst_v, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1450 SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1451
1452 align_buffer_page_end(dst_y_2, kDestWidth * kDestHeight);
1453 align_buffer_page_end(dst_u_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1454 SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1455 align_buffer_page_end(dst_v_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1456 SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1457
1458 for (int i = 0; i < kHeight * kWidth; ++i) {
1459 src_y[i] = (fastrand() & 0xff);
1460 }
1461 for (int i = 0; i < (SUBSAMPLE(kHeight, SUBSAMP_Y) * kStrideUV) * 2; ++i) {
1462 src_uv[i] = (fastrand() & 0xff);
1463 }
1464 memset(dst_y, 1, kDestWidth * kDestHeight);
1465 memset(dst_u, 2,
1466 SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1467 memset(dst_v, 3,
1468 SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1469 memset(dst_y_2, 1, kDestWidth * kDestHeight);
1470 memset(dst_u_2, 2,
1471 SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1472 memset(dst_v_2, 3,
1473 SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1474
1475 ConvertToI420(src_y, sample_size, dst_y_2, kDestWidth, dst_u_2,
1476 SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v_2,
1477 SUBSAMPLE(kDestWidth, SUBSAMP_X), 0, crop_y, kWidth, kHeight,
1478 kDestWidth, kDestHeight, libyuv::kRotate0, libyuv::FOURCC_NV12);
1479
1480 NV12ToI420(src_y + crop_y * kWidth, kWidth,
1481 src_uv + (crop_y / 2) * kStrideUV * 2, kStrideUV * 2, dst_y,
1482 kDestWidth, dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v,
1483 SUBSAMPLE(kDestWidth, SUBSAMP_X), kDestWidth, kDestHeight);
1484
1485 for (int i = 0; i < kDestHeight; ++i) {
1486 for (int j = 0; j < kDestWidth; ++j) {
1487 EXPECT_EQ(dst_y[i * kWidth + j], dst_y_2[i * kWidth + j]);
1488 }
1489 }
1490 for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
1491 for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
1492 EXPECT_EQ(dst_u[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
1493 dst_u_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
1494 }
1495 }
1496 for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
1497 for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
1498 EXPECT_EQ(dst_v[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
1499 dst_v_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
1500 }
1501 }
1502 free_aligned_buffer_page_end(dst_y);
1503 free_aligned_buffer_page_end(dst_u);
1504 free_aligned_buffer_page_end(dst_v);
1505 free_aligned_buffer_page_end(dst_y_2);
1506 free_aligned_buffer_page_end(dst_u_2);
1507 free_aligned_buffer_page_end(dst_v_2);
1508 free_aligned_buffer_page_end(src_y);
1509 }
1510
TEST_F(LibYUVConvertTest,TestYToARGB)1511 TEST_F(LibYUVConvertTest, TestYToARGB) {
1512 uint8 y[32];
1513 uint8 expectedg[32];
1514 for (int i = 0; i < 32; ++i) {
1515 y[i] = i * 5 + 17;
1516 expectedg[i] = static_cast<int>((y[i] - 16) * 1.164f + 0.5f);
1517 }
1518 uint8 argb[32 * 4];
1519 YToARGB(y, 0, argb, 0, 32, 1);
1520
1521 for (int i = 0; i < 32; ++i) {
1522 printf("%2d %d: %d <-> %d,%d,%d,%d\n", i, y[i], expectedg[i],
1523 argb[i * 4 + 0], argb[i * 4 + 1], argb[i * 4 + 2], argb[i * 4 + 3]);
1524 }
1525 for (int i = 0; i < 32; ++i) {
1526 EXPECT_EQ(expectedg[i], argb[i * 4 + 0]);
1527 }
1528 }
1529
1530 static const uint8 kNoDither4x4[16] = {
1531 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1532 };
1533
TEST_F(LibYUVConvertTest,TestNoDither)1534 TEST_F(LibYUVConvertTest, TestNoDither) {
1535 align_buffer_page_end(src_argb, benchmark_width_ * benchmark_height_ * 4);
1536 align_buffer_page_end(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1537 align_buffer_page_end(dst_rgb565dither,
1538 benchmark_width_ * benchmark_height_ * 2);
1539 MemRandomize(src_argb, benchmark_width_ * benchmark_height_ * 4);
1540 MemRandomize(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1541 MemRandomize(dst_rgb565dither, benchmark_width_ * benchmark_height_ * 2);
1542 ARGBToRGB565(src_argb, benchmark_width_ * 4, dst_rgb565, benchmark_width_ * 2,
1543 benchmark_width_, benchmark_height_);
1544 ARGBToRGB565Dither(src_argb, benchmark_width_ * 4, dst_rgb565dither,
1545 benchmark_width_ * 2, kNoDither4x4, benchmark_width_,
1546 benchmark_height_);
1547 for (int i = 0; i < benchmark_width_ * benchmark_height_ * 2; ++i) {
1548 EXPECT_EQ(dst_rgb565[i], dst_rgb565dither[i]);
1549 }
1550
1551 free_aligned_buffer_page_end(src_argb);
1552 free_aligned_buffer_page_end(dst_rgb565);
1553 free_aligned_buffer_page_end(dst_rgb565dither);
1554 }
1555
1556 // Ordered 4x4 dither for 888 to 565. Values from 0 to 7.
1557 static const uint8 kDither565_4x4[16] = {
1558 0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
1559 };
1560
TEST_F(LibYUVConvertTest,TestDither)1561 TEST_F(LibYUVConvertTest, TestDither) {
1562 align_buffer_page_end(src_argb, benchmark_width_ * benchmark_height_ * 4);
1563 align_buffer_page_end(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1564 align_buffer_page_end(dst_rgb565dither,
1565 benchmark_width_ * benchmark_height_ * 2);
1566 align_buffer_page_end(dst_argb, benchmark_width_ * benchmark_height_ * 4);
1567 align_buffer_page_end(dst_argbdither,
1568 benchmark_width_ * benchmark_height_ * 4);
1569 MemRandomize(src_argb, benchmark_width_ * benchmark_height_ * 4);
1570 MemRandomize(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1571 MemRandomize(dst_rgb565dither, benchmark_width_ * benchmark_height_ * 2);
1572 MemRandomize(dst_argb, benchmark_width_ * benchmark_height_ * 4);
1573 MemRandomize(dst_argbdither, benchmark_width_ * benchmark_height_ * 4);
1574 ARGBToRGB565(src_argb, benchmark_width_ * 4, dst_rgb565, benchmark_width_ * 2,
1575 benchmark_width_, benchmark_height_);
1576 ARGBToRGB565Dither(src_argb, benchmark_width_ * 4, dst_rgb565dither,
1577 benchmark_width_ * 2, kDither565_4x4, benchmark_width_,
1578 benchmark_height_);
1579 RGB565ToARGB(dst_rgb565, benchmark_width_ * 2, dst_argb, benchmark_width_ * 4,
1580 benchmark_width_, benchmark_height_);
1581 RGB565ToARGB(dst_rgb565dither, benchmark_width_ * 2, dst_argbdither,
1582 benchmark_width_ * 4, benchmark_width_, benchmark_height_);
1583
1584 for (int i = 0; i < benchmark_width_ * benchmark_height_ * 4; ++i) {
1585 EXPECT_NEAR(dst_argb[i], dst_argbdither[i], 9);
1586 }
1587 free_aligned_buffer_page_end(src_argb);
1588 free_aligned_buffer_page_end(dst_rgb565);
1589 free_aligned_buffer_page_end(dst_rgb565dither);
1590 free_aligned_buffer_page_end(dst_argb);
1591 free_aligned_buffer_page_end(dst_argbdither);
1592 }
1593
1594 #define TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1595 YALIGN, W1280, DIFF, N, NEG, OFF, FMT_C, BPP_C) \
1596 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##Dither##N) { \
1597 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1598 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
1599 const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN); \
1600 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
1601 const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
1602 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
1603 align_buffer_page_end(src_u, kSizeUV + OFF); \
1604 align_buffer_page_end(src_v, kSizeUV + OFF); \
1605 align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF); \
1606 align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF); \
1607 for (int i = 0; i < kWidth * kHeight; ++i) { \
1608 src_y[i + OFF] = (fastrand() & 0xff); \
1609 } \
1610 for (int i = 0; i < kSizeUV; ++i) { \
1611 src_u[i + OFF] = (fastrand() & 0xff); \
1612 src_v[i + OFF] = (fastrand() & 0xff); \
1613 } \
1614 memset(dst_argb_c + OFF, 1, kStrideB * kHeight); \
1615 memset(dst_argb_opt + OFF, 101, kStrideB * kHeight); \
1616 MaskCpuFlags(disable_cpu_flags_); \
1617 FMT_PLANAR##To##FMT_B##Dither(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
1618 src_v + OFF, kStrideUV, dst_argb_c + OFF, \
1619 kStrideB, NULL, kWidth, NEG kHeight); \
1620 MaskCpuFlags(benchmark_cpu_info_); \
1621 for (int i = 0; i < benchmark_iterations_; ++i) { \
1622 FMT_PLANAR##To##FMT_B##Dither( \
1623 src_y + OFF, kWidth, src_u + OFF, kStrideUV, src_v + OFF, kStrideUV, \
1624 dst_argb_opt + OFF, kStrideB, NULL, kWidth, NEG kHeight); \
1625 } \
1626 int max_diff = 0; \
1627 /* Convert to ARGB so 565 is expanded to bytes that can be compared. */ \
1628 align_buffer_page_end(dst_argb32_c, kWidth* BPP_C* kHeight); \
1629 align_buffer_page_end(dst_argb32_opt, kWidth* BPP_C* kHeight); \
1630 memset(dst_argb32_c, 2, kWidth* BPP_C* kHeight); \
1631 memset(dst_argb32_opt, 102, kWidth* BPP_C* kHeight); \
1632 FMT_B##To##FMT_C(dst_argb_c + OFF, kStrideB, dst_argb32_c, kWidth * BPP_C, \
1633 kWidth, kHeight); \
1634 FMT_B##To##FMT_C(dst_argb_opt + OFF, kStrideB, dst_argb32_opt, \
1635 kWidth * BPP_C, kWidth, kHeight); \
1636 for (int i = 0; i < kWidth * BPP_C * kHeight; ++i) { \
1637 int abs_diff = abs(static_cast<int>(dst_argb32_c[i]) - \
1638 static_cast<int>(dst_argb32_opt[i])); \
1639 if (abs_diff > max_diff) { \
1640 max_diff = abs_diff; \
1641 } \
1642 } \
1643 EXPECT_LE(max_diff, DIFF); \
1644 free_aligned_buffer_page_end(src_y); \
1645 free_aligned_buffer_page_end(src_u); \
1646 free_aligned_buffer_page_end(src_v); \
1647 free_aligned_buffer_page_end(dst_argb_c); \
1648 free_aligned_buffer_page_end(dst_argb_opt); \
1649 free_aligned_buffer_page_end(dst_argb32_c); \
1650 free_aligned_buffer_page_end(dst_argb32_opt); \
1651 }
1652
1653 #define TESTPLANARTOBD(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1654 YALIGN, DIFF, FMT_C, BPP_C) \
1655 TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1656 YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, FMT_C, \
1657 BPP_C) \
1658 TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1659 YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, FMT_C, \
1660 BPP_C) \
1661 TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1662 YALIGN, benchmark_width_, DIFF, _Invert, -, 0, FMT_C, BPP_C) \
1663 TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1664 YALIGN, benchmark_width_, DIFF, _Opt, +, 0, FMT_C, BPP_C)
1665
1666 TESTPLANARTOBD(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4)
1667
1668 #define TESTPTOB(NAME, UYVYTOI420, UYVYTONV12) \
1669 TEST_F(LibYUVConvertTest, NAME) { \
1670 const int kWidth = benchmark_width_; \
1671 const int kHeight = benchmark_height_; \
1672 \
1673 align_buffer_page_end(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2) * kHeight); \
1674 align_buffer_page_end(orig_y, kWidth* kHeight); \
1675 align_buffer_page_end(orig_u, \
1676 SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2)); \
1677 align_buffer_page_end(orig_v, \
1678 SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2)); \
1679 \
1680 align_buffer_page_end(dst_y_orig, kWidth* kHeight); \
1681 align_buffer_page_end(dst_uv_orig, \
1682 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2)); \
1683 \
1684 align_buffer_page_end(dst_y, kWidth* kHeight); \
1685 align_buffer_page_end(dst_uv, \
1686 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2)); \
1687 \
1688 MemRandomize(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2) * kHeight); \
1689 \
1690 /* Convert UYVY to NV12 in 2 steps for reference */ \
1691 libyuv::UYVYTOI420(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2), orig_y, kWidth, \
1692 orig_u, SUBSAMPLE(kWidth, 2), orig_v, \
1693 SUBSAMPLE(kWidth, 2), kWidth, kHeight); \
1694 libyuv::I420ToNV12(orig_y, kWidth, orig_u, SUBSAMPLE(kWidth, 2), orig_v, \
1695 SUBSAMPLE(kWidth, 2), dst_y_orig, kWidth, dst_uv_orig, \
1696 2 * SUBSAMPLE(kWidth, 2), kWidth, kHeight); \
1697 \
1698 /* Convert to NV12 */ \
1699 for (int i = 0; i < benchmark_iterations_; ++i) { \
1700 libyuv::UYVYTONV12(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2), dst_y, kWidth, \
1701 dst_uv, 2 * SUBSAMPLE(kWidth, 2), kWidth, kHeight); \
1702 } \
1703 \
1704 for (int i = 0; i < kWidth * kHeight; ++i) { \
1705 EXPECT_EQ(orig_y[i], dst_y[i]); \
1706 } \
1707 for (int i = 0; i < kWidth * kHeight; ++i) { \
1708 EXPECT_EQ(dst_y_orig[i], dst_y[i]); \
1709 } \
1710 for (int i = 0; i < 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2); \
1711 ++i) { \
1712 EXPECT_EQ(dst_uv_orig[i], dst_uv[i]); \
1713 } \
1714 \
1715 free_aligned_buffer_page_end(orig_uyvy); \
1716 free_aligned_buffer_page_end(orig_y); \
1717 free_aligned_buffer_page_end(orig_u); \
1718 free_aligned_buffer_page_end(orig_v); \
1719 free_aligned_buffer_page_end(dst_y_orig); \
1720 free_aligned_buffer_page_end(dst_uv_orig); \
1721 free_aligned_buffer_page_end(dst_y); \
1722 free_aligned_buffer_page_end(dst_uv); \
1723 }
1724
TESTPTOB(TestYUY2ToNV12,YUY2ToI420,YUY2ToNV12)1725 TESTPTOB(TestYUY2ToNV12, YUY2ToI420, YUY2ToNV12)
1726 TESTPTOB(TestUYVYToNV12, UYVYToI420, UYVYToNV12)
1727
1728 #define TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1729 W1280, N, NEG, OFF, FMT_C, BPP_C) \
1730 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) { \
1731 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1732 const int kHeight = benchmark_height_; \
1733 const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B; \
1734 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
1735 const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
1736 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
1737 align_buffer_page_end(src_u, kSizeUV + OFF); \
1738 align_buffer_page_end(src_v, kSizeUV + OFF); \
1739 align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF); \
1740 for (int i = 0; i < kWidth * kHeight; ++i) { \
1741 src_y[i + OFF] = (fastrand() & 0xff); \
1742 } \
1743 for (int i = 0; i < kSizeUV; ++i) { \
1744 src_u[i + OFF] = (fastrand() & 0xff); \
1745 src_v[i + OFF] = (fastrand() & 0xff); \
1746 } \
1747 memset(dst_argb_b + OFF, 1, kStrideB * kHeight); \
1748 for (int i = 0; i < benchmark_iterations_; ++i) { \
1749 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
1750 src_v + OFF, kStrideUV, dst_argb_b + OFF, \
1751 kStrideB, kWidth, NEG kHeight); \
1752 } \
1753 /* Convert to a 3rd format in 1 step and 2 steps and compare */ \
1754 const int kStrideC = kWidth * BPP_C; \
1755 align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF); \
1756 align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF); \
1757 memset(dst_argb_c + OFF, 2, kStrideC * kHeight); \
1758 memset(dst_argb_bc + OFF, 3, kStrideC * kHeight); \
1759 FMT_PLANAR##To##FMT_C(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
1760 src_v + OFF, kStrideUV, dst_argb_c + OFF, kStrideC, \
1761 kWidth, NEG kHeight); \
1762 /* Convert B to C */ \
1763 FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC, \
1764 kWidth, kHeight); \
1765 for (int i = 0; i < kStrideC * kHeight; ++i) { \
1766 EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_bc[i + OFF]); \
1767 } \
1768 free_aligned_buffer_page_end(src_y); \
1769 free_aligned_buffer_page_end(src_u); \
1770 free_aligned_buffer_page_end(src_v); \
1771 free_aligned_buffer_page_end(dst_argb_b); \
1772 free_aligned_buffer_page_end(dst_argb_c); \
1773 free_aligned_buffer_page_end(dst_argb_bc); \
1774 }
1775
1776 #define TESTPLANARTOE(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1777 FMT_C, BPP_C) \
1778 TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1779 benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C) \
1780 TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1781 benchmark_width_, _Unaligned, +, 1, FMT_C, BPP_C) \
1782 TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1783 benchmark_width_, _Invert, -, 0, FMT_C, BPP_C) \
1784 TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1785 benchmark_width_, _Opt, +, 0, FMT_C, BPP_C)
1786
1787 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ABGR, 4)
1788 TESTPLANARTOE(J420, 2, 2, ARGB, 1, 4, ARGB, 4)
1789 TESTPLANARTOE(J420, 2, 2, ABGR, 1, 4, ARGB, 4)
1790 TESTPLANARTOE(H420, 2, 2, ARGB, 1, 4, ARGB, 4)
1791 TESTPLANARTOE(H420, 2, 2, ABGR, 1, 4, ARGB, 4)
1792 TESTPLANARTOE(I420, 2, 2, BGRA, 1, 4, ARGB, 4)
1793 TESTPLANARTOE(I420, 2, 2, ABGR, 1, 4, ARGB, 4)
1794 TESTPLANARTOE(I420, 2, 2, RGBA, 1, 4, ARGB, 4)
1795 TESTPLANARTOE(I420, 2, 2, RGB24, 1, 3, ARGB, 4)
1796 TESTPLANARTOE(I420, 2, 2, RAW, 1, 3, RGB24, 3)
1797 TESTPLANARTOE(I420, 2, 2, RGB24, 1, 3, RAW, 3)
1798 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, RAW, 3)
1799 TESTPLANARTOE(I420, 2, 2, RAW, 1, 3, ARGB, 4)
1800 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, RGB565, 2)
1801 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ARGB1555, 2)
1802 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ARGB4444, 2)
1803 TESTPLANARTOE(I422, 2, 1, ARGB, 1, 4, ARGB, 4)
1804 TESTPLANARTOE(J422, 2, 1, ARGB, 1, 4, ARGB, 4)
1805 TESTPLANARTOE(J422, 2, 1, ABGR, 1, 4, ARGB, 4)
1806 TESTPLANARTOE(H422, 2, 1, ARGB, 1, 4, ARGB, 4)
1807 TESTPLANARTOE(H422, 2, 1, ABGR, 1, 4, ARGB, 4)
1808 TESTPLANARTOE(I422, 2, 1, BGRA, 1, 4, ARGB, 4)
1809 TESTPLANARTOE(I422, 2, 1, ABGR, 1, 4, ARGB, 4)
1810 TESTPLANARTOE(I422, 2, 1, RGBA, 1, 4, ARGB, 4)
1811 TESTPLANARTOE(I444, 1, 1, ARGB, 1, 4, ARGB, 4)
1812 TESTPLANARTOE(J444, 1, 1, ARGB, 1, 4, ARGB, 4)
1813 TESTPLANARTOE(I444, 1, 1, ABGR, 1, 4, ARGB, 4)
1814 TESTPLANARTOE(I420, 2, 2, YUY2, 2, 4, ARGB, 4)
1815 TESTPLANARTOE(I420, 2, 2, UYVY, 2, 4, ARGB, 4)
1816 TESTPLANARTOE(I422, 2, 1, YUY2, 2, 4, ARGB, 4)
1817 TESTPLANARTOE(I422, 2, 1, UYVY, 2, 4, ARGB, 4)
1818
1819 #define TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1820 W1280, N, NEG, OFF, FMT_C, BPP_C, ATTEN) \
1821 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) { \
1822 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1823 const int kHeight = benchmark_height_; \
1824 const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B; \
1825 const int kSizeUV = \
1826 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y); \
1827 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
1828 align_buffer_page_end(src_u, kSizeUV + OFF); \
1829 align_buffer_page_end(src_v, kSizeUV + OFF); \
1830 align_buffer_page_end(src_a, kWidth* kHeight + OFF); \
1831 align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF); \
1832 for (int i = 0; i < kWidth * kHeight; ++i) { \
1833 src_y[i + OFF] = (fastrand() & 0xff); \
1834 src_a[i + OFF] = (fastrand() & 0xff); \
1835 } \
1836 for (int i = 0; i < kSizeUV; ++i) { \
1837 src_u[i + OFF] = (fastrand() & 0xff); \
1838 src_v[i + OFF] = (fastrand() & 0xff); \
1839 } \
1840 memset(dst_argb_b + OFF, 1, kStrideB * kHeight); \
1841 for (int i = 0; i < benchmark_iterations_; ++i) { \
1842 FMT_PLANAR##To##FMT_B( \
1843 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), \
1844 src_v + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), src_a + OFF, kWidth, \
1845 dst_argb_b + OFF, kStrideB, kWidth, NEG kHeight, ATTEN); \
1846 } \
1847 /* Convert to a 3rd format in 1 step and 2 steps and compare */ \
1848 const int kStrideC = kWidth * BPP_C; \
1849 align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF); \
1850 align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF); \
1851 memset(dst_argb_c + OFF, 2, kStrideC * kHeight); \
1852 memset(dst_argb_bc + OFF, 3, kStrideC * kHeight); \
1853 FMT_PLANAR##To##FMT_C( \
1854 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), \
1855 src_v + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), src_a + OFF, kWidth, \
1856 dst_argb_c + OFF, kStrideC, kWidth, NEG kHeight, ATTEN); \
1857 /* Convert B to C */ \
1858 FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC, \
1859 kWidth, kHeight); \
1860 for (int i = 0; i < kStrideC * kHeight; ++i) { \
1861 EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_bc[i + OFF]); \
1862 } \
1863 free_aligned_buffer_page_end(src_y); \
1864 free_aligned_buffer_page_end(src_u); \
1865 free_aligned_buffer_page_end(src_v); \
1866 free_aligned_buffer_page_end(src_a); \
1867 free_aligned_buffer_page_end(dst_argb_b); \
1868 free_aligned_buffer_page_end(dst_argb_c); \
1869 free_aligned_buffer_page_end(dst_argb_bc); \
1870 }
1871
1872 #define TESTQPLANARTOE(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1873 FMT_C, BPP_C) \
1874 TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1875 benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C, 0) \
1876 TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1877 benchmark_width_, _Unaligned, +, 1, FMT_C, BPP_C, 0) \
1878 TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1879 benchmark_width_, _Invert, -, 0, FMT_C, BPP_C, 0) \
1880 TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1881 benchmark_width_, _Opt, +, 0, FMT_C, BPP_C, 0) \
1882 TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1883 benchmark_width_, _Premult, +, 0, FMT_C, BPP_C, 1)
1884
1885 TESTQPLANARTOE(I420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4)
1886 TESTQPLANARTOE(I420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4)
1887
1888 TEST_F(LibYUVConvertTest, RotateWithARGBSource) {
1889 // 2x2 frames
1890 uint32_t src[4];
1891 uint32_t dst[4];
1892 // some random input
1893 src[0] = 0x11000000;
1894 src[1] = 0x00450000;
1895 src[2] = 0x00009f00;
1896 src[3] = 0x000000ff;
1897 // zeros on destination
1898 dst[0] = 0x00000000;
1899 dst[1] = 0x00000000;
1900 dst[2] = 0x00000000;
1901 dst[3] = 0x00000000;
1902
1903 int r = ConvertToARGB(reinterpret_cast<uint8_t*>(src),
1904 16, // input size
1905 reinterpret_cast<uint8_t*>(dst),
1906 8, // destination stride
1907 0, // crop_x
1908 0, // crop_y
1909 2, // width
1910 2, // height
1911 2, // crop width
1912 2, // crop height
1913 kRotate90, FOURCC_ARGB);
1914
1915 EXPECT_EQ(r, 0);
1916 // 90 degrees rotation, no conversion
1917 EXPECT_EQ(dst[0], src[2]);
1918 EXPECT_EQ(dst[1], src[0]);
1919 EXPECT_EQ(dst[2], src[3]);
1920 EXPECT_EQ(dst[3], src[1]);
1921 }
1922
1923 } // namespace libyuv
1924