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