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 <assert.h>
12 #include <stdlib.h>
13 #include <time.h>
14 
15 #include "libyuv/row.h" /* For ARGBToAR30Row_AVX2 */
16 
17 #include "libyuv/basic_types.h"
18 #include "libyuv/compare.h"
19 #include "libyuv/convert.h"
20 #include "libyuv/convert_argb.h"
21 #include "libyuv/convert_from.h"
22 #include "libyuv/convert_from_argb.h"
23 #include "libyuv/cpu_id.h"
24 #ifdef HAVE_JPEG
25 #include "libyuv/mjpeg_decoder.h"
26 #endif
27 #include "../unit_test/unit_test.h"
28 #include "libyuv/planar_functions.h"
29 #include "libyuv/rotate.h"
30 #include "libyuv/video_common.h"
31 
32 #if defined(__arm__) || defined(__aarch64__)
33 // arm version subsamples by summing 4 pixels then multiplying by matrix with
34 // 4x smaller coefficients which are rounded to nearest integer.
35 #define ARM_YUV_ERROR 4
36 #else
37 #define ARM_YUV_ERROR 0
38 #endif
39 
40 namespace libyuv {
41 
42 // Alias to copy pixels as is
43 #define AR30ToAR30 ARGBCopy
44 #define ABGRToABGR ARGBCopy
45 
46 #define SUBSAMPLE(v, a) ((((v) + (a)-1)) / (a))
47 
48 // Planar test
49 
50 #define TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X,         \
51                        SRC_SUBSAMP_Y, FMT_PLANAR, DST_T, DST_BPC,             \
52                        DST_SUBSAMP_X, DST_SUBSAMP_Y, W1280, N, NEG, OFF)      \
53   TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) {              \
54     static_assert(SRC_BPC == 1 || SRC_BPC == 2, "SRC BPC unsupported");       \
55     static_assert(DST_BPC == 1 || DST_BPC == 2, "DST BPC unsupported");       \
56     static_assert(SRC_SUBSAMP_X == 1 || SRC_SUBSAMP_X == 2,                   \
57                   "DST SRC_SUBSAMP_X unsupported");                           \
58     static_assert(SRC_SUBSAMP_Y == 1 || SRC_SUBSAMP_Y == 2,                   \
59                   "DST SRC_SUBSAMP_Y unsupported");                           \
60     static_assert(DST_SUBSAMP_X == 1 || DST_SUBSAMP_X == 2,                   \
61                   "DST DST_SUBSAMP_X unsupported");                           \
62     static_assert(DST_SUBSAMP_Y == 1 || DST_SUBSAMP_Y == 2,                   \
63                   "DST DST_SUBSAMP_Y unsupported");                           \
64     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                           \
65     const int kHeight = benchmark_height_;                                    \
66     const int kSrcHalfWidth = SUBSAMPLE(kWidth, SRC_SUBSAMP_X);               \
67     const int kSrcHalfHeight = SUBSAMPLE(kHeight, SRC_SUBSAMP_Y);             \
68     const int kDstHalfWidth = SUBSAMPLE(kWidth, DST_SUBSAMP_X);               \
69     const int kDstHalfHeight = SUBSAMPLE(kHeight, DST_SUBSAMP_Y);             \
70     align_buffer_page_end(src_y, kWidth* kHeight* SRC_BPC + OFF);             \
71     align_buffer_page_end(src_u,                                              \
72                           kSrcHalfWidth* kSrcHalfHeight* SRC_BPC + OFF);      \
73     align_buffer_page_end(src_v,                                              \
74                           kSrcHalfWidth* kSrcHalfHeight* SRC_BPC + OFF);      \
75     align_buffer_page_end(dst_y_c, kWidth* kHeight* DST_BPC);                 \
76     align_buffer_page_end(dst_u_c, kDstHalfWidth* kDstHalfHeight* DST_BPC);   \
77     align_buffer_page_end(dst_v_c, kDstHalfWidth* kDstHalfHeight* DST_BPC);   \
78     align_buffer_page_end(dst_y_opt, kWidth* kHeight* DST_BPC);               \
79     align_buffer_page_end(dst_u_opt, kDstHalfWidth* kDstHalfHeight* DST_BPC); \
80     align_buffer_page_end(dst_v_opt, kDstHalfWidth* kDstHalfHeight* DST_BPC); \
81     MemRandomize(src_y + OFF, kWidth * kHeight * SRC_BPC);                    \
82     MemRandomize(src_u + OFF, kSrcHalfWidth * kSrcHalfHeight * SRC_BPC);      \
83     MemRandomize(src_v + OFF, kSrcHalfWidth * kSrcHalfHeight * SRC_BPC);      \
84     memset(dst_y_c, 1, kWidth* kHeight* DST_BPC);                             \
85     memset(dst_u_c, 2, kDstHalfWidth* kDstHalfHeight* DST_BPC);               \
86     memset(dst_v_c, 3, kDstHalfWidth* kDstHalfHeight* DST_BPC);               \
87     memset(dst_y_opt, 101, kWidth* kHeight* DST_BPC);                         \
88     memset(dst_u_opt, 102, kDstHalfWidth* kDstHalfHeight* DST_BPC);           \
89     memset(dst_v_opt, 103, kDstHalfWidth* kDstHalfHeight* DST_BPC);           \
90     MaskCpuFlags(disable_cpu_flags_);                                         \
91     SRC_FMT_PLANAR##To##FMT_PLANAR(                                           \
92         reinterpret_cast<SRC_T*>(src_y + OFF), kWidth,                        \
93         reinterpret_cast<SRC_T*>(src_u + OFF), kSrcHalfWidth,                 \
94         reinterpret_cast<SRC_T*>(src_v + OFF), kSrcHalfWidth,                 \
95         reinterpret_cast<DST_T*>(dst_y_c), kWidth,                            \
96         reinterpret_cast<DST_T*>(dst_u_c), kDstHalfWidth,                     \
97         reinterpret_cast<DST_T*>(dst_v_c), kDstHalfWidth, kWidth,             \
98         NEG kHeight);                                                         \
99     MaskCpuFlags(benchmark_cpu_info_);                                        \
100     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
101       SRC_FMT_PLANAR##To##FMT_PLANAR(                                         \
102           reinterpret_cast<SRC_T*>(src_y + OFF), kWidth,                      \
103           reinterpret_cast<SRC_T*>(src_u + OFF), kSrcHalfWidth,               \
104           reinterpret_cast<SRC_T*>(src_v + OFF), kSrcHalfWidth,               \
105           reinterpret_cast<DST_T*>(dst_y_opt), kWidth,                        \
106           reinterpret_cast<DST_T*>(dst_u_opt), kDstHalfWidth,                 \
107           reinterpret_cast<DST_T*>(dst_v_opt), kDstHalfWidth, kWidth,         \
108           NEG kHeight);                                                       \
109     }                                                                         \
110     for (int i = 0; i < kHeight * kWidth * DST_BPC; ++i) {                    \
111       EXPECT_EQ(dst_y_c[i], dst_y_opt[i]);                                    \
112     }                                                                         \
113     for (int i = 0; i < kDstHalfWidth * kDstHalfHeight * DST_BPC; ++i) {      \
114       EXPECT_EQ(dst_u_c[i], dst_u_opt[i]);                                    \
115       EXPECT_EQ(dst_v_c[i], dst_v_opt[i]);                                    \
116     }                                                                         \
117     free_aligned_buffer_page_end(dst_y_c);                                    \
118     free_aligned_buffer_page_end(dst_u_c);                                    \
119     free_aligned_buffer_page_end(dst_v_c);                                    \
120     free_aligned_buffer_page_end(dst_y_opt);                                  \
121     free_aligned_buffer_page_end(dst_u_opt);                                  \
122     free_aligned_buffer_page_end(dst_v_opt);                                  \
123     free_aligned_buffer_page_end(src_y);                                      \
124     free_aligned_buffer_page_end(src_u);                                      \
125     free_aligned_buffer_page_end(src_v);                                      \
126   }
127 
128 #define TESTPLANARTOP(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X,           \
129                       SRC_SUBSAMP_Y, FMT_PLANAR, DST_T, DST_BPC,               \
130                       DST_SUBSAMP_X, DST_SUBSAMP_Y)                            \
131   TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
132                  FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y,     \
133                  benchmark_width_ - 4, _Any, +, 0)                             \
134   TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
135                  FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y,     \
136                  benchmark_width_, _Unaligned, +, 1)                           \
137   TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
138                  FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y,     \
139                  benchmark_width_, _Invert, -, 0)                              \
140   TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
141                  FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y,     \
142                  benchmark_width_, _Opt, +, 0)
143 
144 TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I420, uint8_t, 1, 2, 2)
145 TESTPLANARTOP(I422, uint8_t, 1, 2, 1, I420, uint8_t, 1, 2, 2)
146 TESTPLANARTOP(I444, uint8_t, 1, 1, 1, I420, uint8_t, 1, 2, 2)
147 TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I422, uint8_t, 1, 2, 1)
148 TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I444, uint8_t, 1, 1, 1)
149 TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I420Mirror, uint8_t, 1, 2, 2)
150 TESTPLANARTOP(I422, uint8_t, 1, 2, 1, I422, uint8_t, 1, 2, 1)
151 TESTPLANARTOP(I444, uint8_t, 1, 1, 1, I444, uint8_t, 1, 1, 1)
152 TESTPLANARTOP(I010, uint16_t, 2, 2, 2, I010, uint16_t, 2, 2, 2)
153 TESTPLANARTOP(I010, uint16_t, 2, 2, 2, I420, uint8_t, 1, 2, 2)
154 TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I010, uint16_t, 2, 2, 2)
155 TESTPLANARTOP(H010, uint16_t, 2, 2, 2, H010, uint16_t, 2, 2, 2)
156 TESTPLANARTOP(H010, uint16_t, 2, 2, 2, H420, uint8_t, 1, 2, 2)
157 TESTPLANARTOP(H420, uint8_t, 1, 2, 2, H010, uint16_t, 2, 2, 2)
158 
159 // Test Android 420 to I420
160 #define TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X,          \
161                         SRC_SUBSAMP_Y, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
162                         W1280, N, NEG, OFF, PN, OFF_U, OFF_V)                 \
163   TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##_##PN##N) {       \
164     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                           \
165     const int kHeight = benchmark_height_;                                    \
166     const int kSizeUV =                                                       \
167         SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); \
168     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                      \
169     align_buffer_page_end(src_uv,                                             \
170                           kSizeUV*((PIXEL_STRIDE == 3) ? 3 : 2) + OFF);       \
171     align_buffer_page_end(dst_y_c, kWidth* kHeight);                          \
172     align_buffer_page_end(dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X) *             \
173                                        SUBSAMPLE(kHeight, SUBSAMP_Y));        \
174     align_buffer_page_end(dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X) *             \
175                                        SUBSAMPLE(kHeight, SUBSAMP_Y));        \
176     align_buffer_page_end(dst_y_opt, kWidth* kHeight);                        \
177     align_buffer_page_end(dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X) *           \
178                                          SUBSAMPLE(kHeight, SUBSAMP_Y));      \
179     align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) *           \
180                                          SUBSAMPLE(kHeight, SUBSAMP_Y));      \
181     uint8_t* src_u = src_uv + OFF_U;                                          \
182     uint8_t* src_v = src_uv + (PIXEL_STRIDE == 1 ? kSizeUV : OFF_V);          \
183     int src_stride_uv = SUBSAMPLE(kWidth, SUBSAMP_X) * PIXEL_STRIDE;          \
184     for (int i = 0; i < kHeight; ++i)                                         \
185       for (int j = 0; j < kWidth; ++j)                                        \
186         src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                    \
187     for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) {             \
188       for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) {            \
189         src_u[(i * src_stride_uv) + j * PIXEL_STRIDE + OFF] =                 \
190             (fastrand() & 0xff);                                              \
191         src_v[(i * src_stride_uv) + j * PIXEL_STRIDE + OFF] =                 \
192             (fastrand() & 0xff);                                              \
193       }                                                                       \
194     }                                                                         \
195     memset(dst_y_c, 1, kWidth* kHeight);                                      \
196     memset(dst_u_c, 2,                                                        \
197            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));     \
198     memset(dst_v_c, 3,                                                        \
199            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));     \
200     memset(dst_y_opt, 101, kWidth* kHeight);                                  \
201     memset(dst_u_opt, 102,                                                    \
202            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));     \
203     memset(dst_v_opt, 103,                                                    \
204            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));     \
205     MaskCpuFlags(disable_cpu_flags_);                                         \
206     SRC_FMT_PLANAR##To##FMT_PLANAR(                                           \
207         src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X),   \
208         src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), PIXEL_STRIDE, dst_y_c, \
209         kWidth, dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_c,               \
210         SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight);                   \
211     MaskCpuFlags(benchmark_cpu_info_);                                        \
212     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
213       SRC_FMT_PLANAR##To##FMT_PLANAR(                                         \
214           src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
215           src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), PIXEL_STRIDE,        \
216           dst_y_opt, kWidth, dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X),         \
217           dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight);      \
218     }                                                                         \
219     int max_diff = 0;                                                         \
220     for (int i = 0; i < kHeight; ++i) {                                       \
221       for (int j = 0; j < kWidth; ++j) {                                      \
222         int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) -        \
223                            static_cast<int>(dst_y_opt[i * kWidth + j]));      \
224         if (abs_diff > max_diff) {                                            \
225           max_diff = abs_diff;                                                \
226         }                                                                     \
227       }                                                                       \
228     }                                                                         \
229     EXPECT_EQ(0, max_diff);                                                   \
230     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                 \
231       for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) {                \
232         int abs_diff = abs(                                                   \
233             static_cast<int>(dst_u_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
234             static_cast<int>(                                                 \
235                 dst_u_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]));            \
236         if (abs_diff > max_diff) {                                            \
237           max_diff = abs_diff;                                                \
238         }                                                                     \
239       }                                                                       \
240     }                                                                         \
241     EXPECT_LE(max_diff, 3);                                                   \
242     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                 \
243       for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) {                \
244         int abs_diff = abs(                                                   \
245             static_cast<int>(dst_v_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
246             static_cast<int>(                                                 \
247                 dst_v_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]));            \
248         if (abs_diff > max_diff) {                                            \
249           max_diff = abs_diff;                                                \
250         }                                                                     \
251       }                                                                       \
252     }                                                                         \
253     EXPECT_LE(max_diff, 3);                                                   \
254     free_aligned_buffer_page_end(dst_y_c);                                    \
255     free_aligned_buffer_page_end(dst_u_c);                                    \
256     free_aligned_buffer_page_end(dst_v_c);                                    \
257     free_aligned_buffer_page_end(dst_y_opt);                                  \
258     free_aligned_buffer_page_end(dst_u_opt);                                  \
259     free_aligned_buffer_page_end(dst_v_opt);                                  \
260     free_aligned_buffer_page_end(src_y);                                      \
261     free_aligned_buffer_page_end(src_uv);                                     \
262   }
263 
264 #define TESTAPLANARTOP(SRC_FMT_PLANAR, PN, PIXEL_STRIDE, OFF_U, OFF_V,         \
265                        SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, SUBSAMP_X,    \
266                        SUBSAMP_Y)                                              \
267   TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,  \
268                   FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4,      \
269                   _Any, +, 0, 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_,          \
272                   _Unaligned, +, 1, 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_, _Invert, \
275                   -, 0, PN, OFF_U, OFF_V)                                      \
276   TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,  \
277                   FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, \
278                   0, PN, OFF_U, OFF_V)
279 
280 TESTAPLANARTOP(Android420, I420, 1, 0, 0, 2, 2, I420, 2, 2)
281 TESTAPLANARTOP(Android420, NV12, 2, 0, 1, 2, 2, I420, 2, 2)
282 TESTAPLANARTOP(Android420, NV21, 2, 1, 0, 2, 2, I420, 2, 2)
283 
284 #define TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,         \
285                         FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF) \
286   TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) {              \
287     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                           \
288     const int kHeight = benchmark_height_;                                    \
289     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                      \
290     align_buffer_page_end(src_u, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *           \
291                                          SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) +  \
292                                      OFF);                                    \
293     align_buffer_page_end(src_v, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *           \
294                                          SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) +  \
295                                      OFF);                                    \
296     align_buffer_page_end(dst_y_c, kWidth* kHeight);                          \
297     align_buffer_page_end(dst_uv_c, SUBSAMPLE(kWidth * 2, SUBSAMP_X) *        \
298                                         SUBSAMPLE(kHeight, SUBSAMP_Y));       \
299     align_buffer_page_end(dst_y_opt, kWidth* kHeight);                        \
300     align_buffer_page_end(dst_uv_opt, SUBSAMPLE(kWidth * 2, SUBSAMP_X) *      \
301                                           SUBSAMPLE(kHeight, SUBSAMP_Y));     \
302     for (int i = 0; i < kHeight; ++i)                                         \
303       for (int j = 0; j < kWidth; ++j)                                        \
304         src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                    \
305     for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) {             \
306       for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) {            \
307         src_u[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =             \
308             (fastrand() & 0xff);                                              \
309         src_v[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =             \
310             (fastrand() & 0xff);                                              \
311       }                                                                       \
312     }                                                                         \
313     memset(dst_y_c, 1, kWidth* kHeight);                                      \
314     memset(dst_uv_c, 2,                                                       \
315            SUBSAMPLE(kWidth * 2, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
316     memset(dst_y_opt, 101, kWidth* kHeight);                                  \
317     memset(dst_uv_opt, 102,                                                   \
318            SUBSAMPLE(kWidth * 2, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
319     MaskCpuFlags(disable_cpu_flags_);                                         \
320     SRC_FMT_PLANAR##To##FMT_PLANAR(                                           \
321         src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X),   \
322         src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_c, kWidth,       \
323         dst_uv_c, SUBSAMPLE(kWidth * 2, SUBSAMP_X), kWidth, NEG kHeight);     \
324     MaskCpuFlags(benchmark_cpu_info_);                                        \
325     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
326       SRC_FMT_PLANAR##To##FMT_PLANAR(                                         \
327           src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
328           src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_opt, kWidth,   \
329           dst_uv_opt, SUBSAMPLE(kWidth * 2, SUBSAMP_X), kWidth, NEG kHeight); \
330     }                                                                         \
331     int max_diff = 0;                                                         \
332     for (int i = 0; i < kHeight; ++i) {                                       \
333       for (int j = 0; j < kWidth; ++j) {                                      \
334         int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) -        \
335                            static_cast<int>(dst_y_opt[i * kWidth + j]));      \
336         if (abs_diff > max_diff) {                                            \
337           max_diff = abs_diff;                                                \
338         }                                                                     \
339       }                                                                       \
340     }                                                                         \
341     EXPECT_LE(max_diff, 1);                                                   \
342     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                 \
343       for (int j = 0; j < SUBSAMPLE(kWidth * 2, SUBSAMP_X); ++j) {            \
344         int abs_diff =                                                        \
345             abs(static_cast<int>(                                             \
346                     dst_uv_c[i * SUBSAMPLE(kWidth * 2, SUBSAMP_X) + j]) -     \
347                 static_cast<int>(                                             \
348                     dst_uv_opt[i * SUBSAMPLE(kWidth * 2, SUBSAMP_X) + j]));   \
349         if (abs_diff > max_diff) {                                            \
350           max_diff = abs_diff;                                                \
351         }                                                                     \
352       }                                                                       \
353     }                                                                         \
354     EXPECT_LE(max_diff, 1);                                                   \
355     free_aligned_buffer_page_end(dst_y_c);                                    \
356     free_aligned_buffer_page_end(dst_uv_c);                                   \
357     free_aligned_buffer_page_end(dst_y_opt);                                  \
358     free_aligned_buffer_page_end(dst_uv_opt);                                 \
359     free_aligned_buffer_page_end(src_y);                                      \
360     free_aligned_buffer_page_end(src_u);                                      \
361     free_aligned_buffer_page_end(src_v);                                      \
362   }
363 
364 #define TESTPLANARTOBP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,        \
365                        FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y)                    \
366   TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
367                   SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0)   \
368   TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
369                   SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Unaligned, +, 1) \
370   TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
371                   SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0)    \
372   TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
373                   SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0)
374 
375 TESTPLANARTOBP(I420, 2, 2, NV12, 2, 2)
376 TESTPLANARTOBP(I420, 2, 2, NV21, 2, 2)
377 
378 #define TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,         \
379                          FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF, \
380                          DOY)                                                  \
381   TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) {               \
382     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
383     const int kHeight = benchmark_height_;                                     \
384     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
385     align_buffer_page_end(src_uv, 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *       \
386                                           SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) +  \
387                                       OFF);                                    \
388     align_buffer_page_end(dst_y_c, kWidth* kHeight);                           \
389     align_buffer_page_end(dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X) *              \
390                                        SUBSAMPLE(kHeight, SUBSAMP_Y));         \
391     align_buffer_page_end(dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X) *              \
392                                        SUBSAMPLE(kHeight, SUBSAMP_Y));         \
393     align_buffer_page_end(dst_y_opt, kWidth* kHeight);                         \
394     align_buffer_page_end(dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X) *            \
395                                          SUBSAMPLE(kHeight, SUBSAMP_Y));       \
396     align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) *            \
397                                          SUBSAMPLE(kHeight, SUBSAMP_Y));       \
398     for (int i = 0; i < kHeight; ++i)                                          \
399       for (int j = 0; j < kWidth; ++j)                                         \
400         src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                     \
401     for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) {              \
402       for (int j = 0; j < 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) {         \
403         src_uv[(i * 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =         \
404             (fastrand() & 0xff);                                               \
405       }                                                                        \
406     }                                                                          \
407     memset(dst_y_c, 1, kWidth* kHeight);                                       \
408     memset(dst_u_c, 2,                                                         \
409            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
410     memset(dst_v_c, 3,                                                         \
411            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
412     memset(dst_y_opt, 101, kWidth* kHeight);                                   \
413     memset(dst_u_opt, 102,                                                     \
414            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
415     memset(dst_v_opt, 103,                                                     \
416            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
417     MaskCpuFlags(disable_cpu_flags_);                                          \
418     SRC_FMT_PLANAR##To##FMT_PLANAR(                                            \
419         src_y + OFF, kWidth, src_uv + OFF,                                     \
420         2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X), DOY ? dst_y_c : NULL, kWidth,    \
421         dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_c,                        \
422         SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight);                    \
423     MaskCpuFlags(benchmark_cpu_info_);                                         \
424     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
425       SRC_FMT_PLANAR##To##FMT_PLANAR(                                          \
426           src_y + OFF, kWidth, src_uv + OFF,                                   \
427           2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X), DOY ? dst_y_opt : NULL,        \
428           kWidth, dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_opt,          \
429           SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight);                  \
430     }                                                                          \
431     int max_diff = 0;                                                          \
432     if (DOY) {                                                                 \
433       for (int i = 0; i < kHeight; ++i) {                                      \
434         for (int j = 0; j < kWidth; ++j) {                                     \
435           int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) -       \
436                              static_cast<int>(dst_y_opt[i * kWidth + j]));     \
437           if (abs_diff > max_diff) {                                           \
438             max_diff = abs_diff;                                               \
439           }                                                                    \
440         }                                                                      \
441       }                                                                        \
442       EXPECT_LE(max_diff, 1);                                                  \
443     }                                                                          \
444     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                  \
445       for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) {                 \
446         int abs_diff = abs(                                                    \
447             static_cast<int>(dst_u_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) -  \
448             static_cast<int>(                                                  \
449                 dst_u_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]));             \
450         if (abs_diff > max_diff) {                                             \
451           max_diff = abs_diff;                                                 \
452         }                                                                      \
453       }                                                                        \
454     }                                                                          \
455     EXPECT_LE(max_diff, 1);                                                    \
456     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                  \
457       for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) {                 \
458         int abs_diff = abs(                                                    \
459             static_cast<int>(dst_v_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) -  \
460             static_cast<int>(                                                  \
461                 dst_v_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]));             \
462         if (abs_diff > max_diff) {                                             \
463           max_diff = abs_diff;                                                 \
464         }                                                                      \
465       }                                                                        \
466     }                                                                          \
467     EXPECT_LE(max_diff, 1);                                                    \
468     free_aligned_buffer_page_end(dst_y_c);                                     \
469     free_aligned_buffer_page_end(dst_u_c);                                     \
470     free_aligned_buffer_page_end(dst_v_c);                                     \
471     free_aligned_buffer_page_end(dst_y_opt);                                   \
472     free_aligned_buffer_page_end(dst_u_opt);                                   \
473     free_aligned_buffer_page_end(dst_v_opt);                                   \
474     free_aligned_buffer_page_end(src_y);                                       \
475     free_aligned_buffer_page_end(src_uv);                                      \
476   }
477 
478 #define TESTBIPLANARTOP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,         \
479                         FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y)                     \
480   TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR,  \
481                    SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0, 1) \
482   TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR,  \
483                    SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Unaligned, +, 1,  \
484                    1)                                                         \
485   TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR,  \
486                    SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0, 1)  \
487   TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR,  \
488                    SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0, 1)     \
489   TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR,  \
490                    SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _NullY, +, 0, 0)
491 
492 TESTBIPLANARTOP(NV12, 2, 2, I420, 2, 2)
493 TESTBIPLANARTOP(NV21, 2, 2, I420, 2, 2)
494 
495 #define ALIGNINT(V, ALIGN) (((V) + (ALIGN)-1) / (ALIGN) * (ALIGN))
496 
497 #define TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
498                        YALIGN, W1280, N, NEG, OFF)                            \
499   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                       \
500     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                           \
501     const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                  \
502     const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                     \
503     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                       \
504     const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);            \
505     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                      \
506     align_buffer_page_end(src_u, kSizeUV + OFF);                              \
507     align_buffer_page_end(src_v, kSizeUV + OFF);                              \
508     align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF);               \
509     align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF);             \
510     for (int i = 0; i < kWidth * kHeight; ++i) {                              \
511       src_y[i + OFF] = (fastrand() & 0xff);                                   \
512     }                                                                         \
513     for (int i = 0; i < kSizeUV; ++i) {                                       \
514       src_u[i + OFF] = (fastrand() & 0xff);                                   \
515       src_v[i + OFF] = (fastrand() & 0xff);                                   \
516     }                                                                         \
517     memset(dst_argb_c + OFF, 1, kStrideB * kHeight);                          \
518     memset(dst_argb_opt + OFF, 101, kStrideB * kHeight);                      \
519     MaskCpuFlags(disable_cpu_flags_);                                         \
520     double time0 = get_time();                                                \
521     FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV,        \
522                           src_v + OFF, kStrideUV, dst_argb_c + OFF, kStrideB, \
523                           kWidth, NEG kHeight);                               \
524     double time1 = get_time();                                                \
525     MaskCpuFlags(benchmark_cpu_info_);                                        \
526     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
527       FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV,      \
528                             src_v + OFF, kStrideUV, dst_argb_opt + OFF,       \
529                             kStrideB, kWidth, NEG kHeight);                   \
530     }                                                                         \
531     double time2 = get_time();                                                \
532     printf(" %8d us C - %8d us OPT\n",                                        \
533            static_cast<int>((time1 - time0) * 1e6),                           \
534            static_cast<int>((time2 - time1) * 1e6 / benchmark_iterations_));  \
535     for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) {                      \
536       EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_opt[i + OFF]);                  \
537     }                                                                         \
538     free_aligned_buffer_page_end(src_y);                                      \
539     free_aligned_buffer_page_end(src_u);                                      \
540     free_aligned_buffer_page_end(src_v);                                      \
541     free_aligned_buffer_page_end(dst_argb_c);                                 \
542     free_aligned_buffer_page_end(dst_argb_opt);                               \
543   }
544 
545 #define TESTPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
546                       YALIGN)                                                \
547   TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
548                  YALIGN, benchmark_width_ - 4, _Any, +, 0)                   \
549   TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
550                  YALIGN, benchmark_width_, _Unaligned, +, 1)                 \
551   TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
552                  YALIGN, benchmark_width_, _Invert, -, 0)                    \
553   TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
554                  YALIGN, benchmark_width_, _Opt, +, 0)
555 
556 TESTPLANARTOB(I420, 2, 2, ARGB, 4, 4, 1)
557 TESTPLANARTOB(J420, 2, 2, ARGB, 4, 4, 1)
558 TESTPLANARTOB(J420, 2, 2, ABGR, 4, 4, 1)
559 TESTPLANARTOB(H420, 2, 2, ARGB, 4, 4, 1)
560 TESTPLANARTOB(H420, 2, 2, ABGR, 4, 4, 1)
561 TESTPLANARTOB(I420, 2, 2, BGRA, 4, 4, 1)
562 TESTPLANARTOB(I420, 2, 2, ABGR, 4, 4, 1)
563 TESTPLANARTOB(I420, 2, 2, RGBA, 4, 4, 1)
564 TESTPLANARTOB(I420, 2, 2, RAW, 3, 3, 1)
565 TESTPLANARTOB(I420, 2, 2, RGB24, 3, 3, 1)
566 TESTPLANARTOB(H420, 2, 2, RAW, 3, 3, 1)
567 TESTPLANARTOB(H420, 2, 2, RGB24, 3, 3, 1)
568 TESTPLANARTOB(I420, 2, 2, RGB565, 2, 2, 1)
569 TESTPLANARTOB(I420, 2, 2, ARGB1555, 2, 2, 1)
570 TESTPLANARTOB(I420, 2, 2, ARGB4444, 2, 2, 1)
571 TESTPLANARTOB(I422, 2, 1, ARGB, 4, 4, 1)
572 TESTPLANARTOB(I422, 2, 1, RGB565, 2, 2, 1)
573 TESTPLANARTOB(J422, 2, 1, ARGB, 4, 4, 1)
574 TESTPLANARTOB(J422, 2, 1, ABGR, 4, 4, 1)
575 TESTPLANARTOB(H422, 2, 1, ARGB, 4, 4, 1)
576 TESTPLANARTOB(H422, 2, 1, ABGR, 4, 4, 1)
577 TESTPLANARTOB(I422, 2, 1, BGRA, 4, 4, 1)
578 TESTPLANARTOB(I422, 2, 1, ABGR, 4, 4, 1)
579 TESTPLANARTOB(I422, 2, 1, RGBA, 4, 4, 1)
580 TESTPLANARTOB(I444, 1, 1, ARGB, 4, 4, 1)
581 TESTPLANARTOB(J444, 1, 1, ARGB, 4, 4, 1)
582 TESTPLANARTOB(I444, 1, 1, ABGR, 4, 4, 1)
583 TESTPLANARTOB(I420, 2, 2, YUY2, 2, 4, 1)
584 TESTPLANARTOB(I420, 2, 2, UYVY, 2, 4, 1)
585 TESTPLANARTOB(I422, 2, 1, YUY2, 2, 4, 1)
586 TESTPLANARTOB(I422, 2, 1, UYVY, 2, 4, 1)
587 TESTPLANARTOB(I420, 2, 2, I400, 1, 1, 1)
588 TESTPLANARTOB(J420, 2, 2, J400, 1, 1, 1)
589 TESTPLANARTOB(I420, 2, 2, AR30, 4, 4, 1)
590 TESTPLANARTOB(H420, 2, 2, AR30, 4, 4, 1)
591 
592 #define TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
593                         YALIGN, W1280, DIFF, N, NEG, OFF, ATTEN)               \
594   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                        \
595     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
596     const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                   \
597     const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                      \
598     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                        \
599     const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);             \
600     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
601     align_buffer_page_end(src_u, kSizeUV + OFF);                               \
602     align_buffer_page_end(src_v, kSizeUV + OFF);                               \
603     align_buffer_page_end(src_a, kWidth* kHeight + OFF);                       \
604     align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF);                \
605     align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF);              \
606     for (int i = 0; i < kWidth * kHeight; ++i) {                               \
607       src_y[i + OFF] = (fastrand() & 0xff);                                    \
608       src_a[i + OFF] = (fastrand() & 0xff);                                    \
609     }                                                                          \
610     for (int i = 0; i < kSizeUV; ++i) {                                        \
611       src_u[i + OFF] = (fastrand() & 0xff);                                    \
612       src_v[i + OFF] = (fastrand() & 0xff);                                    \
613     }                                                                          \
614     memset(dst_argb_c + OFF, 1, kStrideB * kHeight);                           \
615     memset(dst_argb_opt + OFF, 101, kStrideB * kHeight);                       \
616     MaskCpuFlags(disable_cpu_flags_);                                          \
617     FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV,         \
618                           src_v + OFF, kStrideUV, src_a + OFF, kWidth,         \
619                           dst_argb_c + OFF, kStrideB, kWidth, NEG kHeight,     \
620                           ATTEN);                                              \
621     MaskCpuFlags(benchmark_cpu_info_);                                         \
622     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
623       FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV,       \
624                             src_v + OFF, kStrideUV, src_a + OFF, kWidth,       \
625                             dst_argb_opt + OFF, kStrideB, kWidth, NEG kHeight, \
626                             ATTEN);                                            \
627     }                                                                          \
628     int max_diff = 0;                                                          \
629     for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) {                       \
630       int abs_diff = abs(static_cast<int>(dst_argb_c[i + OFF]) -               \
631                          static_cast<int>(dst_argb_opt[i + OFF]));             \
632       if (abs_diff > max_diff) {                                               \
633         max_diff = abs_diff;                                                   \
634       }                                                                        \
635     }                                                                          \
636     EXPECT_LE(max_diff, DIFF);                                                 \
637     free_aligned_buffer_page_end(src_y);                                       \
638     free_aligned_buffer_page_end(src_u);                                       \
639     free_aligned_buffer_page_end(src_v);                                       \
640     free_aligned_buffer_page_end(src_a);                                       \
641     free_aligned_buffer_page_end(dst_argb_c);                                  \
642     free_aligned_buffer_page_end(dst_argb_opt);                                \
643   }
644 
645 #define TESTQPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
646                        YALIGN, DIFF)                                          \
647   TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
648                   YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, 0)          \
649   TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
650                   YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, 0)        \
651   TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
652                   YALIGN, benchmark_width_, DIFF, _Invert, -, 0, 0)           \
653   TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
654                   YALIGN, benchmark_width_, DIFF, _Opt, +, 0, 0)              \
655   TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
656                   YALIGN, benchmark_width_, DIFF, _Premult, +, 0, 1)
657 
658 TESTQPLANARTOB(I420Alpha, 2, 2, ARGB, 4, 4, 1, 2)
659 TESTQPLANARTOB(I420Alpha, 2, 2, ABGR, 4, 4, 1, 2)
660 
661 #define TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,       \
662                          W1280, DIFF, N, NEG, OFF)                             \
663   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                        \
664     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
665     const int kHeight = benchmark_height_;                                     \
666     const int kStrideB = kWidth * BPP_B;                                       \
667     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                        \
668     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
669     align_buffer_page_end(src_uv,                                              \
670                           kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y) * 2 + OFF); \
671     align_buffer_page_end(dst_argb_c, kStrideB* kHeight);                      \
672     align_buffer_page_end(dst_argb_opt, kStrideB* kHeight);                    \
673     for (int i = 0; i < kHeight; ++i)                                          \
674       for (int j = 0; j < kWidth; ++j)                                         \
675         src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                     \
676     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                  \
677       for (int j = 0; j < kStrideUV * 2; ++j) {                                \
678         src_uv[i * kStrideUV * 2 + j + OFF] = (fastrand() & 0xff);             \
679       }                                                                        \
680     }                                                                          \
681     memset(dst_argb_c, 1, kStrideB* kHeight);                                  \
682     memset(dst_argb_opt, 101, kStrideB* kHeight);                              \
683     MaskCpuFlags(disable_cpu_flags_);                                          \
684     FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_uv + OFF, kStrideUV * 2,    \
685                           dst_argb_c, kWidth * BPP_B, kWidth, NEG kHeight);    \
686     MaskCpuFlags(benchmark_cpu_info_);                                         \
687     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
688       FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_uv + OFF, kStrideUV * 2,  \
689                             dst_argb_opt, kWidth * BPP_B, kWidth,              \
690                             NEG kHeight);                                      \
691     }                                                                          \
692     /* Convert to ARGB so 565 is expanded to bytes that can be compared. */    \
693     align_buffer_page_end(dst_argb32_c, kWidth * 4 * kHeight);                 \
694     align_buffer_page_end(dst_argb32_opt, kWidth * 4 * kHeight);               \
695     memset(dst_argb32_c, 2, kWidth * 4 * kHeight);                             \
696     memset(dst_argb32_opt, 102, kWidth * 4 * kHeight);                         \
697     FMT_B##ToARGB(dst_argb_c, kStrideB, dst_argb32_c, kWidth * 4, kWidth,      \
698                   kHeight);                                                    \
699     FMT_B##ToARGB(dst_argb_opt, kStrideB, dst_argb32_opt, kWidth * 4, kWidth,  \
700                   kHeight);                                                    \
701     int max_diff = 0;                                                          \
702     for (int i = 0; i < kHeight; ++i) {                                        \
703       for (int j = 0; j < kWidth * 4; ++j) {                                   \
704         int abs_diff =                                                         \
705             abs(static_cast<int>(dst_argb32_c[i * kWidth * 4 + j]) -           \
706                 static_cast<int>(dst_argb32_opt[i * kWidth * 4 + j]));         \
707         if (abs_diff > max_diff) {                                             \
708           max_diff = abs_diff;                                                 \
709         }                                                                      \
710       }                                                                        \
711     }                                                                          \
712     EXPECT_LE(max_diff, DIFF);                                                 \
713     free_aligned_buffer_page_end(src_y);                                       \
714     free_aligned_buffer_page_end(src_uv);                                      \
715     free_aligned_buffer_page_end(dst_argb_c);                                  \
716     free_aligned_buffer_page_end(dst_argb_opt);                                \
717     free_aligned_buffer_page_end(dst_argb32_c);                                \
718     free_aligned_buffer_page_end(dst_argb32_opt);                              \
719   }
720 
721 #define TESTBIPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, DIFF) \
722   TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,            \
723                    benchmark_width_ - 4, DIFF, _Any, +, 0)                    \
724   TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,            \
725                    benchmark_width_, DIFF, _Unaligned, +, 1)                  \
726   TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,            \
727                    benchmark_width_, DIFF, _Invert, -, 0)                     \
728   TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,            \
729                    benchmark_width_, DIFF, _Opt, +, 0)
730 
731 TESTBIPLANARTOB(NV12, 2, 2, ARGB, 4, 2)
732 TESTBIPLANARTOB(NV21, 2, 2, ARGB, 4, 2)
733 TESTBIPLANARTOB(NV12, 2, 2, ABGR, 4, 2)
734 TESTBIPLANARTOB(NV21, 2, 2, ABGR, 4, 2)
735 TESTBIPLANARTOB(NV12, 2, 2, RGB24, 3, 2)
736 TESTBIPLANARTOB(NV21, 2, 2, RGB24, 3, 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 TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2, ARM_YUV_ERROR)
866 TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1, ARM_YUV_ERROR)
867 TESTATOPLANAR(BGRA, 4, 1, I420, 2, 2, 4)
868 TESTATOPLANAR(ABGR, 4, 1, I420, 2, 2, 4)
869 TESTATOPLANAR(RGBA, 4, 1, I420, 2, 2, 4)
870 TESTATOPLANAR(RAW, 3, 1, I420, 2, 2, 4)
871 TESTATOPLANAR(RGB24, 3, 1, I420, 2, 2, 4)
872 TESTATOPLANAR(RGB565, 2, 1, I420, 2, 2, 5)
873 // TODO(fbarchard): Make 1555 neon work same as C code, reduce to diff 9.
874 TESTATOPLANAR(ARGB1555, 2, 1, I420, 2, 2, 15)
875 TESTATOPLANAR(ARGB4444, 2, 1, I420, 2, 2, 17)
876 TESTATOPLANAR(ARGB, 4, 1, I422, 2, 1, 2)
877 TESTATOPLANAR(ARGB, 4, 1, I444, 1, 1, 2)
878 TESTATOPLANAR(YUY2, 2, 1, I420, 2, 2, 2)
879 TESTATOPLANAR(UYVY, 2, 1, I420, 2, 2, 2)
880 TESTATOPLANAR(YUY2, 2, 1, I422, 2, 1, 2)
881 TESTATOPLANAR(UYVY, 2, 1, I422, 2, 1, 2)
882 TESTATOPLANAR(I400, 1, 1, I420, 2, 2, 2)
883 TESTATOPLANAR(J400, 1, 1, J420, 2, 2, 2)
884 
885 #define TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X,          \
886                          SUBSAMP_Y, W1280, N, NEG, OFF)                       \
887   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) {                       \
888     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                           \
889     const int kHeight = benchmark_height_;                                    \
890     const int kStride = SUBSAMPLE(kWidth, SUB_A) * BPP_A;                     \
891     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                       \
892     align_buffer_page_end(src_argb, kStride* kHeight + OFF);                  \
893     align_buffer_page_end(dst_y_c, kWidth* kHeight);                          \
894     align_buffer_page_end(dst_uv_c,                                           \
895                           kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));     \
896     align_buffer_page_end(dst_y_opt, kWidth* kHeight);                        \
897     align_buffer_page_end(dst_uv_opt,                                         \
898                           kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));     \
899     for (int i = 0; i < kHeight; ++i)                                         \
900       for (int j = 0; j < kStride; ++j)                                       \
901         src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff);              \
902     memset(dst_y_c, 1, kWidth* kHeight);                                      \
903     memset(dst_uv_c, 2, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));       \
904     memset(dst_y_opt, 101, kWidth* kHeight);                                  \
905     memset(dst_uv_opt, 102, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));   \
906     MaskCpuFlags(disable_cpu_flags_);                                         \
907     FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_c, kWidth, dst_uv_c, \
908                           kStrideUV * 2, kWidth, NEG kHeight);                \
909     MaskCpuFlags(benchmark_cpu_info_);                                        \
910     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
911       FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_opt, kWidth,       \
912                             dst_uv_opt, kStrideUV * 2, kWidth, NEG kHeight);  \
913     }                                                                         \
914     int max_diff = 0;                                                         \
915     for (int i = 0; i < kHeight; ++i) {                                       \
916       for (int j = 0; j < kWidth; ++j) {                                      \
917         int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) -        \
918                            static_cast<int>(dst_y_opt[i * kWidth + j]));      \
919         if (abs_diff > max_diff) {                                            \
920           max_diff = abs_diff;                                                \
921         }                                                                     \
922       }                                                                       \
923     }                                                                         \
924     EXPECT_LE(max_diff, 4);                                                   \
925     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                 \
926       for (int j = 0; j < kStrideUV * 2; ++j) {                               \
927         int abs_diff =                                                        \
928             abs(static_cast<int>(dst_uv_c[i * kStrideUV * 2 + j]) -           \
929                 static_cast<int>(dst_uv_opt[i * kStrideUV * 2 + j]));         \
930         if (abs_diff > max_diff) {                                            \
931           max_diff = abs_diff;                                                \
932         }                                                                     \
933       }                                                                       \
934     }                                                                         \
935     EXPECT_LE(max_diff, 4);                                                   \
936     free_aligned_buffer_page_end(dst_y_c);                                    \
937     free_aligned_buffer_page_end(dst_uv_c);                                   \
938     free_aligned_buffer_page_end(dst_y_opt);                                  \
939     free_aligned_buffer_page_end(dst_uv_opt);                                 \
940     free_aligned_buffer_page_end(src_argb);                                   \
941   }
942 
943 #define TESTATOBIPLANAR(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \
944   TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
945                    benchmark_width_ - 4, _Any, +, 0)                           \
946   TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
947                    benchmark_width_, _Unaligned, +, 1)                         \
948   TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
949                    benchmark_width_, _Invert, -, 0)                            \
950   TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
951                    benchmark_width_, _Opt, +, 0)
952 
953 TESTATOBIPLANAR(ARGB, 1, 4, NV12, 2, 2)
954 TESTATOBIPLANAR(ARGB, 1, 4, NV21, 2, 2)
955 TESTATOBIPLANAR(YUY2, 2, 4, NV12, 2, 2)
956 TESTATOBIPLANAR(UYVY, 2, 4, NV12, 2, 2)
957 
958 #define TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,  \
959                   HEIGHT_B, W1280, DIFF, N, NEG, OFF)                        \
960   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##N) {                           \
961     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                          \
962     const int kHeight = benchmark_height_;                                   \
963     const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;     \
964     const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B;     \
965     const int kStrideA =                                                     \
966         (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;               \
967     const int kStrideB =                                                     \
968         (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;               \
969     align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF);               \
970     align_buffer_page_end(dst_argb_c, kStrideB* kHeightB);                   \
971     align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB);                 \
972     for (int i = 0; i < kStrideA * kHeightA; ++i) {                          \
973       src_argb[i + OFF] = (fastrand() & 0xff);                               \
974     }                                                                        \
975     memset(dst_argb_c, 1, kStrideB* kHeightB);                               \
976     memset(dst_argb_opt, 101, kStrideB* kHeightB);                           \
977     MaskCpuFlags(disable_cpu_flags_);                                        \
978     FMT_A##To##FMT_B(src_argb + OFF, kStrideA, dst_argb_c, kStrideB, kWidth, \
979                      NEG kHeight);                                           \
980     MaskCpuFlags(benchmark_cpu_info_);                                       \
981     for (int i = 0; i < benchmark_iterations_; ++i) {                        \
982       FMT_A##To##FMT_B(src_argb + OFF, kStrideA, dst_argb_opt, kStrideB,     \
983                        kWidth, NEG kHeight);                                 \
984     }                                                                        \
985     int max_diff = 0;                                                        \
986     for (int i = 0; i < kStrideB * kHeightB; ++i) {                          \
987       int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -                   \
988                          static_cast<int>(dst_argb_opt[i]));                 \
989       if (abs_diff > max_diff) {                                             \
990         max_diff = abs_diff;                                                 \
991       }                                                                      \
992     }                                                                        \
993     EXPECT_LE(max_diff, DIFF);                                               \
994     free_aligned_buffer_page_end(src_argb);                                  \
995     free_aligned_buffer_page_end(dst_argb_c);                                \
996     free_aligned_buffer_page_end(dst_argb_opt);                              \
997   }
998 
999 #define TESTATOBRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B,     \
1000                        STRIDE_B, HEIGHT_B, DIFF)                           \
1001   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##_Random) {                   \
1002     for (int times = 0; times < benchmark_iterations_; ++times) {          \
1003       const int kWidth = (fastrand() & 63) + 1;                            \
1004       const int kHeight = (fastrand() & 31) + 1;                           \
1005       const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
1006       const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B; \
1007       const int kStrideA =                                                 \
1008           (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;           \
1009       const int kStrideB =                                                 \
1010           (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;           \
1011       align_buffer_page_end(src_argb, kStrideA* kHeightA);                 \
1012       align_buffer_page_end(dst_argb_c, kStrideB* kHeightB);               \
1013       align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB);             \
1014       for (int i = 0; i < kStrideA * kHeightA; ++i) {                      \
1015         src_argb[i] = (fastrand() & 0xff);                                 \
1016       }                                                                    \
1017       memset(dst_argb_c, 123, kStrideB* kHeightB);                         \
1018       memset(dst_argb_opt, 123, kStrideB* kHeightB);                       \
1019       MaskCpuFlags(disable_cpu_flags_);                                    \
1020       FMT_A##To##FMT_B(src_argb, kStrideA, dst_argb_c, kStrideB, kWidth,   \
1021                        kHeight);                                           \
1022       MaskCpuFlags(benchmark_cpu_info_);                                   \
1023       FMT_A##To##FMT_B(src_argb, kStrideA, dst_argb_opt, kStrideB, kWidth, \
1024                        kHeight);                                           \
1025       int max_diff = 0;                                                    \
1026       for (int i = 0; i < kStrideB * kHeightB; ++i) {                      \
1027         int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -               \
1028                            static_cast<int>(dst_argb_opt[i]));             \
1029         if (abs_diff > max_diff) {                                         \
1030           max_diff = abs_diff;                                             \
1031         }                                                                  \
1032       }                                                                    \
1033       EXPECT_LE(max_diff, DIFF);                                           \
1034       free_aligned_buffer_page_end(src_argb);                              \
1035       free_aligned_buffer_page_end(dst_argb_c);                            \
1036       free_aligned_buffer_page_end(dst_argb_opt);                          \
1037     }                                                                      \
1038   }
1039 
1040 #define TESTATOB(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1041                  HEIGHT_B, DIFF)                                           \
1042   TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1043             HEIGHT_B, benchmark_width_ - 4, DIFF, _Any, +, 0)              \
1044   TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1045             HEIGHT_B, benchmark_width_, DIFF, _Unaligned, +, 1)            \
1046   TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1047             HEIGHT_B, benchmark_width_, DIFF, _Invert, -, 0)               \
1048   TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1049             HEIGHT_B, benchmark_width_, DIFF, _Opt, +, 0)                  \
1050   TESTATOBRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1051                  HEIGHT_B, DIFF)
1052 
1053 TESTATOB(ARGB, 4, 4, 1, ARGB, 4, 4, 1, 0)
1054 TESTATOB(ARGB, 4, 4, 1, BGRA, 4, 4, 1, 0)
1055 TESTATOB(ARGB, 4, 4, 1, ABGR, 4, 4, 1, 0)
1056 TESTATOB(ARGB, 4, 4, 1, RGBA, 4, 4, 1, 0)
1057 TESTATOB(ARGB, 4, 4, 1, RAW, 3, 3, 1, 0)
1058 TESTATOB(ARGB, 4, 4, 1, RGB24, 3, 3, 1, 0)
1059 TESTATOB(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0)
1060 TESTATOB(ARGB, 4, 4, 1, ARGB1555, 2, 2, 1, 0)
1061 TESTATOB(ARGB, 4, 4, 1, ARGB4444, 2, 2, 1, 0)
1062 TESTATOB(ABGR, 4, 4, 1, AR30, 4, 4, 1, 0)
1063 TESTATOB(ARGB, 4, 4, 1, AR30, 4, 4, 1, 0)
1064 TESTATOB(ARGB, 4, 4, 1, YUY2, 2, 4, 1, 4)
1065 TESTATOB(ARGB, 4, 4, 1, UYVY, 2, 4, 1, 4)
1066 TESTATOB(ARGB, 4, 4, 1, I400, 1, 1, 1, 2)
1067 TESTATOB(ARGB, 4, 4, 1, J400, 1, 1, 1, 2)
1068 TESTATOB(BGRA, 4, 4, 1, ARGB, 4, 4, 1, 0)
1069 TESTATOB(ABGR, 4, 4, 1, ARGB, 4, 4, 1, 0)
1070 TESTATOB(RGBA, 4, 4, 1, ARGB, 4, 4, 1, 0)
1071 TESTATOB(AR30, 4, 4, 1, AR30, 4, 4, 1, 0)
1072 TESTATOB(RAW, 3, 3, 1, ARGB, 4, 4, 1, 0)
1073 TESTATOB(RAW, 3, 3, 1, RGB24, 3, 3, 1, 0)
1074 TESTATOB(RGB24, 3, 3, 1, ARGB, 4, 4, 1, 0)
1075 TESTATOB(RGB565, 2, 2, 1, ARGB, 4, 4, 1, 0)
1076 TESTATOB(ARGB1555, 2, 2, 1, ARGB, 4, 4, 1, 0)
1077 TESTATOB(ARGB4444, 2, 2, 1, ARGB, 4, 4, 1, 0)
1078 TESTATOB(AR30, 4, 4, 1, ARGB, 4, 4, 1, 0)
1079 TESTATOB(AR30, 4, 4, 1, ABGR, 4, 4, 1, 0)
1080 TESTATOB(AB30, 4, 4, 1, ARGB, 4, 4, 1, 0)
1081 TESTATOB(AB30, 4, 4, 1, ABGR, 4, 4, 1, 0)
1082 TESTATOB(AR30, 4, 4, 1, AB30, 4, 4, 1, 0)
1083 TESTATOB(YUY2, 2, 4, 1, ARGB, 4, 4, 1, ARM_YUV_ERROR)
1084 TESTATOB(UYVY, 2, 4, 1, ARGB, 4, 4, 1, ARM_YUV_ERROR)
1085 TESTATOB(YUY2, 2, 4, 1, Y, 1, 1, 1, 0)
1086 TESTATOB(I400, 1, 1, 1, ARGB, 4, 4, 1, 0)
1087 TESTATOB(J400, 1, 1, 1, ARGB, 4, 4, 1, 0)
1088 TESTATOB(I400, 1, 1, 1, I400, 1, 1, 1, 0)
1089 TESTATOB(J400, 1, 1, 1, J400, 1, 1, 1, 0)
1090 TESTATOB(I400, 1, 1, 1, I400Mirror, 1, 1, 1, 0)
1091 TESTATOB(ARGB, 4, 4, 1, ARGBMirror, 4, 4, 1, 0)
1092 
1093 #define TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1094                    HEIGHT_B, W1280, DIFF, N, NEG, OFF)                       \
1095   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##Dither##N) {                   \
1096     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                          \
1097     const int kHeight = benchmark_height_;                                   \
1098     const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;     \
1099     const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B;     \
1100     const int kStrideA =                                                     \
1101         (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;               \
1102     const int kStrideB =                                                     \
1103         (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;               \
1104     align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF);               \
1105     align_buffer_page_end(dst_argb_c, kStrideB* kHeightB);                   \
1106     align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB);                 \
1107     for (int i = 0; i < kStrideA * kHeightA; ++i) {                          \
1108       src_argb[i + OFF] = (fastrand() & 0xff);                               \
1109     }                                                                        \
1110     memset(dst_argb_c, 1, kStrideB* kHeightB);                               \
1111     memset(dst_argb_opt, 101, kStrideB* kHeightB);                           \
1112     MaskCpuFlags(disable_cpu_flags_);                                        \
1113     FMT_A##To##FMT_B##Dither(src_argb + OFF, kStrideA, dst_argb_c, kStrideB, \
1114                              NULL, kWidth, NEG kHeight);                     \
1115     MaskCpuFlags(benchmark_cpu_info_);                                       \
1116     for (int i = 0; i < benchmark_iterations_; ++i) {                        \
1117       FMT_A##To##FMT_B##Dither(src_argb + OFF, kStrideA, dst_argb_opt,       \
1118                                kStrideB, NULL, kWidth, NEG kHeight);         \
1119     }                                                                        \
1120     int max_diff = 0;                                                        \
1121     for (int i = 0; i < kStrideB * kHeightB; ++i) {                          \
1122       int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -                   \
1123                          static_cast<int>(dst_argb_opt[i]));                 \
1124       if (abs_diff > max_diff) {                                             \
1125         max_diff = abs_diff;                                                 \
1126       }                                                                      \
1127     }                                                                        \
1128     EXPECT_LE(max_diff, DIFF);                                               \
1129     free_aligned_buffer_page_end(src_argb);                                  \
1130     free_aligned_buffer_page_end(dst_argb_c);                                \
1131     free_aligned_buffer_page_end(dst_argb_opt);                              \
1132   }
1133 
1134 #define TESTATOBDRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B,        \
1135                         STRIDE_B, HEIGHT_B, DIFF)                              \
1136   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##Dither_Random) {                 \
1137     for (int times = 0; times < benchmark_iterations_; ++times) {              \
1138       const int kWidth = (fastrand() & 63) + 1;                                \
1139       const int kHeight = (fastrand() & 31) + 1;                               \
1140       const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;     \
1141       const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B;     \
1142       const int kStrideA =                                                     \
1143           (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;               \
1144       const int kStrideB =                                                     \
1145           (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;               \
1146       align_buffer_page_end(src_argb, kStrideA* kHeightA);                     \
1147       align_buffer_page_end(dst_argb_c, kStrideB* kHeightB);                   \
1148       align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB);                 \
1149       for (int i = 0; i < kStrideA * kHeightA; ++i) {                          \
1150         src_argb[i] = (fastrand() & 0xff);                                     \
1151       }                                                                        \
1152       memset(dst_argb_c, 123, kStrideB* kHeightB);                             \
1153       memset(dst_argb_opt, 123, kStrideB* kHeightB);                           \
1154       MaskCpuFlags(disable_cpu_flags_);                                        \
1155       FMT_A##To##FMT_B##Dither(src_argb, kStrideA, dst_argb_c, kStrideB, NULL, \
1156                                kWidth, kHeight);                               \
1157       MaskCpuFlags(benchmark_cpu_info_);                                       \
1158       FMT_A##To##FMT_B##Dither(src_argb, kStrideA, dst_argb_opt, kStrideB,     \
1159                                NULL, kWidth, kHeight);                         \
1160       int max_diff = 0;                                                        \
1161       for (int i = 0; i < kStrideB * kHeightB; ++i) {                          \
1162         int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -                   \
1163                            static_cast<int>(dst_argb_opt[i]));                 \
1164         if (abs_diff > max_diff) {                                             \
1165           max_diff = abs_diff;                                                 \
1166         }                                                                      \
1167       }                                                                        \
1168       EXPECT_LE(max_diff, DIFF);                                               \
1169       free_aligned_buffer_page_end(src_argb);                                  \
1170       free_aligned_buffer_page_end(dst_argb_c);                                \
1171       free_aligned_buffer_page_end(dst_argb_opt);                              \
1172     }                                                                          \
1173   }
1174 
1175 #define TESTATOBD(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1176                   HEIGHT_B, DIFF)                                           \
1177   TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1178              HEIGHT_B, benchmark_width_ - 4, DIFF, _Any, +, 0)              \
1179   TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1180              HEIGHT_B, benchmark_width_, DIFF, _Unaligned, +, 1)            \
1181   TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1182              HEIGHT_B, benchmark_width_, DIFF, _Invert, -, 0)               \
1183   TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1184              HEIGHT_B, benchmark_width_, DIFF, _Opt, +, 0)                  \
1185   TESTATOBDRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1186                   HEIGHT_B, DIFF)
1187 
1188 TESTATOBD(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0)
1189 
1190 #define TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, W1280, N, NEG, OFF)      \
1191   TEST_F(LibYUVConvertTest, FMT_ATOB##_Symetric##N) {                          \
1192     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
1193     const int kHeight = benchmark_height_;                                     \
1194     const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;       \
1195     const int kStrideA =                                                       \
1196         (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;                 \
1197     align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF);                 \
1198     align_buffer_page_end(dst_argb_c, kStrideA* kHeightA);                     \
1199     align_buffer_page_end(dst_argb_opt, kStrideA* kHeightA);                   \
1200     for (int i = 0; i < kStrideA * kHeightA; ++i) {                            \
1201       src_argb[i + OFF] = (fastrand() & 0xff);                                 \
1202     }                                                                          \
1203     memset(dst_argb_c, 1, kStrideA* kHeightA);                                 \
1204     memset(dst_argb_opt, 101, kStrideA* kHeightA);                             \
1205     MaskCpuFlags(disable_cpu_flags_);                                          \
1206     FMT_ATOB(src_argb + OFF, kStrideA, dst_argb_c, kStrideA, kWidth,           \
1207              NEG kHeight);                                                     \
1208     MaskCpuFlags(benchmark_cpu_info_);                                         \
1209     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
1210       FMT_ATOB(src_argb + OFF, kStrideA, dst_argb_opt, kStrideA, kWidth,       \
1211                NEG kHeight);                                                   \
1212     }                                                                          \
1213     MaskCpuFlags(disable_cpu_flags_);                                          \
1214     FMT_ATOB(dst_argb_c, kStrideA, dst_argb_c, kStrideA, kWidth, NEG kHeight); \
1215     MaskCpuFlags(benchmark_cpu_info_);                                         \
1216     FMT_ATOB(dst_argb_opt, kStrideA, dst_argb_opt, kStrideA, kWidth,           \
1217              NEG kHeight);                                                     \
1218     for (int i = 0; i < kStrideA * kHeightA; ++i) {                            \
1219       EXPECT_EQ(src_argb[i + OFF], dst_argb_opt[i]);                           \
1220       EXPECT_EQ(dst_argb_c[i], dst_argb_opt[i]);                               \
1221     }                                                                          \
1222     free_aligned_buffer_page_end(src_argb);                                    \
1223     free_aligned_buffer_page_end(dst_argb_c);                                  \
1224     free_aligned_buffer_page_end(dst_argb_opt);                                \
1225   }
1226 
1227 #define TESTSYM(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A)                           \
1228   TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_ - 4, _Any, +, \
1229            0)                                                                  \
1230   TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_, _Unaligned,  \
1231            +, 1)                                                               \
1232   TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_, _Opt, +, 0)
1233 
1234 TESTSYM(ARGBToARGB, 4, 4, 1)
1235 TESTSYM(ARGBToBGRA, 4, 4, 1)
1236 TESTSYM(ARGBToABGR, 4, 4, 1)
1237 TESTSYM(BGRAToARGB, 4, 4, 1)
1238 TESTSYM(ABGRToARGB, 4, 4, 1)
1239 
TEST_F(LibYUVConvertTest,Test565)1240 TEST_F(LibYUVConvertTest, Test565) {
1241   SIMD_ALIGNED(uint8_t orig_pixels[256][4]);
1242   SIMD_ALIGNED(uint8_t pixels565[256][2]);
1243 
1244   for (int i = 0; i < 256; ++i) {
1245     for (int j = 0; j < 4; ++j) {
1246       orig_pixels[i][j] = i;
1247     }
1248   }
1249   ARGBToRGB565(&orig_pixels[0][0], 0, &pixels565[0][0], 0, 256, 1);
1250   uint32_t checksum = HashDjb2(&pixels565[0][0], sizeof(pixels565), 5381);
1251   EXPECT_EQ(610919429u, checksum);
1252 }
1253 
1254 #ifdef HAVE_JPEG
TEST_F(LibYUVConvertTest,ValidateJpeg)1255 TEST_F(LibYUVConvertTest, ValidateJpeg) {
1256   const int kOff = 10;
1257   const int kMinJpeg = 64;
1258   const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1259                              ? benchmark_width_ * benchmark_height_
1260                              : kMinJpeg;
1261   const int kSize = kImageSize + kOff;
1262   align_buffer_page_end(orig_pixels, kSize);
1263 
1264   // No SOI or EOI. Expect fail.
1265   memset(orig_pixels, 0, kSize);
1266   EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1267 
1268   // Test special value that matches marker start.
1269   memset(orig_pixels, 0xff, kSize);
1270   EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1271 
1272   // EOI, SOI. Expect pass.
1273   orig_pixels[0] = 0xff;
1274   orig_pixels[1] = 0xd8;  // SOI.
1275   orig_pixels[kSize - kOff + 0] = 0xff;
1276   orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1277   for (int times = 0; times < benchmark_iterations_; ++times) {
1278     EXPECT_TRUE(ValidateJpeg(orig_pixels, kSize));
1279   }
1280   free_aligned_buffer_page_end(orig_pixels);
1281 }
1282 
TEST_F(LibYUVConvertTest,ValidateJpegLarge)1283 TEST_F(LibYUVConvertTest, ValidateJpegLarge) {
1284   const int kOff = 10;
1285   const int kMinJpeg = 64;
1286   const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1287                              ? benchmark_width_ * benchmark_height_
1288                              : kMinJpeg;
1289   const int kSize = kImageSize + kOff;
1290   const int kMultiple = 10;
1291   const int kBufSize = kImageSize * kMultiple + kOff;
1292   align_buffer_page_end(orig_pixels, kBufSize);
1293 
1294   // No SOI or EOI. Expect fail.
1295   memset(orig_pixels, 0, kBufSize);
1296   EXPECT_FALSE(ValidateJpeg(orig_pixels, kBufSize));
1297 
1298   // EOI, SOI. Expect pass.
1299   orig_pixels[0] = 0xff;
1300   orig_pixels[1] = 0xd8;  // SOI.
1301   orig_pixels[kSize - kOff + 0] = 0xff;
1302   orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1303   for (int times = 0; times < benchmark_iterations_; ++times) {
1304     EXPECT_TRUE(ValidateJpeg(orig_pixels, kBufSize));
1305   }
1306   free_aligned_buffer_page_end(orig_pixels);
1307 }
1308 
TEST_F(LibYUVConvertTest,InvalidateJpeg)1309 TEST_F(LibYUVConvertTest, InvalidateJpeg) {
1310   const int kOff = 10;
1311   const int kMinJpeg = 64;
1312   const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1313                              ? benchmark_width_ * benchmark_height_
1314                              : kMinJpeg;
1315   const int kSize = kImageSize + kOff;
1316   align_buffer_page_end(orig_pixels, kSize);
1317 
1318   // NULL pointer. Expect fail.
1319   EXPECT_FALSE(ValidateJpeg(NULL, kSize));
1320 
1321   // Negative size. Expect fail.
1322   EXPECT_FALSE(ValidateJpeg(orig_pixels, -1));
1323 
1324   // Too large size. Expect fail.
1325   EXPECT_FALSE(ValidateJpeg(orig_pixels, 0xfb000000ull));
1326 
1327   // No SOI or EOI. Expect fail.
1328   memset(orig_pixels, 0, kSize);
1329   EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1330 
1331   // SOI but no EOI. Expect fail.
1332   orig_pixels[0] = 0xff;
1333   orig_pixels[1] = 0xd8;  // SOI.
1334   for (int times = 0; times < benchmark_iterations_; ++times) {
1335     EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1336   }
1337 
1338   // EOI but no SOI. Expect fail.
1339   orig_pixels[0] = 0;
1340   orig_pixels[1] = 0;
1341   orig_pixels[kSize - kOff + 0] = 0xff;
1342   orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1343   EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1344 
1345   free_aligned_buffer_page_end(orig_pixels);
1346 }
1347 
TEST_F(LibYUVConvertTest,FuzzJpeg)1348 TEST_F(LibYUVConvertTest, FuzzJpeg) {
1349   // SOI but no EOI. Expect fail.
1350   for (int times = 0; times < benchmark_iterations_; ++times) {
1351     const int kSize = fastrand() % 5000 + 2;
1352     align_buffer_page_end(orig_pixels, kSize);
1353     MemRandomize(orig_pixels, kSize);
1354 
1355     // Add SOI so frame will be scanned.
1356     orig_pixels[0] = 0xff;
1357     orig_pixels[1] = 0xd8;  // SOI.
1358     orig_pixels[kSize - 1] = 0xff;
1359     ValidateJpeg(orig_pixels, kSize);  // Failure normally expected.
1360     free_aligned_buffer_page_end(orig_pixels);
1361   }
1362 }
1363 
TEST_F(LibYUVConvertTest,MJPGToI420)1364 TEST_F(LibYUVConvertTest, MJPGToI420) {
1365   const int kOff = 10;
1366   const int kMinJpeg = 64;
1367   const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1368                              ? benchmark_width_ * benchmark_height_
1369                              : kMinJpeg;
1370   const int kSize = kImageSize + kOff;
1371   align_buffer_page_end(orig_pixels, kSize);
1372   align_buffer_page_end(dst_y_opt, benchmark_width_ * benchmark_height_);
1373   align_buffer_page_end(dst_u_opt, SUBSAMPLE(benchmark_width_, 2) *
1374                                        SUBSAMPLE(benchmark_height_, 2));
1375   align_buffer_page_end(dst_v_opt, SUBSAMPLE(benchmark_width_, 2) *
1376                                        SUBSAMPLE(benchmark_height_, 2));
1377 
1378   // EOI, SOI to make MJPG appear valid.
1379   memset(orig_pixels, 0, kSize);
1380   orig_pixels[0] = 0xff;
1381   orig_pixels[1] = 0xd8;  // SOI.
1382   orig_pixels[kSize - kOff + 0] = 0xff;
1383   orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1384 
1385   for (int times = 0; times < benchmark_iterations_; ++times) {
1386     int ret =
1387         MJPGToI420(orig_pixels, kSize, dst_y_opt, benchmark_width_, dst_u_opt,
1388                    SUBSAMPLE(benchmark_width_, 2), dst_v_opt,
1389                    SUBSAMPLE(benchmark_width_, 2), benchmark_width_,
1390                    benchmark_height_, benchmark_width_, benchmark_height_);
1391     // Expect failure because image is not really valid.
1392     EXPECT_EQ(1, ret);
1393   }
1394 
1395   free_aligned_buffer_page_end(dst_y_opt);
1396   free_aligned_buffer_page_end(dst_u_opt);
1397   free_aligned_buffer_page_end(dst_v_opt);
1398   free_aligned_buffer_page_end(orig_pixels);
1399 }
1400 
TEST_F(LibYUVConvertTest,MJPGToARGB)1401 TEST_F(LibYUVConvertTest, MJPGToARGB) {
1402   const int kOff = 10;
1403   const int kMinJpeg = 64;
1404   const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1405                              ? benchmark_width_ * benchmark_height_
1406                              : kMinJpeg;
1407   const int kSize = kImageSize + kOff;
1408   align_buffer_page_end(orig_pixels, kSize);
1409   align_buffer_page_end(dst_argb_opt, benchmark_width_ * benchmark_height_ * 4);
1410 
1411   // EOI, SOI to make MJPG appear valid.
1412   memset(orig_pixels, 0, kSize);
1413   orig_pixels[0] = 0xff;
1414   orig_pixels[1] = 0xd8;  // SOI.
1415   orig_pixels[kSize - kOff + 0] = 0xff;
1416   orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1417 
1418   for (int times = 0; times < benchmark_iterations_; ++times) {
1419     int ret = MJPGToARGB(orig_pixels, kSize, dst_argb_opt, benchmark_width_ * 4,
1420                          benchmark_width_, benchmark_height_, benchmark_width_,
1421                          benchmark_height_);
1422     // Expect failure because image is not really valid.
1423     EXPECT_EQ(1, ret);
1424   }
1425 
1426   free_aligned_buffer_page_end(dst_argb_opt);
1427   free_aligned_buffer_page_end(orig_pixels);
1428 }
1429 
1430 #endif  // HAVE_JPEG
1431 
TEST_F(LibYUVConvertTest,NV12Crop)1432 TEST_F(LibYUVConvertTest, NV12Crop) {
1433   const int SUBSAMP_X = 2;
1434   const int SUBSAMP_Y = 2;
1435   const int kWidth = benchmark_width_;
1436   const int kHeight = benchmark_height_;
1437   const int crop_y =
1438       ((benchmark_height_ - (benchmark_height_ * 360 / 480)) / 2 + 1) & ~1;
1439   const int kDestWidth = benchmark_width_;
1440   const int kDestHeight = benchmark_height_ - crop_y * 2;
1441   const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);
1442   const int sample_size =
1443       kWidth * kHeight + kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y) * 2;
1444   align_buffer_page_end(src_y, sample_size);
1445   uint8_t* src_uv = src_y + kWidth * kHeight;
1446 
1447   align_buffer_page_end(dst_y, kDestWidth * kDestHeight);
1448   align_buffer_page_end(dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1449                                    SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1450   align_buffer_page_end(dst_v, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1451                                    SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1452 
1453   align_buffer_page_end(dst_y_2, kDestWidth * kDestHeight);
1454   align_buffer_page_end(dst_u_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1455                                      SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1456   align_buffer_page_end(dst_v_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1457                                      SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1458 
1459   for (int i = 0; i < kHeight * kWidth; ++i) {
1460     src_y[i] = (fastrand() & 0xff);
1461   }
1462   for (int i = 0; i < (SUBSAMPLE(kHeight, SUBSAMP_Y) * kStrideUV) * 2; ++i) {
1463     src_uv[i] = (fastrand() & 0xff);
1464   }
1465   memset(dst_y, 1, kDestWidth * kDestHeight);
1466   memset(dst_u, 2,
1467          SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1468   memset(dst_v, 3,
1469          SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1470   memset(dst_y_2, 1, kDestWidth * kDestHeight);
1471   memset(dst_u_2, 2,
1472          SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1473   memset(dst_v_2, 3,
1474          SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1475 
1476   ConvertToI420(src_y, sample_size, dst_y_2, kDestWidth, dst_u_2,
1477                 SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v_2,
1478                 SUBSAMPLE(kDestWidth, SUBSAMP_X), 0, crop_y, kWidth, kHeight,
1479                 kDestWidth, kDestHeight, libyuv::kRotate0, libyuv::FOURCC_NV12);
1480 
1481   NV12ToI420(src_y + crop_y * kWidth, kWidth,
1482              src_uv + (crop_y / 2) * kStrideUV * 2, kStrideUV * 2, dst_y,
1483              kDestWidth, dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v,
1484              SUBSAMPLE(kDestWidth, SUBSAMP_X), kDestWidth, kDestHeight);
1485 
1486   for (int i = 0; i < kDestHeight; ++i) {
1487     for (int j = 0; j < kDestWidth; ++j) {
1488       EXPECT_EQ(dst_y[i * kWidth + j], dst_y_2[i * kWidth + j]);
1489     }
1490   }
1491   for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
1492     for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
1493       EXPECT_EQ(dst_u[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
1494                 dst_u_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
1495     }
1496   }
1497   for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
1498     for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
1499       EXPECT_EQ(dst_v[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
1500                 dst_v_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
1501     }
1502   }
1503   free_aligned_buffer_page_end(dst_y);
1504   free_aligned_buffer_page_end(dst_u);
1505   free_aligned_buffer_page_end(dst_v);
1506   free_aligned_buffer_page_end(dst_y_2);
1507   free_aligned_buffer_page_end(dst_u_2);
1508   free_aligned_buffer_page_end(dst_v_2);
1509   free_aligned_buffer_page_end(src_y);
1510 }
1511 
TEST_F(LibYUVConvertTest,TestYToARGB)1512 TEST_F(LibYUVConvertTest, TestYToARGB) {
1513   uint8_t y[32];
1514   uint8_t expectedg[32];
1515   for (int i = 0; i < 32; ++i) {
1516     y[i] = i * 5 + 17;
1517     expectedg[i] = static_cast<int>((y[i] - 16) * 1.164f + 0.5f);
1518   }
1519   uint8_t argb[32 * 4];
1520   YToARGB(y, 0, argb, 0, 32, 1);
1521 
1522   for (int i = 0; i < 32; ++i) {
1523     printf("%2d %d: %d <-> %d,%d,%d,%d\n", i, y[i], expectedg[i],
1524            argb[i * 4 + 0], argb[i * 4 + 1], argb[i * 4 + 2], argb[i * 4 + 3]);
1525   }
1526   for (int i = 0; i < 32; ++i) {
1527     EXPECT_EQ(expectedg[i], argb[i * 4 + 0]);
1528   }
1529 }
1530 
1531 static const uint8_t kNoDither4x4[16] = {
1532     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1533 };
1534 
TEST_F(LibYUVConvertTest,TestNoDither)1535 TEST_F(LibYUVConvertTest, TestNoDither) {
1536   align_buffer_page_end(src_argb, benchmark_width_ * benchmark_height_ * 4);
1537   align_buffer_page_end(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1538   align_buffer_page_end(dst_rgb565dither,
1539                         benchmark_width_ * benchmark_height_ * 2);
1540   MemRandomize(src_argb, benchmark_width_ * benchmark_height_ * 4);
1541   MemRandomize(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1542   MemRandomize(dst_rgb565dither, benchmark_width_ * benchmark_height_ * 2);
1543   ARGBToRGB565(src_argb, benchmark_width_ * 4, dst_rgb565, benchmark_width_ * 2,
1544                benchmark_width_, benchmark_height_);
1545   ARGBToRGB565Dither(src_argb, benchmark_width_ * 4, dst_rgb565dither,
1546                      benchmark_width_ * 2, kNoDither4x4, benchmark_width_,
1547                      benchmark_height_);
1548   for (int i = 0; i < benchmark_width_ * benchmark_height_ * 2; ++i) {
1549     EXPECT_EQ(dst_rgb565[i], dst_rgb565dither[i]);
1550   }
1551 
1552   free_aligned_buffer_page_end(src_argb);
1553   free_aligned_buffer_page_end(dst_rgb565);
1554   free_aligned_buffer_page_end(dst_rgb565dither);
1555 }
1556 
1557 // Ordered 4x4 dither for 888 to 565.  Values from 0 to 7.
1558 static const uint8_t kDither565_4x4[16] = {
1559     0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
1560 };
1561 
TEST_F(LibYUVConvertTest,TestDither)1562 TEST_F(LibYUVConvertTest, TestDither) {
1563   align_buffer_page_end(src_argb, benchmark_width_ * benchmark_height_ * 4);
1564   align_buffer_page_end(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1565   align_buffer_page_end(dst_rgb565dither,
1566                         benchmark_width_ * benchmark_height_ * 2);
1567   align_buffer_page_end(dst_argb, benchmark_width_ * benchmark_height_ * 4);
1568   align_buffer_page_end(dst_argbdither,
1569                         benchmark_width_ * benchmark_height_ * 4);
1570   MemRandomize(src_argb, benchmark_width_ * benchmark_height_ * 4);
1571   MemRandomize(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1572   MemRandomize(dst_rgb565dither, benchmark_width_ * benchmark_height_ * 2);
1573   MemRandomize(dst_argb, benchmark_width_ * benchmark_height_ * 4);
1574   MemRandomize(dst_argbdither, benchmark_width_ * benchmark_height_ * 4);
1575   ARGBToRGB565(src_argb, benchmark_width_ * 4, dst_rgb565, benchmark_width_ * 2,
1576                benchmark_width_, benchmark_height_);
1577   ARGBToRGB565Dither(src_argb, benchmark_width_ * 4, dst_rgb565dither,
1578                      benchmark_width_ * 2, kDither565_4x4, benchmark_width_,
1579                      benchmark_height_);
1580   RGB565ToARGB(dst_rgb565, benchmark_width_ * 2, dst_argb, benchmark_width_ * 4,
1581                benchmark_width_, benchmark_height_);
1582   RGB565ToARGB(dst_rgb565dither, benchmark_width_ * 2, dst_argbdither,
1583                benchmark_width_ * 4, benchmark_width_, benchmark_height_);
1584 
1585   for (int i = 0; i < benchmark_width_ * benchmark_height_ * 4; ++i) {
1586     EXPECT_NEAR(dst_argb[i], dst_argbdither[i], 9);
1587   }
1588   free_aligned_buffer_page_end(src_argb);
1589   free_aligned_buffer_page_end(dst_rgb565);
1590   free_aligned_buffer_page_end(dst_rgb565dither);
1591   free_aligned_buffer_page_end(dst_argb);
1592   free_aligned_buffer_page_end(dst_argbdither);
1593 }
1594 
1595 #define TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1596                         YALIGN, W1280, DIFF, N, NEG, OFF, FMT_C, BPP_C)        \
1597   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##Dither##N) {                \
1598     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
1599     const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                   \
1600     const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                      \
1601     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                        \
1602     const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);             \
1603     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
1604     align_buffer_page_end(src_u, kSizeUV + OFF);                               \
1605     align_buffer_page_end(src_v, kSizeUV + OFF);                               \
1606     align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF);                \
1607     align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF);              \
1608     for (int i = 0; i < kWidth * kHeight; ++i) {                               \
1609       src_y[i + OFF] = (fastrand() & 0xff);                                    \
1610     }                                                                          \
1611     for (int i = 0; i < kSizeUV; ++i) {                                        \
1612       src_u[i + OFF] = (fastrand() & 0xff);                                    \
1613       src_v[i + OFF] = (fastrand() & 0xff);                                    \
1614     }                                                                          \
1615     memset(dst_argb_c + OFF, 1, kStrideB * kHeight);                           \
1616     memset(dst_argb_opt + OFF, 101, kStrideB * kHeight);                       \
1617     MaskCpuFlags(disable_cpu_flags_);                                          \
1618     FMT_PLANAR##To##FMT_B##Dither(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
1619                                   src_v + OFF, kStrideUV, dst_argb_c + OFF,    \
1620                                   kStrideB, NULL, kWidth, NEG kHeight);        \
1621     MaskCpuFlags(benchmark_cpu_info_);                                         \
1622     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
1623       FMT_PLANAR##To##FMT_B##Dither(                                           \
1624           src_y + OFF, kWidth, src_u + OFF, kStrideUV, src_v + OFF, kStrideUV, \
1625           dst_argb_opt + OFF, kStrideB, NULL, kWidth, NEG kHeight);            \
1626     }                                                                          \
1627     int max_diff = 0;                                                          \
1628     /* Convert to ARGB so 565 is expanded to bytes that can be compared. */    \
1629     align_buffer_page_end(dst_argb32_c, kWidth* BPP_C* kHeight);               \
1630     align_buffer_page_end(dst_argb32_opt, kWidth* BPP_C* kHeight);             \
1631     memset(dst_argb32_c, 2, kWidth* BPP_C* kHeight);                           \
1632     memset(dst_argb32_opt, 102, kWidth* BPP_C* kHeight);                       \
1633     FMT_B##To##FMT_C(dst_argb_c + OFF, kStrideB, dst_argb32_c, kWidth * BPP_C, \
1634                      kWidth, kHeight);                                         \
1635     FMT_B##To##FMT_C(dst_argb_opt + OFF, kStrideB, dst_argb32_opt,             \
1636                      kWidth * BPP_C, kWidth, kHeight);                         \
1637     for (int i = 0; i < kWidth * BPP_C * kHeight; ++i) {                       \
1638       int abs_diff = abs(static_cast<int>(dst_argb32_c[i]) -                   \
1639                          static_cast<int>(dst_argb32_opt[i]));                 \
1640       if (abs_diff > max_diff) {                                               \
1641         max_diff = abs_diff;                                                   \
1642       }                                                                        \
1643     }                                                                          \
1644     EXPECT_LE(max_diff, DIFF);                                                 \
1645     free_aligned_buffer_page_end(src_y);                                       \
1646     free_aligned_buffer_page_end(src_u);                                       \
1647     free_aligned_buffer_page_end(src_v);                                       \
1648     free_aligned_buffer_page_end(dst_argb_c);                                  \
1649     free_aligned_buffer_page_end(dst_argb_opt);                                \
1650     free_aligned_buffer_page_end(dst_argb32_c);                                \
1651     free_aligned_buffer_page_end(dst_argb32_opt);                              \
1652   }
1653 
1654 #define TESTPLANARTOBD(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,  \
1655                        YALIGN, DIFF, FMT_C, BPP_C)                             \
1656   TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,       \
1657                   YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, FMT_C,       \
1658                   BPP_C)                                                       \
1659   TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,       \
1660                   YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, FMT_C,     \
1661                   BPP_C)                                                       \
1662   TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,       \
1663                   YALIGN, benchmark_width_, DIFF, _Invert, -, 0, FMT_C, BPP_C) \
1664   TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,       \
1665                   YALIGN, benchmark_width_, DIFF, _Opt, +, 0, FMT_C, BPP_C)
1666 
1667 TESTPLANARTOBD(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4)
1668 
1669 #define TESTPTOB(NAME, UYVYTOI420, UYVYTONV12)                                \
1670   TEST_F(LibYUVConvertTest, NAME) {                                           \
1671     const int kWidth = benchmark_width_;                                      \
1672     const int kHeight = benchmark_height_;                                    \
1673                                                                               \
1674     align_buffer_page_end(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2) * kHeight);     \
1675     align_buffer_page_end(orig_y, kWidth* kHeight);                           \
1676     align_buffer_page_end(orig_u,                                             \
1677                           SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2));      \
1678     align_buffer_page_end(orig_v,                                             \
1679                           SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2));      \
1680                                                                               \
1681     align_buffer_page_end(dst_y_orig, kWidth* kHeight);                       \
1682     align_buffer_page_end(dst_uv_orig,                                        \
1683                           2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2));  \
1684                                                                               \
1685     align_buffer_page_end(dst_y, kWidth* kHeight);                            \
1686     align_buffer_page_end(dst_uv,                                             \
1687                           2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2));  \
1688                                                                               \
1689     MemRandomize(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2) * kHeight);              \
1690                                                                               \
1691     /* Convert UYVY to NV12 in 2 steps for reference */                       \
1692     libyuv::UYVYTOI420(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2), orig_y, kWidth,   \
1693                        orig_u, SUBSAMPLE(kWidth, 2), orig_v,                  \
1694                        SUBSAMPLE(kWidth, 2), kWidth, kHeight);                \
1695     libyuv::I420ToNV12(orig_y, kWidth, orig_u, SUBSAMPLE(kWidth, 2), orig_v,  \
1696                        SUBSAMPLE(kWidth, 2), dst_y_orig, kWidth, dst_uv_orig, \
1697                        2 * SUBSAMPLE(kWidth, 2), kWidth, kHeight);            \
1698                                                                               \
1699     /* Convert to NV12 */                                                     \
1700     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
1701       libyuv::UYVYTONV12(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2), dst_y, kWidth,  \
1702                          dst_uv, 2 * SUBSAMPLE(kWidth, 2), kWidth, kHeight);  \
1703     }                                                                         \
1704                                                                               \
1705     for (int i = 0; i < kWidth * kHeight; ++i) {                              \
1706       EXPECT_EQ(orig_y[i], dst_y[i]);                                         \
1707     }                                                                         \
1708     for (int i = 0; i < kWidth * kHeight; ++i) {                              \
1709       EXPECT_EQ(dst_y_orig[i], dst_y[i]);                                     \
1710     }                                                                         \
1711     for (int i = 0; i < 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2);     \
1712          ++i) {                                                               \
1713       EXPECT_EQ(dst_uv_orig[i], dst_uv[i]);                                   \
1714     }                                                                         \
1715                                                                               \
1716     free_aligned_buffer_page_end(orig_uyvy);                                  \
1717     free_aligned_buffer_page_end(orig_y);                                     \
1718     free_aligned_buffer_page_end(orig_u);                                     \
1719     free_aligned_buffer_page_end(orig_v);                                     \
1720     free_aligned_buffer_page_end(dst_y_orig);                                 \
1721     free_aligned_buffer_page_end(dst_uv_orig);                                \
1722     free_aligned_buffer_page_end(dst_y);                                      \
1723     free_aligned_buffer_page_end(dst_uv);                                     \
1724   }
1725 
TESTPTOB(TestYUY2ToNV12,YUY2ToI420,YUY2ToNV12)1726 TESTPTOB(TestYUY2ToNV12, YUY2ToI420, YUY2ToNV12)
1727 TESTPTOB(TestUYVYToNV12, UYVYToI420, UYVYToNV12)
1728 
1729 // Transitive tests.  A to B to C is same as A to C.
1730 
1731 #define TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1732                        W1280, N, NEG, OFF, FMT_C, BPP_C)                      \
1733   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) {             \
1734     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                           \
1735     const int kHeight = benchmark_height_;                                    \
1736     const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B;                    \
1737     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                       \
1738     const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);            \
1739     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                      \
1740     align_buffer_page_end(src_u, kSizeUV + OFF);                              \
1741     align_buffer_page_end(src_v, kSizeUV + OFF);                              \
1742     align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF);               \
1743     for (int i = 0; i < kWidth * kHeight; ++i) {                              \
1744       src_y[i + OFF] = (fastrand() & 0xff);                                   \
1745     }                                                                         \
1746     for (int i = 0; i < kSizeUV; ++i) {                                       \
1747       src_u[i + OFF] = (fastrand() & 0xff);                                   \
1748       src_v[i + OFF] = (fastrand() & 0xff);                                   \
1749     }                                                                         \
1750     memset(dst_argb_b + OFF, 1, kStrideB * kHeight);                          \
1751     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
1752       FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV,      \
1753                             src_v + OFF, kStrideUV, dst_argb_b + OFF,         \
1754                             kStrideB, kWidth, NEG kHeight);                   \
1755     }                                                                         \
1756     /* Convert to a 3rd format in 1 step and 2 steps and compare  */          \
1757     const int kStrideC = kWidth * BPP_C;                                      \
1758     align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF);               \
1759     align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF);              \
1760     memset(dst_argb_c + OFF, 2, kStrideC * kHeight);                          \
1761     memset(dst_argb_bc + OFF, 3, kStrideC * kHeight);                         \
1762     FMT_PLANAR##To##FMT_C(src_y + OFF, kWidth, src_u + OFF, kStrideUV,        \
1763                           src_v + OFF, kStrideUV, dst_argb_c + OFF, kStrideC, \
1764                           kWidth, NEG kHeight);                               \
1765     /* Convert B to C */                                                      \
1766     FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC, \
1767                      kWidth, kHeight);                                        \
1768     for (int i = 0; i < kStrideC * kHeight; ++i) {                            \
1769       EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_bc[i + OFF]);                   \
1770     }                                                                         \
1771     free_aligned_buffer_page_end(src_y);                                      \
1772     free_aligned_buffer_page_end(src_u);                                      \
1773     free_aligned_buffer_page_end(src_v);                                      \
1774     free_aligned_buffer_page_end(dst_argb_b);                                 \
1775     free_aligned_buffer_page_end(dst_argb_c);                                 \
1776     free_aligned_buffer_page_end(dst_argb_bc);                                \
1777   }
1778 
1779 #define TESTPLANARTOE(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1780                       FMT_C, BPP_C)                                          \
1781   TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1782                  benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C)             \
1783   TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1784                  benchmark_width_, _Unaligned, +, 1, FMT_C, BPP_C)           \
1785   TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1786                  benchmark_width_, _Invert, -, 0, FMT_C, BPP_C)              \
1787   TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1788                  benchmark_width_, _Opt, +, 0, FMT_C, BPP_C)
1789 
1790 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ABGR, 4)
1791 TESTPLANARTOE(J420, 2, 2, ARGB, 1, 4, ARGB, 4)
1792 TESTPLANARTOE(J420, 2, 2, ABGR, 1, 4, ARGB, 4)
1793 TESTPLANARTOE(H420, 2, 2, ARGB, 1, 4, ARGB, 4)
1794 TESTPLANARTOE(H420, 2, 2, ABGR, 1, 4, ARGB, 4)
1795 TESTPLANARTOE(I420, 2, 2, BGRA, 1, 4, ARGB, 4)
1796 TESTPLANARTOE(I420, 2, 2, ABGR, 1, 4, ARGB, 4)
1797 TESTPLANARTOE(I420, 2, 2, RGBA, 1, 4, ARGB, 4)
1798 TESTPLANARTOE(I420, 2, 2, RGB24, 1, 3, ARGB, 4)
1799 TESTPLANARTOE(I420, 2, 2, RAW, 1, 3, RGB24, 3)
1800 TESTPLANARTOE(I420, 2, 2, RGB24, 1, 3, RAW, 3)
1801 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, RAW, 3)
1802 TESTPLANARTOE(I420, 2, 2, RAW, 1, 3, ARGB, 4)
1803 TESTPLANARTOE(H420, 2, 2, RGB24, 1, 3, ARGB, 4)
1804 TESTPLANARTOE(H420, 2, 2, RAW, 1, 3, RGB24, 3)
1805 TESTPLANARTOE(H420, 2, 2, RGB24, 1, 3, RAW, 3)
1806 TESTPLANARTOE(H420, 2, 2, ARGB, 1, 4, RAW, 3)
1807 TESTPLANARTOE(H420, 2, 2, RAW, 1, 3, ARGB, 4)
1808 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, RGB565, 2)
1809 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ARGB1555, 2)
1810 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ARGB4444, 2)
1811 TESTPLANARTOE(I422, 2, 1, ARGB, 1, 4, RGB565, 2)
1812 TESTPLANARTOE(J422, 2, 1, ARGB, 1, 4, ARGB, 4)
1813 TESTPLANARTOE(J422, 2, 1, ABGR, 1, 4, ARGB, 4)
1814 TESTPLANARTOE(H422, 2, 1, ARGB, 1, 4, ARGB, 4)
1815 TESTPLANARTOE(H422, 2, 1, ABGR, 1, 4, ARGB, 4)
1816 TESTPLANARTOE(I422, 2, 1, BGRA, 1, 4, ARGB, 4)
1817 TESTPLANARTOE(I422, 2, 1, ABGR, 1, 4, ARGB, 4)
1818 TESTPLANARTOE(I422, 2, 1, RGBA, 1, 4, ARGB, 4)
1819 TESTPLANARTOE(I444, 1, 1, ARGB, 1, 4, ARGB, 4)
1820 TESTPLANARTOE(J444, 1, 1, ARGB, 1, 4, ARGB, 4)
1821 TESTPLANARTOE(I444, 1, 1, ABGR, 1, 4, ARGB, 4)
1822 TESTPLANARTOE(I420, 2, 2, YUY2, 2, 4, ARGB, 4)
1823 TESTPLANARTOE(I420, 2, 2, UYVY, 2, 4, ARGB, 4)
1824 TESTPLANARTOE(I422, 2, 1, YUY2, 2, 4, ARGB, 4)
1825 TESTPLANARTOE(I422, 2, 1, UYVY, 2, 4, ARGB, 4)
1826 
1827 #define TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1828                         W1280, N, NEG, OFF, FMT_C, BPP_C, ATTEN)               \
1829   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) {              \
1830     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
1831     const int kHeight = benchmark_height_;                                     \
1832     const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B;                     \
1833     const int kSizeUV =                                                        \
1834         SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y);          \
1835     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
1836     align_buffer_page_end(src_u, kSizeUV + OFF);                               \
1837     align_buffer_page_end(src_v, kSizeUV + OFF);                               \
1838     align_buffer_page_end(src_a, kWidth* kHeight + OFF);                       \
1839     align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF);                \
1840     for (int i = 0; i < kWidth * kHeight; ++i) {                               \
1841       src_y[i + OFF] = (fastrand() & 0xff);                                    \
1842       src_a[i + OFF] = (fastrand() & 0xff);                                    \
1843     }                                                                          \
1844     for (int i = 0; i < kSizeUV; ++i) {                                        \
1845       src_u[i + OFF] = (fastrand() & 0xff);                                    \
1846       src_v[i + OFF] = (fastrand() & 0xff);                                    \
1847     }                                                                          \
1848     memset(dst_argb_b + OFF, 1, kStrideB * kHeight);                           \
1849     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
1850       FMT_PLANAR##To##FMT_B(                                                   \
1851           src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SUBSAMP_X),      \
1852           src_v + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), src_a + OFF, kWidth,      \
1853           dst_argb_b + OFF, kStrideB, kWidth, NEG kHeight, ATTEN);             \
1854     }                                                                          \
1855     /* Convert to a 3rd format in 1 step and 2 steps and compare  */           \
1856     const int kStrideC = kWidth * BPP_C;                                       \
1857     align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF);                \
1858     align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF);               \
1859     memset(dst_argb_c + OFF, 2, kStrideC * kHeight);                           \
1860     memset(dst_argb_bc + OFF, 3, kStrideC * kHeight);                          \
1861     FMT_PLANAR##To##FMT_C(                                                     \
1862         src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SUBSAMP_X),        \
1863         src_v + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), src_a + OFF, kWidth,        \
1864         dst_argb_c + OFF, kStrideC, kWidth, NEG kHeight, ATTEN);               \
1865     /* Convert B to C */                                                       \
1866     FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC,  \
1867                      kWidth, kHeight);                                         \
1868     for (int i = 0; i < kStrideC * kHeight; ++i) {                             \
1869       EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_bc[i + OFF]);                    \
1870     }                                                                          \
1871     free_aligned_buffer_page_end(src_y);                                       \
1872     free_aligned_buffer_page_end(src_u);                                       \
1873     free_aligned_buffer_page_end(src_v);                                       \
1874     free_aligned_buffer_page_end(src_a);                                       \
1875     free_aligned_buffer_page_end(dst_argb_b);                                  \
1876     free_aligned_buffer_page_end(dst_argb_c);                                  \
1877     free_aligned_buffer_page_end(dst_argb_bc);                                 \
1878   }
1879 
1880 #define TESTQPLANARTOE(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1881                        FMT_C, BPP_C)                                          \
1882   TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1883                   benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C, 0)          \
1884   TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1885                   benchmark_width_, _Unaligned, +, 1, FMT_C, BPP_C, 0)        \
1886   TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1887                   benchmark_width_, _Invert, -, 0, FMT_C, BPP_C, 0)           \
1888   TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1889                   benchmark_width_, _Opt, +, 0, FMT_C, BPP_C, 0)              \
1890   TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1891                   benchmark_width_, _Premult, +, 0, FMT_C, BPP_C, 1)
1892 
1893 TESTQPLANARTOE(I420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4)
1894 TESTQPLANARTOE(I420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4)
1895 
1896 #define TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, W1280, N, NEG, \
1897                       OFF, FMT_C, BPP_C)                                       \
1898   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##_##FMT_C##N) {                   \
1899     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
1900     const int kHeight = benchmark_height_;                                     \
1901     const int kStrideA = SUBSAMPLE(kWidth, SUB_A) * BPP_A;                     \
1902     const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B;                     \
1903     align_buffer_page_end(src_argb_a, kStrideA* kHeight + OFF);                \
1904     align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF);                \
1905     MemRandomize(src_argb_a + OFF, kStrideA * kHeight);                        \
1906     memset(dst_argb_b + OFF, 1, kStrideB * kHeight);                           \
1907     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
1908       FMT_A##To##FMT_B(src_argb_a + OFF, kStrideA, dst_argb_b + OFF, kStrideB, \
1909                        kWidth, NEG kHeight);                                   \
1910     }                                                                          \
1911     /* Convert to a 3rd format in 1 step and 2 steps and compare  */           \
1912     const int kStrideC = kWidth * BPP_C;                                       \
1913     align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF);                \
1914     align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF);               \
1915     memset(dst_argb_c + OFF, 2, kStrideC * kHeight);                           \
1916     memset(dst_argb_bc + OFF, 3, kStrideC * kHeight);                          \
1917     FMT_A##To##FMT_C(src_argb_a + OFF, kStrideA, dst_argb_c + OFF, kStrideC,   \
1918                      kWidth, NEG kHeight);                                     \
1919     /* Convert B to C */                                                       \
1920     FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC,  \
1921                      kWidth, kHeight);                                         \
1922     for (int i = 0; i < kStrideC * kHeight; i += 4) {                          \
1923       EXPECT_EQ(dst_argb_c[i + OFF + 0], dst_argb_bc[i + OFF + 0]);            \
1924       EXPECT_EQ(dst_argb_c[i + OFF + 1], dst_argb_bc[i + OFF + 1]);            \
1925       EXPECT_EQ(dst_argb_c[i + OFF + 2], dst_argb_bc[i + OFF + 2]);            \
1926       EXPECT_NEAR(dst_argb_c[i + OFF + 3], dst_argb_bc[i + OFF + 3], 64);      \
1927     }                                                                          \
1928     free_aligned_buffer_page_end(src_argb_a);                                  \
1929     free_aligned_buffer_page_end(dst_argb_b);                                  \
1930     free_aligned_buffer_page_end(dst_argb_c);                                  \
1931     free_aligned_buffer_page_end(dst_argb_bc);                                 \
1932   }
1933 
1934 #define TESTPLANETOE(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, FMT_C, BPP_C) \
1935   TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B,                    \
1936                 benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C)              \
1937   TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_,  \
1938                 _Unaligned, +, 1, FMT_C, BPP_C)                              \
1939   TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_,  \
1940                 _Invert, -, 0, FMT_C, BPP_C)                                 \
1941   TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_,  \
1942                 _Opt, +, 0, FMT_C, BPP_C)
1943 
1944 // Caveat: Destination needs to be 4 bytes
1945 TESTPLANETOE(ARGB, 1, 4, AR30, 1, 4, ARGB, 4)
1946 TESTPLANETOE(ABGR, 1, 4, AR30, 1, 4, ABGR, 4)
1947 TESTPLANETOE(AR30, 1, 4, ARGB, 1, 4, ABGR, 4)
1948 TESTPLANETOE(AR30, 1, 4, ABGR, 1, 4, ARGB, 4)
1949 TESTPLANETOE(ARGB, 1, 4, AB30, 1, 4, ARGB, 4)
1950 TESTPLANETOE(ABGR, 1, 4, AB30, 1, 4, ABGR, 4)
1951 TESTPLANETOE(AB30, 1, 4, ARGB, 1, 4, ABGR, 4)
1952 TESTPLANETOE(AB30, 1, 4, ABGR, 1, 4, ARGB, 4)
1953 
1954 TEST_F(LibYUVConvertTest, RotateWithARGBSource) {
1955   // 2x2 frames
1956   uint32_t src[4];
1957   uint32_t dst[4];
1958   // some random input
1959   src[0] = 0x11000000;
1960   src[1] = 0x00450000;
1961   src[2] = 0x00009f00;
1962   src[3] = 0x000000ff;
1963   // zeros on destination
1964   dst[0] = 0x00000000;
1965   dst[1] = 0x00000000;
1966   dst[2] = 0x00000000;
1967   dst[3] = 0x00000000;
1968 
1969   int r = ConvertToARGB(reinterpret_cast<uint8_t*>(src),
1970                         16,  // input size
1971                         reinterpret_cast<uint8_t*>(dst),
1972                         8,  // destination stride
1973                         0,  // crop_x
1974                         0,  // crop_y
1975                         2,  // width
1976                         2,  // height
1977                         2,  // crop width
1978                         2,  // crop height
1979                         kRotate90, FOURCC_ARGB);
1980 
1981   EXPECT_EQ(r, 0);
1982   // 90 degrees rotation, no conversion
1983   EXPECT_EQ(dst[0], src[2]);
1984   EXPECT_EQ(dst[1], src[0]);
1985   EXPECT_EQ(dst[2], src[3]);
1986   EXPECT_EQ(dst[3], src[1]);
1987 }
1988 
1989 #ifdef HAS_ARGBTOAR30ROW_AVX2
TEST_F(LibYUVConvertTest,ARGBToAR30Row_Opt)1990 TEST_F(LibYUVConvertTest, ARGBToAR30Row_Opt) {
1991   // ARGBToAR30Row_AVX2 expects a multiple of 8 pixels.
1992   const int kPixels = (benchmark_width_ * benchmark_height_ + 7) & ~7;
1993   align_buffer_page_end(src, kPixels * 4);
1994   align_buffer_page_end(dst_opt, kPixels * 4);
1995   align_buffer_page_end(dst_c, kPixels * 4);
1996   MemRandomize(src, kPixels * 4);
1997   memset(dst_opt, 0, kPixels * 4);
1998   memset(dst_c, 1, kPixels * 4);
1999 
2000   ARGBToAR30Row_C(src, dst_c, kPixels);
2001 
2002   int has_avx2 = TestCpuFlag(kCpuHasAVX2);
2003   int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
2004   for (int i = 0; i < benchmark_iterations_; ++i) {
2005     if (has_avx2) {
2006       ARGBToAR30Row_AVX2(src, dst_opt, kPixels);
2007     } else if (has_ssse3) {
2008       ARGBToAR30Row_SSSE3(src, dst_opt, kPixels);
2009     } else {
2010       ARGBToAR30Row_C(src, dst_opt, kPixels);
2011     }
2012   }
2013   for (int i = 0; i < kPixels * 4; ++i) {
2014     EXPECT_EQ(dst_opt[i], dst_c[i]);
2015   }
2016 
2017   free_aligned_buffer_page_end(src);
2018   free_aligned_buffer_page_end(dst_opt);
2019   free_aligned_buffer_page_end(dst_c);
2020 }
2021 #endif  // HAS_ARGBTOAR30ROW_AVX2
2022 
2023 #ifdef HAS_ABGRTOAR30ROW_AVX2
TEST_F(LibYUVConvertTest,ABGRToAR30Row_Opt)2024 TEST_F(LibYUVConvertTest, ABGRToAR30Row_Opt) {
2025   // ABGRToAR30Row_AVX2 expects a multiple of 8 pixels.
2026   const int kPixels = (benchmark_width_ * benchmark_height_ + 7) & ~7;
2027   align_buffer_page_end(src, kPixels * 4);
2028   align_buffer_page_end(dst_opt, kPixels * 4);
2029   align_buffer_page_end(dst_c, kPixels * 4);
2030   MemRandomize(src, kPixels * 4);
2031   memset(dst_opt, 0, kPixels * 4);
2032   memset(dst_c, 1, kPixels * 4);
2033 
2034   ABGRToAR30Row_C(src, dst_c, kPixels);
2035 
2036   int has_avx2 = TestCpuFlag(kCpuHasAVX2);
2037   int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
2038   for (int i = 0; i < benchmark_iterations_; ++i) {
2039     if (has_avx2) {
2040       ABGRToAR30Row_AVX2(src, dst_opt, kPixels);
2041     } else if (has_ssse3) {
2042       ABGRToAR30Row_SSSE3(src, dst_opt, kPixels);
2043     } else {
2044       ABGRToAR30Row_C(src, dst_opt, kPixels);
2045     }
2046   }
2047   for (int i = 0; i < kPixels * 4; ++i) {
2048     EXPECT_EQ(dst_opt[i], dst_c[i]);
2049   }
2050 
2051   free_aligned_buffer_page_end(src);
2052   free_aligned_buffer_page_end(dst_opt);
2053   free_aligned_buffer_page_end(dst_c);
2054 }
2055 #endif  // HAS_ABGRTOAR30ROW_AVX2
2056 
2057 // TODO(fbarchard): Fix clamping issue affected by U channel.
2058 #define TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,   \
2059                          ALIGN, YALIGN, W1280, DIFF, N, NEG, SOFF, DOFF)   \
2060   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                    \
2061     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                        \
2062     const int kHeight = ALIGNINT(benchmark_height_, YALIGN);               \
2063     const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                  \
2064     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                    \
2065     const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);         \
2066     const int kBpc = 2;                                                    \
2067     align_buffer_page_end(src_y, kWidth* kHeight* kBpc + SOFF);            \
2068     align_buffer_page_end(src_u, kSizeUV* kBpc + SOFF);                    \
2069     align_buffer_page_end(src_v, kSizeUV* kBpc + SOFF);                    \
2070     align_buffer_page_end(dst_argb_c, kStrideB* kHeight + DOFF);           \
2071     align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + DOFF);         \
2072     for (int i = 0; i < kWidth * kHeight; ++i) {                           \
2073       reinterpret_cast<uint16_t*>(src_y + SOFF)[i] = (fastrand() & 0x3ff); \
2074     }                                                                      \
2075     for (int i = 0; i < kSizeUV; ++i) {                                    \
2076       reinterpret_cast<uint16_t*>(src_u + SOFF)[i] = (fastrand() & 0x3ff); \
2077       reinterpret_cast<uint16_t*>(src_v + SOFF)[i] = (fastrand() & 0x3ff); \
2078     }                                                                      \
2079     memset(dst_argb_c + DOFF, 1, kStrideB * kHeight);                      \
2080     memset(dst_argb_opt + DOFF, 101, kStrideB * kHeight);                  \
2081     MaskCpuFlags(disable_cpu_flags_);                                      \
2082     FMT_PLANAR##To##FMT_B(                                                 \
2083         reinterpret_cast<uint16_t*>(src_y + SOFF), kWidth,                 \
2084         reinterpret_cast<uint16_t*>(src_u + SOFF), kStrideUV,              \
2085         reinterpret_cast<uint16_t*>(src_v + SOFF), kStrideUV,              \
2086         dst_argb_c + DOFF, kStrideB, kWidth, NEG kHeight);                 \
2087     MaskCpuFlags(benchmark_cpu_info_);                                     \
2088     for (int i = 0; i < benchmark_iterations_; ++i) {                      \
2089       FMT_PLANAR##To##FMT_B(                                               \
2090           reinterpret_cast<uint16_t*>(src_y + SOFF), kWidth,               \
2091           reinterpret_cast<uint16_t*>(src_u + SOFF), kStrideUV,            \
2092           reinterpret_cast<uint16_t*>(src_v + SOFF), kStrideUV,            \
2093           dst_argb_opt + DOFF, kStrideB, kWidth, NEG kHeight);             \
2094     }                                                                      \
2095     int max_diff = 0;                                                      \
2096     for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) {                   \
2097       int abs_diff = abs(static_cast<int>(dst_argb_c[i + DOFF]) -          \
2098                          static_cast<int>(dst_argb_opt[i + DOFF]));        \
2099       if (abs_diff > max_diff) {                                           \
2100         max_diff = abs_diff;                                               \
2101       }                                                                    \
2102     }                                                                      \
2103     EXPECT_LE(max_diff, DIFF);                                             \
2104     free_aligned_buffer_page_end(src_y);                                   \
2105     free_aligned_buffer_page_end(src_u);                                   \
2106     free_aligned_buffer_page_end(src_v);                                   \
2107     free_aligned_buffer_page_end(dst_argb_c);                              \
2108     free_aligned_buffer_page_end(dst_argb_opt);                            \
2109   }
2110 
2111 #define TESTPLANAR16TOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
2112                         YALIGN, DIFF)                                          \
2113   TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
2114                    YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, 0)          \
2115   TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
2116                    YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, 1)        \
2117   TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
2118                    YALIGN, benchmark_width_, DIFF, _Invert, -, 0, 0)           \
2119   TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
2120                    YALIGN, benchmark_width_, DIFF, _Opt, +, 0, 0)
2121 
2122 TESTPLANAR16TOB(I010, 2, 2, ARGB, 4, 4, 1, 2)
2123 TESTPLANAR16TOB(I010, 2, 2, ABGR, 4, 4, 1, 2)
2124 TESTPLANAR16TOB(I010, 2, 2, AR30, 4, 4, 1, 2)
2125 TESTPLANAR16TOB(I010, 2, 2, AB30, 4, 4, 1, 2)
2126 TESTPLANAR16TOB(H010, 2, 2, ARGB, 4, 4, 1, 2)
2127 TESTPLANAR16TOB(H010, 2, 2, ABGR, 4, 4, 1, 2)
2128 TESTPLANAR16TOB(H010, 2, 2, AR30, 4, 4, 1, 2)
2129 TESTPLANAR16TOB(H010, 2, 2, AB30, 4, 4, 1, 2)
2130 
Clamp(int y)2131 static int Clamp(int y) {
2132   if (y < 0) {
2133     y = 0;
2134   }
2135   if (y > 255) {
2136     y = 255;
2137   }
2138   return y;
2139 }
2140 
Clamp10(int y)2141 static int Clamp10(int y) {
2142   if (y < 0) {
2143     y = 0;
2144   }
2145   if (y > 1023) {
2146     y = 1023;
2147   }
2148   return y;
2149 }
2150 
2151 // Test 8 bit YUV to 8 bit RGB
TEST_F(LibYUVConvertTest,TestH420ToARGB)2152 TEST_F(LibYUVConvertTest, TestH420ToARGB) {
2153   const int kSize = 256;
2154   int histogram_b[256];
2155   int histogram_g[256];
2156   int histogram_r[256];
2157   memset(histogram_b, 0, sizeof(histogram_b));
2158   memset(histogram_g, 0, sizeof(histogram_g));
2159   memset(histogram_r, 0, sizeof(histogram_r));
2160   align_buffer_page_end(orig_yuv, kSize + kSize / 2 * 2);
2161   align_buffer_page_end(argb_pixels, kSize * 4);
2162   uint8_t* orig_y = orig_yuv;
2163   uint8_t* orig_u = orig_y + kSize;
2164   uint8_t* orig_v = orig_u + kSize / 2;
2165 
2166   // Test grey scale
2167   for (int i = 0; i < kSize; ++i) {
2168     orig_y[i] = i;
2169   }
2170   for (int i = 0; i < kSize / 2; ++i) {
2171     orig_u[i] = 128;  // 128 is 0.
2172     orig_v[i] = 128;
2173   }
2174 
2175   H420ToARGB(orig_y, 0, orig_u, 0, orig_v, 0, argb_pixels, 0, kSize, 1);
2176 
2177   for (int i = 0; i < kSize; ++i) {
2178     int b = argb_pixels[i * 4 + 0];
2179     int g = argb_pixels[i * 4 + 1];
2180     int r = argb_pixels[i * 4 + 2];
2181     int a = argb_pixels[i * 4 + 3];
2182     ++histogram_b[b];
2183     ++histogram_g[g];
2184     ++histogram_r[r];
2185     int expected_y = Clamp(static_cast<int>((i - 16) * 1.164f));
2186     EXPECT_NEAR(b, expected_y, 1);
2187     EXPECT_NEAR(g, expected_y, 1);
2188     EXPECT_NEAR(r, expected_y, 1);
2189     EXPECT_EQ(a, 255);
2190   }
2191 
2192   int count_b = 0;
2193   int count_g = 0;
2194   int count_r = 0;
2195   for (int i = 0; i < kSize; ++i) {
2196     if (histogram_b[i]) {
2197       ++count_b;
2198     }
2199     if (histogram_g[i]) {
2200       ++count_g;
2201     }
2202     if (histogram_r[i]) {
2203       ++count_r;
2204     }
2205   }
2206   printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2207 
2208   free_aligned_buffer_page_end(orig_yuv);
2209   free_aligned_buffer_page_end(argb_pixels);
2210 }
2211 
2212 // Test 10 bit YUV to 8 bit RGB
TEST_F(LibYUVConvertTest,TestH010ToARGB)2213 TEST_F(LibYUVConvertTest, TestH010ToARGB) {
2214   const int kSize = 1024;
2215   int histogram_b[1024];
2216   int histogram_g[1024];
2217   int histogram_r[1024];
2218   memset(histogram_b, 0, sizeof(histogram_b));
2219   memset(histogram_g, 0, sizeof(histogram_g));
2220   memset(histogram_r, 0, sizeof(histogram_r));
2221   align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2);
2222   align_buffer_page_end(argb_pixels, kSize * 4);
2223   uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv);
2224   uint16_t* orig_u = orig_y + kSize;
2225   uint16_t* orig_v = orig_u + kSize / 2;
2226 
2227   // Test grey scale
2228   for (int i = 0; i < kSize; ++i) {
2229     orig_y[i] = i;
2230   }
2231   for (int i = 0; i < kSize / 2; ++i) {
2232     orig_u[i] = 512;  // 512 is 0.
2233     orig_v[i] = 512;
2234   }
2235 
2236   H010ToARGB(orig_y, 0, orig_u, 0, orig_v, 0, argb_pixels, 0, kSize, 1);
2237 
2238   for (int i = 0; i < kSize; ++i) {
2239     int b = argb_pixels[i * 4 + 0];
2240     int g = argb_pixels[i * 4 + 1];
2241     int r = argb_pixels[i * 4 + 2];
2242     int a = argb_pixels[i * 4 + 3];
2243     ++histogram_b[b];
2244     ++histogram_g[g];
2245     ++histogram_r[r];
2246     int expected_y = Clamp(static_cast<int>((i - 64) * 1.164f / 4));
2247     EXPECT_NEAR(b, expected_y, 1);
2248     EXPECT_NEAR(g, expected_y, 1);
2249     EXPECT_NEAR(r, expected_y, 1);
2250     EXPECT_EQ(a, 255);
2251   }
2252 
2253   int count_b = 0;
2254   int count_g = 0;
2255   int count_r = 0;
2256   for (int i = 0; i < kSize; ++i) {
2257     if (histogram_b[i]) {
2258       ++count_b;
2259     }
2260     if (histogram_g[i]) {
2261       ++count_g;
2262     }
2263     if (histogram_r[i]) {
2264       ++count_r;
2265     }
2266   }
2267   printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2268 
2269   free_aligned_buffer_page_end(orig_yuv);
2270   free_aligned_buffer_page_end(argb_pixels);
2271 }
2272 
2273 // Test 10 bit YUV to 10 bit RGB
2274 // Caveat: Result is near due to float rounding in expected result.
TEST_F(LibYUVConvertTest,TestH010ToAR30)2275 TEST_F(LibYUVConvertTest, TestH010ToAR30) {
2276   const int kSize = 1024;
2277   int histogram_b[1024];
2278   int histogram_g[1024];
2279   int histogram_r[1024];
2280   memset(histogram_b, 0, sizeof(histogram_b));
2281   memset(histogram_g, 0, sizeof(histogram_g));
2282   memset(histogram_r, 0, sizeof(histogram_r));
2283 
2284   align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2);
2285   align_buffer_page_end(ar30_pixels, kSize * 4);
2286   uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv);
2287   uint16_t* orig_u = orig_y + kSize;
2288   uint16_t* orig_v = orig_u + kSize / 2;
2289 
2290   // Test grey scale
2291   for (int i = 0; i < kSize; ++i) {
2292     orig_y[i] = i;
2293   }
2294   for (int i = 0; i < kSize / 2; ++i) {
2295     orig_u[i] = 512;  // 512 is 0.
2296     orig_v[i] = 512;
2297   }
2298 
2299   H010ToAR30(orig_y, 0, orig_u, 0, orig_v, 0, ar30_pixels, 0, kSize, 1);
2300 
2301   for (int i = 0; i < kSize; ++i) {
2302     int b10 = reinterpret_cast<uint32_t*>(ar30_pixels)[i] & 1023;
2303     int g10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 10) & 1023;
2304     int r10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 20) & 1023;
2305     int a2 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 30) & 3;
2306     ++histogram_b[b10];
2307     ++histogram_g[g10];
2308     ++histogram_r[r10];
2309     int expected_y = Clamp10(static_cast<int>((i - 64) * 1.164f));
2310     EXPECT_NEAR(b10, expected_y, 4);
2311     EXPECT_NEAR(g10, expected_y, 4);
2312     EXPECT_NEAR(r10, expected_y, 4);
2313     EXPECT_EQ(a2, 3);
2314   }
2315 
2316   int count_b = 0;
2317   int count_g = 0;
2318   int count_r = 0;
2319   for (int i = 0; i < kSize; ++i) {
2320     if (histogram_b[i]) {
2321       ++count_b;
2322     }
2323     if (histogram_g[i]) {
2324       ++count_g;
2325     }
2326     if (histogram_r[i]) {
2327       ++count_r;
2328     }
2329   }
2330   printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2331 
2332   free_aligned_buffer_page_end(orig_yuv);
2333   free_aligned_buffer_page_end(ar30_pixels);
2334 }
2335 
2336 // Test 10 bit YUV to 10 bit RGB
2337 // Caveat: Result is near due to float rounding in expected result.
TEST_F(LibYUVConvertTest,TestH010ToAB30)2338 TEST_F(LibYUVConvertTest, TestH010ToAB30) {
2339   const int kSize = 1024;
2340   int histogram_b[1024];
2341   int histogram_g[1024];
2342   int histogram_r[1024];
2343   memset(histogram_b, 0, sizeof(histogram_b));
2344   memset(histogram_g, 0, sizeof(histogram_g));
2345   memset(histogram_r, 0, sizeof(histogram_r));
2346 
2347   align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2);
2348   align_buffer_page_end(ab30_pixels, kSize * 4);
2349   uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv);
2350   uint16_t* orig_u = orig_y + kSize;
2351   uint16_t* orig_v = orig_u + kSize / 2;
2352 
2353   // Test grey scale
2354   for (int i = 0; i < kSize; ++i) {
2355     orig_y[i] = i;
2356   }
2357   for (int i = 0; i < kSize / 2; ++i) {
2358     orig_u[i] = 512;  // 512 is 0.
2359     orig_v[i] = 512;
2360   }
2361 
2362   H010ToAB30(orig_y, 0, orig_u, 0, orig_v, 0, ab30_pixels, 0, kSize, 1);
2363 
2364   for (int i = 0; i < kSize; ++i) {
2365     int r10 = reinterpret_cast<uint32_t*>(ab30_pixels)[i] & 1023;
2366     int g10 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 10) & 1023;
2367     int b10 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 20) & 1023;
2368     int a2 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 30) & 3;
2369     ++histogram_b[b10];
2370     ++histogram_g[g10];
2371     ++histogram_r[r10];
2372     int expected_y = Clamp10(static_cast<int>((i - 64) * 1.164f));
2373     EXPECT_NEAR(b10, expected_y, 4);
2374     EXPECT_NEAR(g10, expected_y, 4);
2375     EXPECT_NEAR(r10, expected_y, 4);
2376     EXPECT_EQ(a2, 3);
2377   }
2378 
2379   int count_b = 0;
2380   int count_g = 0;
2381   int count_r = 0;
2382   for (int i = 0; i < kSize; ++i) {
2383     if (histogram_b[i]) {
2384       ++count_b;
2385     }
2386     if (histogram_g[i]) {
2387       ++count_g;
2388     }
2389     if (histogram_r[i]) {
2390       ++count_r;
2391     }
2392   }
2393   printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2394 
2395   free_aligned_buffer_page_end(orig_yuv);
2396   free_aligned_buffer_page_end(ab30_pixels);
2397 }
2398 
2399 // Test 8 bit YUV to 10 bit RGB
TEST_F(LibYUVConvertTest,TestH420ToAR30)2400 TEST_F(LibYUVConvertTest, TestH420ToAR30) {
2401   const int kSize = 256;
2402   const int kHistSize = 1024;
2403   int histogram_b[kHistSize];
2404   int histogram_g[kHistSize];
2405   int histogram_r[kHistSize];
2406   memset(histogram_b, 0, sizeof(histogram_b));
2407   memset(histogram_g, 0, sizeof(histogram_g));
2408   memset(histogram_r, 0, sizeof(histogram_r));
2409   align_buffer_page_end(orig_yuv, kSize + kSize / 2 * 2);
2410   align_buffer_page_end(ar30_pixels, kSize * 4);
2411   uint8_t* orig_y = orig_yuv;
2412   uint8_t* orig_u = orig_y + kSize;
2413   uint8_t* orig_v = orig_u + kSize / 2;
2414 
2415   // Test grey scale
2416   for (int i = 0; i < kSize; ++i) {
2417     orig_y[i] = i;
2418   }
2419   for (int i = 0; i < kSize / 2; ++i) {
2420     orig_u[i] = 128;  // 128 is 0.
2421     orig_v[i] = 128;
2422   }
2423 
2424   H420ToAR30(orig_y, 0, orig_u, 0, orig_v, 0, ar30_pixels, 0, kSize, 1);
2425 
2426   for (int i = 0; i < kSize; ++i) {
2427     int b10 = reinterpret_cast<uint32_t*>(ar30_pixels)[i] & 1023;
2428     int g10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 10) & 1023;
2429     int r10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 20) & 1023;
2430     int a2 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 30) & 3;
2431     ++histogram_b[b10];
2432     ++histogram_g[g10];
2433     ++histogram_r[r10];
2434     int expected_y = Clamp10(static_cast<int>((i - 16) * 1.164f * 4.f));
2435     EXPECT_NEAR(b10, expected_y, 4);
2436     EXPECT_NEAR(g10, expected_y, 4);
2437     EXPECT_NEAR(r10, expected_y, 4);
2438     EXPECT_EQ(a2, 3);
2439   }
2440 
2441   int count_b = 0;
2442   int count_g = 0;
2443   int count_r = 0;
2444   for (int i = 0; i < kHistSize; ++i) {
2445     if (histogram_b[i]) {
2446       ++count_b;
2447     }
2448     if (histogram_g[i]) {
2449       ++count_g;
2450     }
2451     if (histogram_r[i]) {
2452       ++count_r;
2453     }
2454   }
2455   printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2456 
2457   free_aligned_buffer_page_end(orig_yuv);
2458   free_aligned_buffer_page_end(ar30_pixels);
2459 }
2460 
2461 }  // namespace libyuv
2462