• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // wrapper to keep API the same
I400ToNV21(const uint8_t * src_y,int src_stride_y,const uint8_t *,int,const uint8_t *,int,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_vu,int dst_stride_vu,int width,int height)285 int I400ToNV21(const uint8_t* src_y,
286                int src_stride_y,
287                const uint8_t* /* src_u */,
288                int /* src_stride_u */,
289                const uint8_t* /* src_v */,
290                int /* src_stride_v */,
291                uint8_t* dst_y,
292                int dst_stride_y,
293                uint8_t* dst_vu,
294                int dst_stride_vu,
295                int width,
296                int height) {
297   return I400ToNV21(src_y, src_stride_y, dst_y, dst_stride_y, dst_vu,
298                     dst_stride_vu, width, height);
299 }
300 
301 #define TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,         \
302                         FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF) \
303   TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) {              \
304     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                           \
305     const int kHeight = benchmark_height_;                                    \
306     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                      \
307     align_buffer_page_end(src_u, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *           \
308                                          SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) +  \
309                                      OFF);                                    \
310     align_buffer_page_end(src_v, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *           \
311                                          SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) +  \
312                                      OFF);                                    \
313     align_buffer_page_end(dst_y_c, kWidth* kHeight);                          \
314     align_buffer_page_end(dst_uv_c, SUBSAMPLE(kWidth, SUBSAMP_X) * 2 *        \
315                                         SUBSAMPLE(kHeight, SUBSAMP_Y));       \
316     align_buffer_page_end(dst_y_opt, kWidth* kHeight);                        \
317     align_buffer_page_end(dst_uv_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * 2 *      \
318                                           SUBSAMPLE(kHeight, SUBSAMP_Y));     \
319     for (int i = 0; i < kHeight; ++i)                                         \
320       for (int j = 0; j < kWidth; ++j)                                        \
321         src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                    \
322     for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) {             \
323       for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) {            \
324         src_u[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =             \
325             (fastrand() & 0xff);                                              \
326         src_v[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =             \
327             (fastrand() & 0xff);                                              \
328       }                                                                       \
329     }                                                                         \
330     memset(dst_y_c, 1, kWidth* kHeight);                                      \
331     memset(dst_uv_c, 2,                                                       \
332            SUBSAMPLE(kWidth, SUBSAMP_X) * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
333     memset(dst_y_opt, 101, kWidth* kHeight);                                  \
334     memset(dst_uv_opt, 102,                                                   \
335            SUBSAMPLE(kWidth, SUBSAMP_X) * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
336     MaskCpuFlags(disable_cpu_flags_);                                         \
337     SRC_FMT_PLANAR##To##FMT_PLANAR(                                           \
338         src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X),   \
339         src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_c, kWidth,       \
340         dst_uv_c, SUBSAMPLE(kWidth, SUBSAMP_X) * 2, kWidth, NEG kHeight);     \
341     MaskCpuFlags(benchmark_cpu_info_);                                        \
342     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
343       SRC_FMT_PLANAR##To##FMT_PLANAR(                                         \
344           src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
345           src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_opt, kWidth,   \
346           dst_uv_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * 2, kWidth, NEG kHeight); \
347     }                                                                         \
348     int max_diff = 0;                                                         \
349     for (int i = 0; i < kHeight; ++i) {                                       \
350       for (int j = 0; j < kWidth; ++j) {                                      \
351         int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) -        \
352                            static_cast<int>(dst_y_opt[i * kWidth + j]));      \
353         if (abs_diff > max_diff) {                                            \
354           max_diff = abs_diff;                                                \
355         }                                                                     \
356       }                                                                       \
357     }                                                                         \
358     EXPECT_LE(max_diff, 1);                                                   \
359     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                 \
360       for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X) * 2; ++j) {            \
361         int abs_diff =                                                        \
362             abs(static_cast<int>(                                             \
363                     dst_uv_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) * 2 + j]) -     \
364                 static_cast<int>(                                             \
365                     dst_uv_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) * 2 + j]));   \
366         if (abs_diff > max_diff) {                                            \
367           max_diff = abs_diff;                                                \
368         }                                                                     \
369       }                                                                       \
370     }                                                                         \
371     EXPECT_LE(max_diff, 1);                                                   \
372     free_aligned_buffer_page_end(dst_y_c);                                    \
373     free_aligned_buffer_page_end(dst_uv_c);                                   \
374     free_aligned_buffer_page_end(dst_y_opt);                                  \
375     free_aligned_buffer_page_end(dst_uv_opt);                                 \
376     free_aligned_buffer_page_end(src_y);                                      \
377     free_aligned_buffer_page_end(src_u);                                      \
378     free_aligned_buffer_page_end(src_v);                                      \
379   }
380 
381 #define TESTPLANARTOBP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,        \
382                        FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y)                    \
383   TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
384                   SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0)   \
385   TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
386                   SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Unaligned, +, 1) \
387   TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
388                   SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0)    \
389   TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
390                   SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0)
391 
392 TESTPLANARTOBP(I420, 2, 2, NV12, 2, 2)
393 TESTPLANARTOBP(I420, 2, 2, NV21, 2, 2)
394 TESTPLANARTOBP(I422, 2, 1, NV21, 2, 2)
395 TESTPLANARTOBP(I444, 1, 1, NV21, 2, 2)
396 TESTPLANARTOBP(I400, 2, 2, NV21, 2, 2)
397 
398 #define TESTBIPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,        \
399                           FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG,     \
400                           OFF)                                                 \
401   TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) {               \
402     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
403     const int kHeight = benchmark_height_;                                     \
404     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
405     align_buffer_page_end(src_uv, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * 2 *       \
406                                           SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) +  \
407                                       OFF);                                    \
408     align_buffer_page_end(dst_y_c, kWidth* kHeight);                           \
409     align_buffer_page_end(dst_uv_c, SUBSAMPLE(kWidth, SUBSAMP_X) * 2 *         \
410                                         SUBSAMPLE(kHeight, SUBSAMP_Y));        \
411     align_buffer_page_end(dst_y_opt, kWidth* kHeight);                         \
412     align_buffer_page_end(dst_uv_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * 2 *       \
413                                           SUBSAMPLE(kHeight, SUBSAMP_Y));      \
414     for (int i = 0; i < kHeight; ++i)                                          \
415       for (int j = 0; j < kWidth; ++j)                                         \
416         src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                     \
417     for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) {              \
418       for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) {             \
419         src_uv[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) * 2 + j + 0 + OFF] =     \
420             (fastrand() & 0xff);                                               \
421         src_uv[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) * 2 + j + 1 + OFF] =     \
422             (fastrand() & 0xff);                                               \
423       }                                                                        \
424     }                                                                          \
425     memset(dst_y_c, 1, kWidth* kHeight);                                       \
426     memset(dst_uv_c, 2,                                                        \
427            SUBSAMPLE(kWidth, SUBSAMP_X) * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));  \
428     memset(dst_y_opt, 101, kWidth* kHeight);                                   \
429     memset(dst_uv_opt, 102,                                                    \
430            SUBSAMPLE(kWidth, SUBSAMP_X) * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));  \
431     MaskCpuFlags(disable_cpu_flags_);                                          \
432     SRC_FMT_PLANAR##To##FMT_PLANAR(                                            \
433         src_y + OFF, kWidth, src_uv + OFF,                                     \
434         SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * 2, dst_y_c, kWidth, dst_uv_c,       \
435         SUBSAMPLE(kWidth, SUBSAMP_X) * 2, kWidth, NEG kHeight);                \
436     MaskCpuFlags(benchmark_cpu_info_);                                         \
437     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
438       SRC_FMT_PLANAR##To##FMT_PLANAR(                                          \
439           src_y + OFF, kWidth, src_uv + OFF,                                   \
440           SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * 2, dst_y_opt, kWidth, dst_uv_opt, \
441           SUBSAMPLE(kWidth, SUBSAMP_X) * 2, kWidth, NEG kHeight);              \
442     }                                                                          \
443     int max_diff = 0;                                                          \
444     for (int i = 0; i < kHeight; ++i) {                                        \
445       for (int j = 0; j < kWidth; ++j) {                                       \
446         int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) -         \
447                            static_cast<int>(dst_y_opt[i * kWidth + j]));       \
448         if (abs_diff > max_diff) {                                             \
449           max_diff = abs_diff;                                                 \
450         }                                                                      \
451       }                                                                        \
452     }                                                                          \
453     EXPECT_LE(max_diff, 1);                                                    \
454     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                  \
455       for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X) * 2; ++j) {             \
456         int abs_diff =                                                         \
457             abs(static_cast<int>(                                              \
458                     dst_uv_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) * 2 + j]) -      \
459                 static_cast<int>(                                              \
460                     dst_uv_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) * 2 + j]));    \
461         if (abs_diff > max_diff) {                                             \
462           max_diff = abs_diff;                                                 \
463         }                                                                      \
464       }                                                                        \
465     }                                                                          \
466     EXPECT_LE(max_diff, 1);                                                    \
467     free_aligned_buffer_page_end(dst_y_c);                                     \
468     free_aligned_buffer_page_end(dst_uv_c);                                    \
469     free_aligned_buffer_page_end(dst_y_opt);                                   \
470     free_aligned_buffer_page_end(dst_uv_opt);                                  \
471     free_aligned_buffer_page_end(src_y);                                       \
472     free_aligned_buffer_page_end(src_uv);                                      \
473   }
474 
475 #define TESTBIPLANARTOBP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,        \
476                          FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y)                    \
477   TESTBIPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
478                     SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0)       \
479   TESTBIPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
480                     SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0)   \
481   TESTBIPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
482                     SUBSAMP_X, SUBSAMP_Y, benchmark_width, _Unaligned, +, 1)  \
483   TESTBIPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
484                     SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0)    \
485   TESTBIPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
486                     SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0)
487 
488 // TODO(fbarchard): Fix msan on this unittest
489 // TESTBIPLANARTOBP(NV21, 2, 2, NV12, 2, 2)
490 
491 #define TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,         \
492                          FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF, \
493                          DOY)                                                  \
494   TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) {               \
495     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
496     const int kHeight = benchmark_height_;                                     \
497     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
498     align_buffer_page_end(src_uv, 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *       \
499                                           SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) +  \
500                                       OFF);                                    \
501     align_buffer_page_end(dst_y_c, kWidth* kHeight);                           \
502     align_buffer_page_end(dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X) *              \
503                                        SUBSAMPLE(kHeight, SUBSAMP_Y));         \
504     align_buffer_page_end(dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X) *              \
505                                        SUBSAMPLE(kHeight, SUBSAMP_Y));         \
506     align_buffer_page_end(dst_y_opt, kWidth* kHeight);                         \
507     align_buffer_page_end(dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X) *            \
508                                          SUBSAMPLE(kHeight, SUBSAMP_Y));       \
509     align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) *            \
510                                          SUBSAMPLE(kHeight, SUBSAMP_Y));       \
511     for (int i = 0; i < kHeight; ++i)                                          \
512       for (int j = 0; j < kWidth; ++j)                                         \
513         src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                     \
514     for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) {              \
515       for (int j = 0; j < 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) {         \
516         src_uv[(i * 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =         \
517             (fastrand() & 0xff);                                               \
518       }                                                                        \
519     }                                                                          \
520     memset(dst_y_c, 1, kWidth* kHeight);                                       \
521     memset(dst_u_c, 2,                                                         \
522            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
523     memset(dst_v_c, 3,                                                         \
524            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
525     memset(dst_y_opt, 101, kWidth* kHeight);                                   \
526     memset(dst_u_opt, 102,                                                     \
527            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
528     memset(dst_v_opt, 103,                                                     \
529            SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
530     MaskCpuFlags(disable_cpu_flags_);                                          \
531     SRC_FMT_PLANAR##To##FMT_PLANAR(                                            \
532         src_y + OFF, kWidth, src_uv + OFF,                                     \
533         2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X), DOY ? dst_y_c : NULL, kWidth,    \
534         dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_c,                        \
535         SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight);                    \
536     MaskCpuFlags(benchmark_cpu_info_);                                         \
537     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
538       SRC_FMT_PLANAR##To##FMT_PLANAR(                                          \
539           src_y + OFF, kWidth, src_uv + OFF,                                   \
540           2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X), DOY ? dst_y_opt : NULL,        \
541           kWidth, dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_opt,          \
542           SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight);                  \
543     }                                                                          \
544     int max_diff = 0;                                                          \
545     if (DOY) {                                                                 \
546       for (int i = 0; i < kHeight; ++i) {                                      \
547         for (int j = 0; j < kWidth; ++j) {                                     \
548           int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) -       \
549                              static_cast<int>(dst_y_opt[i * kWidth + j]));     \
550           if (abs_diff > max_diff) {                                           \
551             max_diff = abs_diff;                                               \
552           }                                                                    \
553         }                                                                      \
554       }                                                                        \
555       EXPECT_LE(max_diff, 1);                                                  \
556     }                                                                          \
557     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                  \
558       for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) {                 \
559         int abs_diff = abs(                                                    \
560             static_cast<int>(dst_u_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) -  \
561             static_cast<int>(                                                  \
562                 dst_u_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]));             \
563         if (abs_diff > max_diff) {                                             \
564           max_diff = abs_diff;                                                 \
565         }                                                                      \
566       }                                                                        \
567     }                                                                          \
568     EXPECT_LE(max_diff, 1);                                                    \
569     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                  \
570       for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) {                 \
571         int abs_diff = abs(                                                    \
572             static_cast<int>(dst_v_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) -  \
573             static_cast<int>(                                                  \
574                 dst_v_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]));             \
575         if (abs_diff > max_diff) {                                             \
576           max_diff = abs_diff;                                                 \
577         }                                                                      \
578       }                                                                        \
579     }                                                                          \
580     EXPECT_LE(max_diff, 1);                                                    \
581     free_aligned_buffer_page_end(dst_y_c);                                     \
582     free_aligned_buffer_page_end(dst_u_c);                                     \
583     free_aligned_buffer_page_end(dst_v_c);                                     \
584     free_aligned_buffer_page_end(dst_y_opt);                                   \
585     free_aligned_buffer_page_end(dst_u_opt);                                   \
586     free_aligned_buffer_page_end(dst_v_opt);                                   \
587     free_aligned_buffer_page_end(src_y);                                       \
588     free_aligned_buffer_page_end(src_uv);                                      \
589   }
590 
591 #define TESTBIPLANARTOP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,         \
592                         FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y)                     \
593   TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR,  \
594                    SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0, 1) \
595   TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR,  \
596                    SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Unaligned, +, 1,  \
597                    1)                                                         \
598   TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR,  \
599                    SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0, 1)  \
600   TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR,  \
601                    SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0, 1)     \
602   TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR,  \
603                    SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _NullY, +, 0, 0)
604 
605 TESTBIPLANARTOP(NV12, 2, 2, I420, 2, 2)
606 TESTBIPLANARTOP(NV21, 2, 2, I420, 2, 2)
607 
608 #define ALIGNINT(V, ALIGN) (((V) + (ALIGN)-1) / (ALIGN) * (ALIGN))
609 
610 #define TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
611                        YALIGN, W1280, N, NEG, OFF)                            \
612   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                       \
613     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                           \
614     const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                  \
615     const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                     \
616     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                       \
617     const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);            \
618     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                      \
619     align_buffer_page_end(src_u, kSizeUV + OFF);                              \
620     align_buffer_page_end(src_v, kSizeUV + OFF);                              \
621     align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF);               \
622     align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF);             \
623     for (int i = 0; i < kWidth * kHeight; ++i) {                              \
624       src_y[i + OFF] = (fastrand() & 0xff);                                   \
625     }                                                                         \
626     for (int i = 0; i < kSizeUV; ++i) {                                       \
627       src_u[i + OFF] = (fastrand() & 0xff);                                   \
628       src_v[i + OFF] = (fastrand() & 0xff);                                   \
629     }                                                                         \
630     memset(dst_argb_c + OFF, 1, kStrideB * kHeight);                          \
631     memset(dst_argb_opt + OFF, 101, kStrideB * kHeight);                      \
632     MaskCpuFlags(disable_cpu_flags_);                                         \
633     double time0 = get_time();                                                \
634     FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV,        \
635                           src_v + OFF, kStrideUV, dst_argb_c + OFF, kStrideB, \
636                           kWidth, NEG kHeight);                               \
637     double time1 = get_time();                                                \
638     MaskCpuFlags(benchmark_cpu_info_);                                        \
639     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
640       FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV,      \
641                             src_v + OFF, kStrideUV, dst_argb_opt + OFF,       \
642                             kStrideB, kWidth, NEG kHeight);                   \
643     }                                                                         \
644     double time2 = get_time();                                                \
645     printf(" %8d us C - %8d us OPT\n",                                        \
646            static_cast<int>((time1 - time0) * 1e6),                           \
647            static_cast<int>((time2 - time1) * 1e6 / benchmark_iterations_));  \
648     for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) {                      \
649       EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_opt[i + OFF]);                  \
650     }                                                                         \
651     free_aligned_buffer_page_end(src_y);                                      \
652     free_aligned_buffer_page_end(src_u);                                      \
653     free_aligned_buffer_page_end(src_v);                                      \
654     free_aligned_buffer_page_end(dst_argb_c);                                 \
655     free_aligned_buffer_page_end(dst_argb_opt);                               \
656   }
657 
658 #define TESTPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
659                       YALIGN)                                                \
660   TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
661                  YALIGN, benchmark_width_ - 4, _Any, +, 0)                   \
662   TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
663                  YALIGN, benchmark_width_, _Unaligned, +, 1)                 \
664   TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
665                  YALIGN, benchmark_width_, _Invert, -, 0)                    \
666   TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
667                  YALIGN, benchmark_width_, _Opt, +, 0)
668 
669 TESTPLANARTOB(I420, 2, 2, ARGB, 4, 4, 1)
670 TESTPLANARTOB(J420, 2, 2, ARGB, 4, 4, 1)
671 TESTPLANARTOB(J420, 2, 2, ABGR, 4, 4, 1)
672 TESTPLANARTOB(H420, 2, 2, ARGB, 4, 4, 1)
673 TESTPLANARTOB(H420, 2, 2, ABGR, 4, 4, 1)
674 TESTPLANARTOB(I420, 2, 2, BGRA, 4, 4, 1)
675 TESTPLANARTOB(I420, 2, 2, ABGR, 4, 4, 1)
676 TESTPLANARTOB(I420, 2, 2, RGBA, 4, 4, 1)
677 TESTPLANARTOB(I420, 2, 2, RAW, 3, 3, 1)
678 TESTPLANARTOB(I420, 2, 2, RGB24, 3, 3, 1)
679 TESTPLANARTOB(H420, 2, 2, RAW, 3, 3, 1)
680 TESTPLANARTOB(H420, 2, 2, RGB24, 3, 3, 1)
681 TESTPLANARTOB(I420, 2, 2, RGB565, 2, 2, 1)
682 TESTPLANARTOB(J420, 2, 2, RGB565, 2, 2, 1)
683 TESTPLANARTOB(H420, 2, 2, RGB565, 2, 2, 1)
684 TESTPLANARTOB(I420, 2, 2, ARGB1555, 2, 2, 1)
685 TESTPLANARTOB(I420, 2, 2, ARGB4444, 2, 2, 1)
686 TESTPLANARTOB(I422, 2, 1, ARGB, 4, 4, 1)
687 TESTPLANARTOB(I422, 2, 1, RGB565, 2, 2, 1)
688 TESTPLANARTOB(J422, 2, 1, ARGB, 4, 4, 1)
689 TESTPLANARTOB(J422, 2, 1, ABGR, 4, 4, 1)
690 TESTPLANARTOB(H422, 2, 1, ARGB, 4, 4, 1)
691 TESTPLANARTOB(H422, 2, 1, ABGR, 4, 4, 1)
692 TESTPLANARTOB(I422, 2, 1, BGRA, 4, 4, 1)
693 TESTPLANARTOB(I422, 2, 1, ABGR, 4, 4, 1)
694 TESTPLANARTOB(I422, 2, 1, RGBA, 4, 4, 1)
695 TESTPLANARTOB(I444, 1, 1, ARGB, 4, 4, 1)
696 TESTPLANARTOB(J444, 1, 1, ARGB, 4, 4, 1)
697 TESTPLANARTOB(I444, 1, 1, ABGR, 4, 4, 1)
698 TESTPLANARTOB(I420, 2, 2, YUY2, 2, 4, 1)
699 TESTPLANARTOB(I420, 2, 2, UYVY, 2, 4, 1)
700 TESTPLANARTOB(I422, 2, 1, YUY2, 2, 4, 1)
701 TESTPLANARTOB(I422, 2, 1, UYVY, 2, 4, 1)
702 TESTPLANARTOB(I420, 2, 2, I400, 1, 1, 1)
703 TESTPLANARTOB(J420, 2, 2, J400, 1, 1, 1)
704 TESTPLANARTOB(I420, 2, 2, AR30, 4, 4, 1)
705 TESTPLANARTOB(H420, 2, 2, AR30, 4, 4, 1)
706 
707 #define TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
708                         YALIGN, W1280, DIFF, N, NEG, OFF, ATTEN)               \
709   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                        \
710     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
711     const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                   \
712     const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                      \
713     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                        \
714     const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);             \
715     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
716     align_buffer_page_end(src_u, kSizeUV + OFF);                               \
717     align_buffer_page_end(src_v, kSizeUV + OFF);                               \
718     align_buffer_page_end(src_a, kWidth* kHeight + OFF);                       \
719     align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF);                \
720     align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF);              \
721     for (int i = 0; i < kWidth * kHeight; ++i) {                               \
722       src_y[i + OFF] = (fastrand() & 0xff);                                    \
723       src_a[i + OFF] = (fastrand() & 0xff);                                    \
724     }                                                                          \
725     for (int i = 0; i < kSizeUV; ++i) {                                        \
726       src_u[i + OFF] = (fastrand() & 0xff);                                    \
727       src_v[i + OFF] = (fastrand() & 0xff);                                    \
728     }                                                                          \
729     memset(dst_argb_c + OFF, 1, kStrideB * kHeight);                           \
730     memset(dst_argb_opt + OFF, 101, kStrideB * kHeight);                       \
731     MaskCpuFlags(disable_cpu_flags_);                                          \
732     FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV,         \
733                           src_v + OFF, kStrideUV, src_a + OFF, kWidth,         \
734                           dst_argb_c + OFF, kStrideB, kWidth, NEG kHeight,     \
735                           ATTEN);                                              \
736     MaskCpuFlags(benchmark_cpu_info_);                                         \
737     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
738       FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV,       \
739                             src_v + OFF, kStrideUV, src_a + OFF, kWidth,       \
740                             dst_argb_opt + OFF, kStrideB, kWidth, NEG kHeight, \
741                             ATTEN);                                            \
742     }                                                                          \
743     int max_diff = 0;                                                          \
744     for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) {                       \
745       int abs_diff = abs(static_cast<int>(dst_argb_c[i + OFF]) -               \
746                          static_cast<int>(dst_argb_opt[i + OFF]));             \
747       if (abs_diff > max_diff) {                                               \
748         max_diff = abs_diff;                                                   \
749       }                                                                        \
750     }                                                                          \
751     EXPECT_LE(max_diff, DIFF);                                                 \
752     free_aligned_buffer_page_end(src_y);                                       \
753     free_aligned_buffer_page_end(src_u);                                       \
754     free_aligned_buffer_page_end(src_v);                                       \
755     free_aligned_buffer_page_end(src_a);                                       \
756     free_aligned_buffer_page_end(dst_argb_c);                                  \
757     free_aligned_buffer_page_end(dst_argb_opt);                                \
758   }
759 
760 #define TESTQPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
761                        YALIGN, DIFF)                                          \
762   TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
763                   YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, 0)          \
764   TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
765                   YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, 0)        \
766   TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
767                   YALIGN, benchmark_width_, DIFF, _Invert, -, 0, 0)           \
768   TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
769                   YALIGN, benchmark_width_, DIFF, _Opt, +, 0, 0)              \
770   TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
771                   YALIGN, benchmark_width_, DIFF, _Premult, +, 0, 1)
772 
773 TESTQPLANARTOB(I420Alpha, 2, 2, ARGB, 4, 4, 1, 2)
774 TESTQPLANARTOB(I420Alpha, 2, 2, ABGR, 4, 4, 1, 2)
775 
776 #define TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, FMT_C,       \
777                          BPP_B, W1280, DIFF, N, NEG, OFF)                      \
778   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                        \
779     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
780     const int kHeight = benchmark_height_;                                     \
781     const int kStrideB = kWidth * BPP_B;                                       \
782     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                        \
783     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
784     align_buffer_page_end(src_uv,                                              \
785                           kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y) * 2 + OFF); \
786     align_buffer_page_end(dst_argb_c, kStrideB* kHeight);                      \
787     align_buffer_page_end(dst_argb_opt, kStrideB* kHeight);                    \
788     for (int i = 0; i < kHeight; ++i)                                          \
789       for (int j = 0; j < kWidth; ++j)                                         \
790         src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                     \
791     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                  \
792       for (int j = 0; j < kStrideUV * 2; ++j) {                                \
793         src_uv[i * kStrideUV * 2 + j + OFF] = (fastrand() & 0xff);             \
794       }                                                                        \
795     }                                                                          \
796     memset(dst_argb_c, 1, kStrideB* kHeight);                                  \
797     memset(dst_argb_opt, 101, kStrideB* kHeight);                              \
798     MaskCpuFlags(disable_cpu_flags_);                                          \
799     FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_uv + OFF, kStrideUV * 2,    \
800                           dst_argb_c, kWidth * BPP_B, kWidth, NEG kHeight);    \
801     MaskCpuFlags(benchmark_cpu_info_);                                         \
802     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
803       FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_uv + OFF, kStrideUV * 2,  \
804                             dst_argb_opt, kWidth * BPP_B, kWidth,              \
805                             NEG kHeight);                                      \
806     }                                                                          \
807     /* Convert to ARGB so 565 is expanded to bytes that can be compared. */    \
808     align_buffer_page_end(dst_argb32_c, kWidth * 4 * kHeight);                 \
809     align_buffer_page_end(dst_argb32_opt, kWidth * 4 * kHeight);               \
810     memset(dst_argb32_c, 2, kWidth * 4 * kHeight);                             \
811     memset(dst_argb32_opt, 102, kWidth * 4 * kHeight);                         \
812     FMT_C##ToARGB(dst_argb_c, kStrideB, dst_argb32_c, kWidth * 4, kWidth,      \
813                   kHeight);                                                    \
814     FMT_C##ToARGB(dst_argb_opt, kStrideB, dst_argb32_opt, kWidth * 4, kWidth,  \
815                   kHeight);                                                    \
816     int max_diff = 0;                                                          \
817     for (int i = 0; i < kHeight; ++i) {                                        \
818       for (int j = 0; j < kWidth * 4; ++j) {                                   \
819         int abs_diff =                                                         \
820             abs(static_cast<int>(dst_argb32_c[i * kWidth * 4 + j]) -           \
821                 static_cast<int>(dst_argb32_opt[i * kWidth * 4 + j]));         \
822         if (abs_diff > max_diff) {                                             \
823           max_diff = abs_diff;                                                 \
824         }                                                                      \
825       }                                                                        \
826     }                                                                          \
827     EXPECT_LE(max_diff, DIFF);                                                 \
828     free_aligned_buffer_page_end(src_y);                                       \
829     free_aligned_buffer_page_end(src_uv);                                      \
830     free_aligned_buffer_page_end(dst_argb_c);                                  \
831     free_aligned_buffer_page_end(dst_argb_opt);                                \
832     free_aligned_buffer_page_end(dst_argb32_c);                                \
833     free_aligned_buffer_page_end(dst_argb32_opt);                              \
834   }
835 
836 #define TESTBIPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, FMT_C, BPP_B, \
837                         DIFF)                                                  \
838   TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, FMT_C, BPP_B,      \
839                    benchmark_width_ - 4, DIFF, _Any, +, 0)                     \
840   TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, FMT_C, BPP_B,      \
841                    benchmark_width_, DIFF, _Unaligned, +, 1)                   \
842   TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, FMT_C, BPP_B,      \
843                    benchmark_width_, DIFF, _Invert, -, 0)                      \
844   TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, FMT_C, BPP_B,      \
845                    benchmark_width_, DIFF, _Opt, +, 0)
846 
847 TESTBIPLANARTOB(NV12, 2, 2, ARGB, ARGB, 4, 2)
848 TESTBIPLANARTOB(NV21, 2, 2, ARGB, ARGB, 4, 2)
849 TESTBIPLANARTOB(NV12, 2, 2, ABGR, ABGR, 4, 2)
850 TESTBIPLANARTOB(NV21, 2, 2, ABGR, ABGR, 4, 2)
851 TESTBIPLANARTOB(NV12, 2, 2, RGB24, RGB24, 3, 2)
852 TESTBIPLANARTOB(NV21, 2, 2, RGB24, RGB24, 3, 2)
853 TESTBIPLANARTOB(NV12, 2, 2, RAW, RAW, 3, 2)
854 TESTBIPLANARTOB(NV21, 2, 2, RAW, RAW, 3, 2)
855 TESTBIPLANARTOB(NV12, 2, 2, RGB565, RGB565, 2, 9)
856 TESTBIPLANARTOB(NV21, 2, 2, YUV24, RAW, 3, 2)
857 
858 #ifdef DO_THREE_PLANES
859 // Do 3 allocations for yuv.  conventional but slower.
860 #define TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
861                        W1280, DIFF, N, NEG, OFF)                               \
862   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) {                        \
863     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
864     const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                   \
865     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                        \
866     const int kStride = (kStrideUV * SUBSAMP_X * 8 * BPP_A + 7) / 8;           \
867     align_buffer_page_end(src_argb, kStride* kHeight + OFF);                   \
868     align_buffer_page_end(dst_y_c, kWidth* kHeight);                           \
869     align_buffer_page_end(dst_u_c, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y));  \
870     align_buffer_page_end(dst_v_c, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y));  \
871     align_buffer_page_end(dst_y_opt, kWidth* kHeight);                         \
872     align_buffer_page_end(dst_u_opt,                                           \
873                           kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y));           \
874     align_buffer_page_end(dst_v_opt,                                           \
875                           kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y));           \
876     memset(dst_y_c, 1, kWidth* kHeight);                                       \
877     memset(dst_u_c, 2, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y));              \
878     memset(dst_v_c, 3, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y));              \
879     memset(dst_y_opt, 101, kWidth* kHeight);                                   \
880     memset(dst_u_opt, 102, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y));          \
881     memset(dst_v_opt, 103, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y));          \
882     for (int i = 0; i < kHeight; ++i)                                          \
883       for (int j = 0; j < kStride; ++j)                                        \
884         src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff);               \
885     MaskCpuFlags(disable_cpu_flags_);                                          \
886     FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_c, kWidth, dst_u_c,   \
887                           kStrideUV, dst_v_c, kStrideUV, kWidth, NEG kHeight); \
888     MaskCpuFlags(benchmark_cpu_info_);                                         \
889     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
890       FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_opt, kWidth,        \
891                             dst_u_opt, kStrideUV, dst_v_opt, kStrideUV,        \
892                             kWidth, NEG kHeight);                              \
893     }                                                                          \
894     for (int i = 0; i < kHeight; ++i) {                                        \
895       for (int j = 0; j < kWidth; ++j) {                                       \
896         EXPECT_NEAR(static_cast<int>(dst_y_c[i * kWidth + j]),                 \
897                     static_cast<int>(dst_y_opt[i * kWidth + j]), DIFF);        \
898       }                                                                        \
899     }                                                                          \
900     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                  \
901       for (int j = 0; j < kStrideUV; ++j) {                                    \
902         EXPECT_NEAR(static_cast<int>(dst_u_c[i * kStrideUV + j]),              \
903                     static_cast<int>(dst_u_opt[i * kStrideUV + j]), DIFF);     \
904       }                                                                        \
905     }                                                                          \
906     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                  \
907       for (int j = 0; j < kStrideUV; ++j) {                                    \
908         EXPECT_NEAR(static_cast<int>(dst_v_c[i * kStrideUV + j]),              \
909                     static_cast<int>(dst_v_opt[i * kStrideUV + j]), DIFF);     \
910       }                                                                        \
911     }                                                                          \
912     free_aligned_buffer_page_end(dst_y_c);                                     \
913     free_aligned_buffer_page_end(dst_u_c);                                     \
914     free_aligned_buffer_page_end(dst_v_c);                                     \
915     free_aligned_buffer_page_end(dst_y_opt);                                   \
916     free_aligned_buffer_page_end(dst_u_opt);                                   \
917     free_aligned_buffer_page_end(dst_v_opt);                                   \
918     free_aligned_buffer_page_end(src_argb);                                    \
919   }
920 #else
921 #define TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
922                        W1280, DIFF, N, NEG, OFF)                               \
923   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) {                        \
924     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
925     const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                   \
926     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                        \
927     const int kStride = (kStrideUV * SUBSAMP_X * 8 * BPP_A + 7) / 8;           \
928     align_buffer_page_end(src_argb, kStride* kHeight + OFF);                   \
929     align_buffer_page_end(dst_y_c, kWidth* kHeight);                           \
930     align_buffer_page_end(dst_uv_c,                                            \
931                           kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
932     align_buffer_page_end(dst_y_opt, kWidth* kHeight);                         \
933     align_buffer_page_end(dst_uv_opt,                                          \
934                           kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
935     memset(dst_y_c, 1, kWidth* kHeight);                                       \
936     memset(dst_uv_c, 2, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));        \
937     memset(dst_y_opt, 101, kWidth* kHeight);                                   \
938     memset(dst_uv_opt, 102, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));    \
939     for (int i = 0; i < kHeight; ++i)                                          \
940       for (int j = 0; j < kStride; ++j)                                        \
941         src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff);               \
942     MaskCpuFlags(disable_cpu_flags_);                                          \
943     FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_c, kWidth, dst_uv_c,  \
944                           kStrideUV * 2, dst_uv_c + kStrideUV, kStrideUV * 2,  \
945                           kWidth, NEG kHeight);                                \
946     MaskCpuFlags(benchmark_cpu_info_);                                         \
947     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
948       FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_opt, kWidth,        \
949                             dst_uv_opt, kStrideUV * 2, dst_uv_opt + kStrideUV, \
950                             kStrideUV * 2, kWidth, NEG kHeight);               \
951     }                                                                          \
952     for (int i = 0; i < kHeight; ++i) {                                        \
953       for (int j = 0; j < kWidth; ++j) {                                       \
954         EXPECT_NEAR(static_cast<int>(dst_y_c[i * kWidth + j]),                 \
955                     static_cast<int>(dst_y_opt[i * kWidth + j]), DIFF);        \
956       }                                                                        \
957     }                                                                          \
958     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y) * 2; ++i) {              \
959       for (int j = 0; j < kStrideUV; ++j) {                                    \
960         EXPECT_NEAR(static_cast<int>(dst_uv_c[i * kStrideUV + j]),             \
961                     static_cast<int>(dst_uv_opt[i * kStrideUV + j]), DIFF);    \
962       }                                                                        \
963     }                                                                          \
964     free_aligned_buffer_page_end(dst_y_c);                                     \
965     free_aligned_buffer_page_end(dst_uv_c);                                    \
966     free_aligned_buffer_page_end(dst_y_opt);                                   \
967     free_aligned_buffer_page_end(dst_uv_opt);                                  \
968     free_aligned_buffer_page_end(src_argb);                                    \
969   }
970 #endif
971 
972 #define TESTATOPLANAR(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
973                       DIFF)                                                   \
974   TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
975                  benchmark_width_ - 4, DIFF, _Any, +, 0)                      \
976   TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
977                  benchmark_width_, DIFF, _Unaligned, +, 1)                    \
978   TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
979                  benchmark_width_, DIFF, _Invert, -, 0)                       \
980   TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
981                  benchmark_width_, DIFF, _Opt, +, 0)
982 
983 TESTATOPLANAR(ABGR, 4, 1, I420, 2, 2, 4)
984 TESTATOPLANAR(ARGB, 4, 1, I420, 2, 2, 4)
985 TESTATOPLANAR(ARGB, 4, 1, I422, 2, 1, 2)
986 TESTATOPLANAR(ARGB, 4, 1, I444, 1, 1, 2)
987 TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2, ARM_YUV_ERROR)
988 TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1, ARM_YUV_ERROR)
989 TESTATOPLANAR(ARGB1555, 2, 1, I420, 2, 2, 15)
990 TESTATOPLANAR(ARGB4444, 2, 1, I420, 2, 2, 17)
991 TESTATOPLANAR(BGRA, 4, 1, I420, 2, 2, 4)
992 TESTATOPLANAR(I400, 1, 1, I420, 2, 2, 2)
993 TESTATOPLANAR(J400, 1, 1, J420, 2, 2, 2)
994 TESTATOPLANAR(RAW, 3, 1, I420, 2, 2, 4)
995 TESTATOPLANAR(RGB24, 3, 1, I420, 2, 2, 4)
996 // TODO(fbarchard): Investigate J420 error of 11 on Windows.
997 TESTATOPLANAR(RGB24, 3, 1, J420, 2, 2, 11)
998 TESTATOPLANAR(RGB565, 2, 1, I420, 2, 2, 5)
999 TESTATOPLANAR(RGBA, 4, 1, I420, 2, 2, 4)
1000 TESTATOPLANAR(UYVY, 2, 1, I420, 2, 2, 2)
1001 TESTATOPLANAR(UYVY, 2, 1, I422, 2, 1, 2)
1002 TESTATOPLANAR(YUY2, 2, 1, I420, 2, 2, 2)
1003 TESTATOPLANAR(YUY2, 2, 1, I422, 2, 1, 2)
1004 
1005 #define TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X,          \
1006                          SUBSAMP_Y, W1280, N, NEG, OFF)                       \
1007   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) {                       \
1008     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                           \
1009     const int kHeight = benchmark_height_;                                    \
1010     const int kStride = SUBSAMPLE(kWidth, SUB_A) * BPP_A;                     \
1011     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                       \
1012     align_buffer_page_end(src_argb, kStride* kHeight + OFF);                  \
1013     align_buffer_page_end(dst_y_c, kWidth* kHeight);                          \
1014     align_buffer_page_end(dst_uv_c,                                           \
1015                           kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));     \
1016     align_buffer_page_end(dst_y_opt, kWidth* kHeight);                        \
1017     align_buffer_page_end(dst_uv_opt,                                         \
1018                           kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));     \
1019     for (int i = 0; i < kHeight; ++i)                                         \
1020       for (int j = 0; j < kStride; ++j)                                       \
1021         src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff);              \
1022     memset(dst_y_c, 1, kWidth* kHeight);                                      \
1023     memset(dst_uv_c, 2, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));       \
1024     memset(dst_y_opt, 101, kWidth* kHeight);                                  \
1025     memset(dst_uv_opt, 102, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));   \
1026     MaskCpuFlags(disable_cpu_flags_);                                         \
1027     FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_c, kWidth, dst_uv_c, \
1028                           kStrideUV * 2, kWidth, NEG kHeight);                \
1029     MaskCpuFlags(benchmark_cpu_info_);                                        \
1030     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
1031       FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_opt, kWidth,       \
1032                             dst_uv_opt, kStrideUV * 2, kWidth, NEG kHeight);  \
1033     }                                                                         \
1034     int max_diff = 0;                                                         \
1035     for (int i = 0; i < kHeight; ++i) {                                       \
1036       for (int j = 0; j < kWidth; ++j) {                                      \
1037         int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) -        \
1038                            static_cast<int>(dst_y_opt[i * kWidth + j]));      \
1039         if (abs_diff > max_diff) {                                            \
1040           max_diff = abs_diff;                                                \
1041         }                                                                     \
1042       }                                                                       \
1043     }                                                                         \
1044     EXPECT_LE(max_diff, 4);                                                   \
1045     for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                 \
1046       for (int j = 0; j < kStrideUV * 2; ++j) {                               \
1047         int abs_diff =                                                        \
1048             abs(static_cast<int>(dst_uv_c[i * kStrideUV * 2 + j]) -           \
1049                 static_cast<int>(dst_uv_opt[i * kStrideUV * 2 + j]));         \
1050         if (abs_diff > max_diff) {                                            \
1051           max_diff = abs_diff;                                                \
1052         }                                                                     \
1053       }                                                                       \
1054     }                                                                         \
1055     EXPECT_LE(max_diff, 4);                                                   \
1056     free_aligned_buffer_page_end(dst_y_c);                                    \
1057     free_aligned_buffer_page_end(dst_uv_c);                                   \
1058     free_aligned_buffer_page_end(dst_y_opt);                                  \
1059     free_aligned_buffer_page_end(dst_uv_opt);                                 \
1060     free_aligned_buffer_page_end(src_argb);                                   \
1061   }
1062 
1063 #define TESTATOBIPLANAR(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \
1064   TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
1065                    benchmark_width_ - 4, _Any, +, 0)                           \
1066   TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
1067                    benchmark_width_, _Unaligned, +, 1)                         \
1068   TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
1069                    benchmark_width_, _Invert, -, 0)                            \
1070   TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,      \
1071                    benchmark_width_, _Opt, +, 0)
1072 
1073 TESTATOBIPLANAR(ARGB, 1, 4, NV12, 2, 2)
1074 TESTATOBIPLANAR(ARGB, 1, 4, NV21, 2, 2)
1075 TESTATOBIPLANAR(YUY2, 2, 4, NV12, 2, 2)
1076 TESTATOBIPLANAR(UYVY, 2, 4, NV12, 2, 2)
1077 TESTATOBIPLANAR(AYUV, 1, 4, NV12, 2, 2)
1078 TESTATOBIPLANAR(AYUV, 1, 4, NV21, 2, 2)
1079 
1080 #define TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,  \
1081                   HEIGHT_B, W1280, DIFF, N, NEG, OFF)                        \
1082   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##N) {                           \
1083     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                          \
1084     const int kHeight = benchmark_height_;                                   \
1085     const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;     \
1086     const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B;     \
1087     const int kStrideA =                                                     \
1088         (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;               \
1089     const int kStrideB =                                                     \
1090         (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;               \
1091     align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF);               \
1092     align_buffer_page_end(dst_argb_c, kStrideB* kHeightB);                   \
1093     align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB);                 \
1094     for (int i = 0; i < kStrideA * kHeightA; ++i) {                          \
1095       src_argb[i + OFF] = (fastrand() & 0xff);                               \
1096     }                                                                        \
1097     memset(dst_argb_c, 1, kStrideB* kHeightB);                               \
1098     memset(dst_argb_opt, 101, kStrideB* kHeightB);                           \
1099     MaskCpuFlags(disable_cpu_flags_);                                        \
1100     FMT_A##To##FMT_B(src_argb + OFF, kStrideA, dst_argb_c, kStrideB, kWidth, \
1101                      NEG kHeight);                                           \
1102     MaskCpuFlags(benchmark_cpu_info_);                                       \
1103     for (int i = 0; i < benchmark_iterations_; ++i) {                        \
1104       FMT_A##To##FMT_B(src_argb + OFF, kStrideA, dst_argb_opt, kStrideB,     \
1105                        kWidth, NEG kHeight);                                 \
1106     }                                                                        \
1107     int max_diff = 0;                                                        \
1108     for (int i = 0; i < kStrideB * kHeightB; ++i) {                          \
1109       int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -                   \
1110                          static_cast<int>(dst_argb_opt[i]));                 \
1111       if (abs_diff > max_diff) {                                             \
1112         max_diff = abs_diff;                                                 \
1113       }                                                                      \
1114     }                                                                        \
1115     EXPECT_LE(max_diff, DIFF);                                               \
1116     free_aligned_buffer_page_end(src_argb);                                  \
1117     free_aligned_buffer_page_end(dst_argb_c);                                \
1118     free_aligned_buffer_page_end(dst_argb_opt);                              \
1119   }
1120 
1121 #define TESTATOBRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B,     \
1122                        STRIDE_B, HEIGHT_B, DIFF)                           \
1123   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##_Random) {                   \
1124     for (int times = 0; times < benchmark_iterations_; ++times) {          \
1125       const int kWidth = (fastrand() & 63) + 1;                            \
1126       const int kHeight = (fastrand() & 31) + 1;                           \
1127       const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
1128       const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B; \
1129       const int kStrideA =                                                 \
1130           (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;           \
1131       const int kStrideB =                                                 \
1132           (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;           \
1133       align_buffer_page_end(src_argb, kStrideA* kHeightA);                 \
1134       align_buffer_page_end(dst_argb_c, kStrideB* kHeightB);               \
1135       align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB);             \
1136       for (int i = 0; i < kStrideA * kHeightA; ++i) {                      \
1137         src_argb[i] = (fastrand() & 0xff);                                 \
1138       }                                                                    \
1139       memset(dst_argb_c, 123, kStrideB* kHeightB);                         \
1140       memset(dst_argb_opt, 123, kStrideB* kHeightB);                       \
1141       MaskCpuFlags(disable_cpu_flags_);                                    \
1142       FMT_A##To##FMT_B(src_argb, kStrideA, dst_argb_c, kStrideB, kWidth,   \
1143                        kHeight);                                           \
1144       MaskCpuFlags(benchmark_cpu_info_);                                   \
1145       FMT_A##To##FMT_B(src_argb, kStrideA, dst_argb_opt, kStrideB, kWidth, \
1146                        kHeight);                                           \
1147       for (int i = 0; i < kStrideB * kHeightB; ++i) {                      \
1148         EXPECT_NEAR(dst_argb_c[i], dst_argb_opt[i], DIFF);                 \
1149       }                                                                    \
1150       free_aligned_buffer_page_end(src_argb);                              \
1151       free_aligned_buffer_page_end(dst_argb_c);                            \
1152       free_aligned_buffer_page_end(dst_argb_opt);                          \
1153     }                                                                      \
1154   }
1155 
1156 #define TESTATOB(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1157                  HEIGHT_B, DIFF)                                           \
1158   TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1159             HEIGHT_B, benchmark_width_ - 4, DIFF, _Any, +, 0)              \
1160   TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1161             HEIGHT_B, benchmark_width_, DIFF, _Unaligned, +, 1)            \
1162   TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1163             HEIGHT_B, benchmark_width_, DIFF, _Invert, -, 0)               \
1164   TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1165             HEIGHT_B, benchmark_width_, DIFF, _Opt, +, 0)                  \
1166   TESTATOBRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1167                  HEIGHT_B, DIFF)
1168 
1169 // TODO(fbarchard): make ARM version of C code that matches NEON.
1170 TESTATOB(AB30, 4, 4, 1, ABGR, 4, 4, 1, 0)
1171 TESTATOB(AB30, 4, 4, 1, ARGB, 4, 4, 1, 0)
1172 TESTATOB(ABGR, 4, 4, 1, AR30, 4, 4, 1, 0)
1173 TESTATOB(ABGR, 4, 4, 1, ARGB, 4, 4, 1, 0)
1174 TESTATOB(AR30, 4, 4, 1, AB30, 4, 4, 1, 0)
1175 TESTATOB(AR30, 4, 4, 1, ABGR, 4, 4, 1, 0)
1176 TESTATOB(AR30, 4, 4, 1, AR30, 4, 4, 1, 0)
1177 TESTATOB(AR30, 4, 4, 1, ARGB, 4, 4, 1, 0)
1178 TESTATOB(ARGB, 4, 4, 1, ABGR, 4, 4, 1, 0)
1179 TESTATOB(ARGB, 4, 4, 1, AR30, 4, 4, 1, 0)
1180 TESTATOB(ARGB, 4, 4, 1, ARGB, 4, 4, 1, 0)
1181 TESTATOB(ARGB, 4, 4, 1, ARGB1555, 2, 2, 1, 0)
1182 TESTATOB(ARGB, 4, 4, 1, ARGB4444, 2, 2, 1, 0)
1183 TESTATOB(ARGB, 4, 4, 1, ARGBMirror, 4, 4, 1, 0)
1184 TESTATOB(ARGB, 4, 4, 1, BGRA, 4, 4, 1, 0)
1185 TESTATOB(ARGB, 4, 4, 1, I400, 1, 1, 1, 2)
1186 TESTATOB(ARGB, 4, 4, 1, J400, 1, 1, 1, 2)
1187 TESTATOB(ARGB, 4, 4, 1, RAW, 3, 3, 1, 0)
1188 TESTATOB(ARGB, 4, 4, 1, RGB24, 3, 3, 1, 0)
1189 TESTATOB(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0)
1190 TESTATOB(ARGB, 4, 4, 1, RGBA, 4, 4, 1, 0)
1191 TESTATOB(ARGB, 4, 4, 1, UYVY, 2, 4, 1, 4)
1192 TESTATOB(ARGB, 4, 4, 1, YUY2, 2, 4, 1, 4)
1193 TESTATOB(ARGB1555, 2, 2, 1, ARGB, 4, 4, 1, 0)
1194 TESTATOB(ARGB4444, 2, 2, 1, ARGB, 4, 4, 1, 0)
1195 TESTATOB(BGRA, 4, 4, 1, ARGB, 4, 4, 1, 0)
1196 TESTATOB(I400, 1, 1, 1, ARGB, 4, 4, 1, 0)
1197 TESTATOB(I400, 1, 1, 1, I400, 1, 1, 1, 0)
1198 TESTATOB(I400, 1, 1, 1, I400Mirror, 1, 1, 1, 0)
1199 TESTATOB(J400, 1, 1, 1, ARGB, 4, 4, 1, 0)
1200 TESTATOB(J400, 1, 1, 1, J400, 1, 1, 1, 0)
1201 TESTATOB(RAW, 3, 3, 1, ARGB, 4, 4, 1, 0)
1202 TESTATOB(RAW, 3, 3, 1, RGB24, 3, 3, 1, 0)
1203 TESTATOB(RGB24, 3, 3, 1, ARGB, 4, 4, 1, 0)
1204 TESTATOB(RGB24, 3, 3, 1, J400, 1, 1, 1, 0)
1205 TESTATOB(RGB565, 2, 2, 1, ARGB, 4, 4, 1, 0)
1206 TESTATOB(RGBA, 4, 4, 1, ARGB, 4, 4, 1, 0)
1207 TESTATOB(UYVY, 2, 4, 1, ARGB, 4, 4, 1, ARM_YUV_ERROR)
1208 TESTATOB(YUY2, 2, 4, 1, ARGB, 4, 4, 1, ARM_YUV_ERROR)
1209 TESTATOB(YUY2, 2, 4, 1, Y, 1, 1, 1, 0)
1210 
1211 #define TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1212                    HEIGHT_B, W1280, DIFF, N, NEG, OFF)                       \
1213   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##Dither##N) {                   \
1214     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                          \
1215     const int kHeight = benchmark_height_;                                   \
1216     const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;     \
1217     const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B;     \
1218     const int kStrideA =                                                     \
1219         (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;               \
1220     const int kStrideB =                                                     \
1221         (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;               \
1222     align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF);               \
1223     align_buffer_page_end(dst_argb_c, kStrideB* kHeightB);                   \
1224     align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB);                 \
1225     for (int i = 0; i < kStrideA * kHeightA; ++i) {                          \
1226       src_argb[i + OFF] = (fastrand() & 0xff);                               \
1227     }                                                                        \
1228     memset(dst_argb_c, 1, kStrideB* kHeightB);                               \
1229     memset(dst_argb_opt, 101, kStrideB* kHeightB);                           \
1230     MaskCpuFlags(disable_cpu_flags_);                                        \
1231     FMT_A##To##FMT_B##Dither(src_argb + OFF, kStrideA, dst_argb_c, kStrideB, \
1232                              NULL, kWidth, NEG kHeight);                     \
1233     MaskCpuFlags(benchmark_cpu_info_);                                       \
1234     for (int i = 0; i < benchmark_iterations_; ++i) {                        \
1235       FMT_A##To##FMT_B##Dither(src_argb + OFF, kStrideA, dst_argb_opt,       \
1236                                kStrideB, NULL, kWidth, NEG kHeight);         \
1237     }                                                                        \
1238     int max_diff = 0;                                                        \
1239     for (int i = 0; i < kStrideB * kHeightB; ++i) {                          \
1240       int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -                   \
1241                          static_cast<int>(dst_argb_opt[i]));                 \
1242       if (abs_diff > max_diff) {                                             \
1243         max_diff = abs_diff;                                                 \
1244       }                                                                      \
1245     }                                                                        \
1246     EXPECT_LE(max_diff, DIFF);                                               \
1247     free_aligned_buffer_page_end(src_argb);                                  \
1248     free_aligned_buffer_page_end(dst_argb_c);                                \
1249     free_aligned_buffer_page_end(dst_argb_opt);                              \
1250   }
1251 
1252 #define TESTATOBDRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B,        \
1253                         STRIDE_B, HEIGHT_B, DIFF)                              \
1254   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##Dither_Random) {                 \
1255     for (int times = 0; times < benchmark_iterations_; ++times) {              \
1256       const int kWidth = (fastrand() & 63) + 1;                                \
1257       const int kHeight = (fastrand() & 31) + 1;                               \
1258       const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;     \
1259       const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B;     \
1260       const int kStrideA =                                                     \
1261           (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;               \
1262       const int kStrideB =                                                     \
1263           (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;               \
1264       align_buffer_page_end(src_argb, kStrideA* kHeightA);                     \
1265       align_buffer_page_end(dst_argb_c, kStrideB* kHeightB);                   \
1266       align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB);                 \
1267       for (int i = 0; i < kStrideA * kHeightA; ++i) {                          \
1268         src_argb[i] = (fastrand() & 0xff);                                     \
1269       }                                                                        \
1270       memset(dst_argb_c, 123, kStrideB* kHeightB);                             \
1271       memset(dst_argb_opt, 123, kStrideB* kHeightB);                           \
1272       MaskCpuFlags(disable_cpu_flags_);                                        \
1273       FMT_A##To##FMT_B##Dither(src_argb, kStrideA, dst_argb_c, kStrideB, NULL, \
1274                                kWidth, kHeight);                               \
1275       MaskCpuFlags(benchmark_cpu_info_);                                       \
1276       FMT_A##To##FMT_B##Dither(src_argb, kStrideA, dst_argb_opt, kStrideB,     \
1277                                NULL, kWidth, kHeight);                         \
1278       int max_diff = 0;                                                        \
1279       for (int i = 0; i < kStrideB * kHeightB; ++i) {                          \
1280         int abs_diff = abs(static_cast<int>(dst_argb_c[i]) -                   \
1281                            static_cast<int>(dst_argb_opt[i]));                 \
1282         if (abs_diff > max_diff) {                                             \
1283           max_diff = abs_diff;                                                 \
1284         }                                                                      \
1285       }                                                                        \
1286       EXPECT_LE(max_diff, DIFF);                                               \
1287       free_aligned_buffer_page_end(src_argb);                                  \
1288       free_aligned_buffer_page_end(dst_argb_c);                                \
1289       free_aligned_buffer_page_end(dst_argb_opt);                              \
1290     }                                                                          \
1291   }
1292 
1293 #define TESTATOBD(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1294                   HEIGHT_B, DIFF)                                           \
1295   TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1296              HEIGHT_B, benchmark_width_ - 4, DIFF, _Any, +, 0)              \
1297   TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1298              HEIGHT_B, benchmark_width_, DIFF, _Unaligned, +, 1)            \
1299   TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1300              HEIGHT_B, benchmark_width_, DIFF, _Invert, -, 0)               \
1301   TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B,      \
1302              HEIGHT_B, benchmark_width_, DIFF, _Opt, +, 0)                  \
1303   TESTATOBDRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1304                   HEIGHT_B, DIFF)
1305 
1306 TESTATOBD(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0)
1307 
1308 #define TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, W1280, N, NEG, OFF)      \
1309   TEST_F(LibYUVConvertTest, FMT_ATOB##_Symetric##N) {                          \
1310     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
1311     const int kHeight = benchmark_height_;                                     \
1312     const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;       \
1313     const int kStrideA =                                                       \
1314         (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;                 \
1315     align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF);                 \
1316     align_buffer_page_end(dst_argb_c, kStrideA* kHeightA);                     \
1317     align_buffer_page_end(dst_argb_opt, kStrideA* kHeightA);                   \
1318     for (int i = 0; i < kStrideA * kHeightA; ++i) {                            \
1319       src_argb[i + OFF] = (fastrand() & 0xff);                                 \
1320     }                                                                          \
1321     memset(dst_argb_c, 1, kStrideA* kHeightA);                                 \
1322     memset(dst_argb_opt, 101, kStrideA* kHeightA);                             \
1323     MaskCpuFlags(disable_cpu_flags_);                                          \
1324     FMT_ATOB(src_argb + OFF, kStrideA, dst_argb_c, kStrideA, kWidth,           \
1325              NEG kHeight);                                                     \
1326     MaskCpuFlags(benchmark_cpu_info_);                                         \
1327     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
1328       FMT_ATOB(src_argb + OFF, kStrideA, dst_argb_opt, kStrideA, kWidth,       \
1329                NEG kHeight);                                                   \
1330     }                                                                          \
1331     MaskCpuFlags(disable_cpu_flags_);                                          \
1332     FMT_ATOB(dst_argb_c, kStrideA, dst_argb_c, kStrideA, kWidth, NEG kHeight); \
1333     MaskCpuFlags(benchmark_cpu_info_);                                         \
1334     FMT_ATOB(dst_argb_opt, kStrideA, dst_argb_opt, kStrideA, kWidth,           \
1335              NEG kHeight);                                                     \
1336     for (int i = 0; i < kStrideA * kHeightA; ++i) {                            \
1337       EXPECT_EQ(src_argb[i + OFF], dst_argb_opt[i]);                           \
1338       EXPECT_EQ(dst_argb_c[i], dst_argb_opt[i]);                               \
1339     }                                                                          \
1340     free_aligned_buffer_page_end(src_argb);                                    \
1341     free_aligned_buffer_page_end(dst_argb_c);                                  \
1342     free_aligned_buffer_page_end(dst_argb_opt);                                \
1343   }
1344 
1345 #define TESTSYM(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A)                           \
1346   TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_ - 4, _Any, +, \
1347            0)                                                                  \
1348   TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_, _Unaligned,  \
1349            +, 1)                                                               \
1350   TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_, _Opt, +, 0)
1351 
1352 TESTSYM(ARGBToARGB, 4, 4, 1)
1353 TESTSYM(ARGBToBGRA, 4, 4, 1)
1354 TESTSYM(ARGBToABGR, 4, 4, 1)
1355 TESTSYM(BGRAToARGB, 4, 4, 1)
1356 TESTSYM(ABGRToARGB, 4, 4, 1)
1357 
TEST_F(LibYUVConvertTest,Test565)1358 TEST_F(LibYUVConvertTest, Test565) {
1359   SIMD_ALIGNED(uint8_t orig_pixels[256][4]);
1360   SIMD_ALIGNED(uint8_t pixels565[256][2]);
1361 
1362   for (int i = 0; i < 256; ++i) {
1363     for (int j = 0; j < 4; ++j) {
1364       orig_pixels[i][j] = i;
1365     }
1366   }
1367   ARGBToRGB565(&orig_pixels[0][0], 0, &pixels565[0][0], 0, 256, 1);
1368   uint32_t checksum = HashDjb2(&pixels565[0][0], sizeof(pixels565), 5381);
1369   EXPECT_EQ(610919429u, checksum);
1370 }
1371 
1372 #ifdef HAVE_JPEG
TEST_F(LibYUVConvertTest,ValidateJpeg)1373 TEST_F(LibYUVConvertTest, ValidateJpeg) {
1374   const int kOff = 10;
1375   const int kMinJpeg = 64;
1376   const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1377                              ? benchmark_width_ * benchmark_height_
1378                              : kMinJpeg;
1379   const int kSize = kImageSize + kOff;
1380   align_buffer_page_end(orig_pixels, kSize);
1381 
1382   // No SOI or EOI. Expect fail.
1383   memset(orig_pixels, 0, kSize);
1384   EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1385 
1386   // Test special value that matches marker start.
1387   memset(orig_pixels, 0xff, kSize);
1388   EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1389 
1390   // EOI, SOI. Expect pass.
1391   orig_pixels[0] = 0xff;
1392   orig_pixels[1] = 0xd8;  // SOI.
1393   orig_pixels[2] = 0xff;
1394   orig_pixels[kSize - kOff + 0] = 0xff;
1395   orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1396   for (int times = 0; times < benchmark_iterations_; ++times) {
1397     EXPECT_TRUE(ValidateJpeg(orig_pixels, kSize));
1398   }
1399   free_aligned_buffer_page_end(orig_pixels);
1400 }
1401 
TEST_F(LibYUVConvertTest,ValidateJpegLarge)1402 TEST_F(LibYUVConvertTest, ValidateJpegLarge) {
1403   const int kOff = 10;
1404   const int kMinJpeg = 64;
1405   const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1406                              ? benchmark_width_ * benchmark_height_
1407                              : kMinJpeg;
1408   const int kSize = kImageSize + kOff;
1409   const int kMultiple = 10;
1410   const int kBufSize = kImageSize * kMultiple + kOff;
1411   align_buffer_page_end(orig_pixels, kBufSize);
1412 
1413   // No SOI or EOI. Expect fail.
1414   memset(orig_pixels, 0, kBufSize);
1415   EXPECT_FALSE(ValidateJpeg(orig_pixels, kBufSize));
1416 
1417   // EOI, SOI. Expect pass.
1418   orig_pixels[0] = 0xff;
1419   orig_pixels[1] = 0xd8;  // SOI.
1420   orig_pixels[2] = 0xff;
1421   orig_pixels[kSize - kOff + 0] = 0xff;
1422   orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1423   for (int times = 0; times < benchmark_iterations_; ++times) {
1424     EXPECT_TRUE(ValidateJpeg(orig_pixels, kBufSize));
1425   }
1426   free_aligned_buffer_page_end(orig_pixels);
1427 }
1428 
TEST_F(LibYUVConvertTest,InvalidateJpeg)1429 TEST_F(LibYUVConvertTest, InvalidateJpeg) {
1430   const int kOff = 10;
1431   const int kMinJpeg = 64;
1432   const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1433                              ? benchmark_width_ * benchmark_height_
1434                              : kMinJpeg;
1435   const int kSize = kImageSize + kOff;
1436   align_buffer_page_end(orig_pixels, kSize);
1437 
1438   // NULL pointer. Expect fail.
1439   EXPECT_FALSE(ValidateJpeg(NULL, kSize));
1440 
1441   // Negative size. Expect fail.
1442   EXPECT_FALSE(ValidateJpeg(orig_pixels, -1));
1443 
1444   // Too large size. Expect fail.
1445   EXPECT_FALSE(ValidateJpeg(orig_pixels, 0xfb000000ull));
1446 
1447   // No SOI or EOI. Expect fail.
1448   memset(orig_pixels, 0, kSize);
1449   EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1450 
1451   // SOI but no EOI. Expect fail.
1452   orig_pixels[0] = 0xff;
1453   orig_pixels[1] = 0xd8;  // SOI.
1454   orig_pixels[2] = 0xff;
1455   for (int times = 0; times < benchmark_iterations_; ++times) {
1456     EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1457   }
1458 
1459   // EOI but no SOI. Expect fail.
1460   orig_pixels[0] = 0;
1461   orig_pixels[1] = 0;
1462   orig_pixels[kSize - kOff + 0] = 0xff;
1463   orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1464   EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1465 
1466   free_aligned_buffer_page_end(orig_pixels);
1467 }
1468 
TEST_F(LibYUVConvertTest,FuzzJpeg)1469 TEST_F(LibYUVConvertTest, FuzzJpeg) {
1470   // SOI but no EOI. Expect fail.
1471   for (int times = 0; times < benchmark_iterations_; ++times) {
1472     const int kSize = fastrand() % 5000 + 3;
1473     align_buffer_page_end(orig_pixels, kSize);
1474     MemRandomize(orig_pixels, kSize);
1475 
1476     // Add SOI so frame will be scanned.
1477     orig_pixels[0] = 0xff;
1478     orig_pixels[1] = 0xd8;  // SOI.
1479     orig_pixels[2] = 0xff;
1480     orig_pixels[kSize - 1] = 0xff;
1481     ValidateJpeg(orig_pixels,
1482                  kSize);  // Failure normally expected.
1483     free_aligned_buffer_page_end(orig_pixels);
1484   }
1485 }
1486 
1487 // Test data created in GIMP.  In export jpeg, disable
1488 // thumbnails etc, choose a subsampling, and use low quality
1489 // (50) to keep size small. Generated with xxd -i test.jpg
1490 // test 0 is J400
1491 static const uint8_t kTest0Jpg[] = {
1492     0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
1493     0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43,
1494     0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d, 0x0e, 0x12,
1495     0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23,
1496     0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40,
1497     0x48, 0x5c, 0x4e, 0x40, 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51,
1498     0x57, 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
1499     0x78, 0x5c, 0x65, 0x67, 0x63, 0xff, 0xc2, 0x00, 0x0b, 0x08, 0x00, 0x10,
1500     0x00, 0x20, 0x01, 0x01, 0x11, 0x00, 0xff, 0xc4, 0x00, 0x17, 0x00, 0x01,
1501     0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1502     0x00, 0x00, 0x00, 0x03, 0x04, 0x01, 0x02, 0xff, 0xda, 0x00, 0x08, 0x01,
1503     0x01, 0x00, 0x00, 0x00, 0x01, 0x43, 0x7e, 0xa7, 0x97, 0x57, 0xff, 0xc4,
1504     0x00, 0x1b, 0x10, 0x00, 0x03, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00,
1505     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x11, 0x00, 0x03,
1506     0x10, 0x12, 0x13, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x05,
1507     0x02, 0x3b, 0xc0, 0x6f, 0x66, 0x76, 0x56, 0x23, 0x87, 0x99, 0x0d, 0x26,
1508     0x62, 0xf6, 0xbf, 0xff, 0xc4, 0x00, 0x1e, 0x10, 0x00, 0x02, 0x01, 0x03,
1509     0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1510     0x00, 0x11, 0x21, 0x02, 0x12, 0x32, 0x10, 0x31, 0x71, 0x81, 0xa1, 0xff,
1511     0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x06, 0x3f, 0x02, 0x4b, 0xb3, 0x28,
1512     0x32, 0xd2, 0xed, 0xf9, 0x1d, 0x3e, 0x13, 0x51, 0x73, 0x83, 0xff, 0xc4,
1513     0x00, 0x1c, 0x10, 0x01, 0x01, 0x01, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00,
1514     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x21, 0x51,
1515     0x31, 0x61, 0x81, 0xf0, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01,
1516     0x3f, 0x21, 0x65, 0x6e, 0x31, 0x86, 0x28, 0xf9, 0x30, 0xdc, 0x27, 0xdb,
1517     0xa9, 0x01, 0xf3, 0xde, 0x02, 0xa0, 0xed, 0x1e, 0x34, 0x68, 0x23, 0xf9,
1518     0xc6, 0x48, 0x5d, 0x7a, 0x35, 0x02, 0xf5, 0x6f, 0xff, 0xda, 0x00, 0x08,
1519     0x01, 0x01, 0x00, 0x00, 0x00, 0x10, 0x35, 0xff, 0xc4, 0x00, 0x1f, 0x10,
1520     0x01, 0x00, 0x02, 0x01, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1521     0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x31, 0x41, 0x61, 0x71, 0x91,
1522     0x21, 0x81, 0xd1, 0xb1, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01,
1523     0x3f, 0x10, 0x0b, 0x30, 0xe9, 0x58, 0xbe, 0x1a, 0xfd, 0x88, 0xab, 0x8b,
1524     0x34, 0x74, 0x80, 0x4b, 0xb5, 0xd5, 0xab, 0xcd, 0x46, 0x96, 0x2e, 0xec,
1525     0xbd, 0xaa, 0x78, 0x47, 0x5c, 0x47, 0xa7, 0x30, 0x49, 0xad, 0x88, 0x7c,
1526     0x40, 0x74, 0x30, 0xff, 0x00, 0x23, 0x1d, 0x03, 0x0b, 0xb7, 0xd4, 0xff,
1527     0xd9};
1528 static const size_t kTest0JpgLen = 421;
1529 
1530 // test 1 is J444
1531 static const uint8_t kTest1Jpg[] = {
1532     0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
1533     0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43,
1534     0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d, 0x0e, 0x12,
1535     0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23,
1536     0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40,
1537     0x48, 0x5c, 0x4e, 0x40, 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51,
1538     0x57, 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
1539     0x78, 0x5c, 0x65, 0x67, 0x63, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x11, 0x12,
1540     0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
1541     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1542     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1543     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1544     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1545     0x63, 0x63, 0xff, 0xc2, 0x00, 0x11, 0x08, 0x00, 0x10, 0x00, 0x20, 0x03,
1546     0x01, 0x11, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00,
1547     0x17, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1548     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x01, 0x02, 0xff, 0xc4,
1549     0x00, 0x16, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1550     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0xff, 0xda,
1551     0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x10, 0x03, 0x10, 0x00, 0x00, 0x01,
1552     0x40, 0x8f, 0x26, 0xe8, 0xf4, 0xcc, 0xf9, 0x69, 0x2b, 0x1b, 0x2a, 0xcb,
1553     0xff, 0xc4, 0x00, 0x1b, 0x10, 0x00, 0x03, 0x00, 0x02, 0x03, 0x00, 0x00,
1554     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x11,
1555     0x00, 0x03, 0x10, 0x12, 0x13, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00,
1556     0x01, 0x05, 0x02, 0x3b, 0x80, 0x6f, 0x56, 0x76, 0x56, 0x23, 0x87, 0x99,
1557     0x0d, 0x26, 0x62, 0xf6, 0xbf, 0xff, 0xc4, 0x00, 0x19, 0x11, 0x01, 0x00,
1558     0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1559     0x00, 0x00, 0x01, 0x00, 0x10, 0x11, 0x02, 0x12, 0xff, 0xda, 0x00, 0x08,
1560     0x01, 0x03, 0x01, 0x01, 0x3f, 0x01, 0xf1, 0x00, 0x27, 0x45, 0xbb, 0x31,
1561     0xaf, 0xff, 0xc4, 0x00, 0x1a, 0x11, 0x00, 0x02, 0x03, 0x01, 0x01, 0x00,
1562     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1563     0x02, 0x10, 0x11, 0x41, 0x12, 0xff, 0xda, 0x00, 0x08, 0x01, 0x02, 0x01,
1564     0x01, 0x3f, 0x01, 0xf6, 0x4b, 0x5f, 0x48, 0xb3, 0x69, 0x63, 0x35, 0x72,
1565     0xbf, 0xff, 0xc4, 0x00, 0x1e, 0x10, 0x00, 0x02, 0x01, 0x03, 0x05, 0x00,
1566     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
1567     0x21, 0x02, 0x12, 0x32, 0x10, 0x31, 0x71, 0x81, 0xa1, 0xff, 0xda, 0x00,
1568     0x08, 0x01, 0x01, 0x00, 0x06, 0x3f, 0x02, 0x4b, 0xb3, 0x28, 0x32, 0xd2,
1569     0xed, 0xf9, 0x1d, 0x3e, 0x13, 0x51, 0x73, 0x83, 0xff, 0xc4, 0x00, 0x1c,
1570     0x10, 0x01, 0x01, 0x01, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00,
1571     0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x21, 0x51, 0x31, 0x61,
1572     0x81, 0xf0, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3f, 0x21,
1573     0x75, 0x6e, 0x31, 0x94, 0x28, 0xf9, 0x30, 0xdc, 0x27, 0xdb, 0xa9, 0x01,
1574     0xf3, 0xde, 0x02, 0xa0, 0xed, 0x1e, 0x34, 0x68, 0x23, 0xf9, 0xc6, 0x48,
1575     0x5d, 0x7a, 0x35, 0x02, 0xf5, 0x6f, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
1576     0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x26, 0x61, 0xd4, 0xff,
1577     0xc4, 0x00, 0x1a, 0x11, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,
1578     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x21,
1579     0x31, 0x41, 0x51, 0xff, 0xda, 0x00, 0x08, 0x01, 0x03, 0x01, 0x01, 0x3f,
1580     0x10, 0x54, 0xa8, 0xbf, 0x50, 0x87, 0xb0, 0x9d, 0x8b, 0xc4, 0x6a, 0x26,
1581     0x6b, 0x2a, 0x9c, 0x1f, 0xff, 0xc4, 0x00, 0x18, 0x11, 0x01, 0x01, 0x01,
1582     0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1583     0x00, 0x01, 0x00, 0x11, 0x21, 0x51, 0xff, 0xda, 0x00, 0x08, 0x01, 0x02,
1584     0x01, 0x01, 0x3f, 0x10, 0x70, 0xe1, 0x3e, 0xd1, 0x8e, 0x0d, 0xe1, 0xb5,
1585     0xd5, 0x91, 0x76, 0x43, 0x82, 0x45, 0x4c, 0x7b, 0x7f, 0xff, 0xc4, 0x00,
1586     0x1f, 0x10, 0x01, 0x00, 0x02, 0x01, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00,
1587     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x31, 0x41, 0x61,
1588     0x71, 0x91, 0x21, 0x81, 0xd1, 0xb1, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01,
1589     0x00, 0x01, 0x3f, 0x10, 0x1b, 0x30, 0xe9, 0x58, 0xbe, 0x1a, 0xfd, 0x8a,
1590     0xeb, 0x8b, 0x34, 0x74, 0x80, 0x4b, 0xb5, 0xd5, 0xab, 0xcd, 0x46, 0x96,
1591     0x2e, 0xec, 0xbd, 0xaa, 0x78, 0x47, 0x5c, 0x47, 0xa7, 0x30, 0x49, 0xad,
1592     0x88, 0x7c, 0x40, 0x74, 0x30, 0xff, 0x00, 0x23, 0x1d, 0x03, 0x0b, 0xb7,
1593     0xd4, 0xff, 0xd9};
1594 static const size_t kTest1JpgLen = 735;
1595 
1596 // test 2 is J420
1597 static const uint8_t kTest2Jpg[] = {
1598     0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
1599     0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43,
1600     0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d, 0x0e, 0x12,
1601     0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23,
1602     0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40,
1603     0x48, 0x5c, 0x4e, 0x40, 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51,
1604     0x57, 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
1605     0x78, 0x5c, 0x65, 0x67, 0x63, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x11, 0x12,
1606     0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
1607     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1608     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1609     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1610     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1611     0x63, 0x63, 0xff, 0xc2, 0x00, 0x11, 0x08, 0x00, 0x10, 0x00, 0x20, 0x03,
1612     0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00,
1613     0x18, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1614     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x01, 0x02, 0x04, 0xff,
1615     0xc4, 0x00, 0x16, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1616     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0xff,
1617     0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x10, 0x03, 0x10, 0x00, 0x00,
1618     0x01, 0x20, 0xe7, 0x28, 0xa3, 0x0b, 0x2e, 0x2d, 0xcf, 0xff, 0xc4, 0x00,
1619     0x1b, 0x10, 0x00, 0x03, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
1620     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x11, 0x00, 0x03, 0x10,
1621     0x12, 0x13, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x05, 0x02,
1622     0x3b, 0x80, 0x6f, 0x56, 0x76, 0x56, 0x23, 0x87, 0x99, 0x0d, 0x26, 0x62,
1623     0xf6, 0xbf, 0xff, 0xc4, 0x00, 0x17, 0x11, 0x01, 0x00, 0x03, 0x00, 0x00,
1624     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1625     0x01, 0x11, 0x21, 0xff, 0xda, 0x00, 0x08, 0x01, 0x03, 0x01, 0x01, 0x3f,
1626     0x01, 0xc8, 0x53, 0xff, 0xc4, 0x00, 0x16, 0x11, 0x01, 0x01, 0x01, 0x00,
1627     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1628     0x00, 0x11, 0x32, 0xff, 0xda, 0x00, 0x08, 0x01, 0x02, 0x01, 0x01, 0x3f,
1629     0x01, 0xd2, 0xc7, 0xff, 0xc4, 0x00, 0x1e, 0x10, 0x00, 0x02, 0x01, 0x03,
1630     0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1631     0x00, 0x11, 0x21, 0x02, 0x12, 0x32, 0x10, 0x31, 0x71, 0x81, 0xa1, 0xff,
1632     0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x06, 0x3f, 0x02, 0x4b, 0xb3, 0x28,
1633     0x32, 0xd2, 0xed, 0xf9, 0x1d, 0x3e, 0x13, 0x51, 0x73, 0x83, 0xff, 0xc4,
1634     0x00, 0x1c, 0x10, 0x01, 0x01, 0x01, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00,
1635     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x21, 0x51,
1636     0x31, 0x61, 0x81, 0xf0, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01,
1637     0x3f, 0x21, 0x75, 0x6e, 0x31, 0x94, 0x28, 0xf9, 0x30, 0xdc, 0x27, 0xdb,
1638     0xa9, 0x01, 0xf3, 0xde, 0x02, 0xa0, 0xed, 0x1e, 0x34, 0x68, 0x23, 0xf9,
1639     0xc6, 0x48, 0x5d, 0x7a, 0x35, 0x02, 0xf5, 0x6f, 0xff, 0xda, 0x00, 0x0c,
1640     0x03, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x13, 0x5f,
1641     0xff, 0xc4, 0x00, 0x17, 0x11, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
1642     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11,
1643     0x21, 0xff, 0xda, 0x00, 0x08, 0x01, 0x03, 0x01, 0x01, 0x3f, 0x10, 0x0e,
1644     0xa1, 0x3a, 0x76, 0xff, 0xc4, 0x00, 0x17, 0x11, 0x01, 0x01, 0x01, 0x01,
1645     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1646     0x01, 0x00, 0x21, 0x11, 0xff, 0xda, 0x00, 0x08, 0x01, 0x02, 0x01, 0x01,
1647     0x3f, 0x10, 0x57, 0x0b, 0x08, 0x70, 0xdb, 0xff, 0xc4, 0x00, 0x1f, 0x10,
1648     0x01, 0x00, 0x02, 0x01, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1649     0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x31, 0x41, 0x61, 0x71, 0x91,
1650     0x21, 0x81, 0xd1, 0xb1, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01,
1651     0x3f, 0x10, 0x1b, 0x30, 0xe9, 0x58, 0xbe, 0x1a, 0xfd, 0x8a, 0xeb, 0x8b,
1652     0x34, 0x74, 0x80, 0x4b, 0xb5, 0xd5, 0xab, 0xcd, 0x46, 0x96, 0x2e, 0xec,
1653     0xbd, 0xaa, 0x78, 0x47, 0x5c, 0x47, 0xa7, 0x30, 0x49, 0xad, 0x88, 0x7c,
1654     0x40, 0x74, 0x30, 0xff, 0x00, 0x23, 0x1d, 0x03, 0x0b, 0xb7, 0xd4, 0xff,
1655     0xd9};
1656 static const size_t kTest2JpgLen = 685;
1657 
1658 // test 3 is J422
1659 static const uint8_t kTest3Jpg[] = {
1660     0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
1661     0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43,
1662     0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d, 0x0e, 0x12,
1663     0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23,
1664     0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40,
1665     0x48, 0x5c, 0x4e, 0x40, 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51,
1666     0x57, 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
1667     0x78, 0x5c, 0x65, 0x67, 0x63, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x11, 0x12,
1668     0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
1669     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1670     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1671     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1672     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1673     0x63, 0x63, 0xff, 0xc2, 0x00, 0x11, 0x08, 0x00, 0x10, 0x00, 0x20, 0x03,
1674     0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00,
1675     0x17, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1676     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x01, 0x02, 0xff, 0xc4,
1677     0x00, 0x17, 0x01, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1678     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0xff,
1679     0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x10, 0x03, 0x10, 0x00, 0x00,
1680     0x01, 0x43, 0x8d, 0x1f, 0xa2, 0xb3, 0xca, 0x1b, 0x57, 0x0f, 0xff, 0xc4,
1681     0x00, 0x1b, 0x10, 0x00, 0x03, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00,
1682     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x11, 0x00, 0x03,
1683     0x10, 0x12, 0x13, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x05,
1684     0x02, 0x3b, 0x80, 0x6f, 0x56, 0x76, 0x56, 0x23, 0x87, 0x99, 0x0d, 0x26,
1685     0x62, 0xf6, 0xbf, 0xff, 0xc4, 0x00, 0x19, 0x11, 0x00, 0x02, 0x03, 0x01,
1686     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1687     0x00, 0x01, 0x02, 0x10, 0x11, 0x21, 0xff, 0xda, 0x00, 0x08, 0x01, 0x03,
1688     0x01, 0x01, 0x3f, 0x01, 0x51, 0xce, 0x8c, 0x75, 0xff, 0xc4, 0x00, 0x18,
1689     0x11, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1690     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x61, 0x21, 0xff, 0xda,
1691     0x00, 0x08, 0x01, 0x02, 0x01, 0x01, 0x3f, 0x01, 0xa6, 0xd9, 0x2f, 0x84,
1692     0xe8, 0xf0, 0xff, 0xc4, 0x00, 0x1e, 0x10, 0x00, 0x02, 0x01, 0x03, 0x05,
1693     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1694     0x11, 0x21, 0x02, 0x12, 0x32, 0x10, 0x31, 0x71, 0x81, 0xa1, 0xff, 0xda,
1695     0x00, 0x08, 0x01, 0x01, 0x00, 0x06, 0x3f, 0x02, 0x4b, 0xb3, 0x28, 0x32,
1696     0xd2, 0xed, 0xf9, 0x1d, 0x3e, 0x13, 0x51, 0x73, 0x83, 0xff, 0xc4, 0x00,
1697     0x1c, 0x10, 0x01, 0x01, 0x01, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00,
1698     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x21, 0x51, 0x31,
1699     0x61, 0x81, 0xf0, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3f,
1700     0x21, 0x75, 0x6e, 0x31, 0x94, 0x28, 0xf9, 0x30, 0xdc, 0x27, 0xdb, 0xa9,
1701     0x01, 0xf3, 0xde, 0x02, 0xa0, 0xed, 0x1e, 0x34, 0x68, 0x23, 0xf9, 0xc6,
1702     0x48, 0x5d, 0x7a, 0x35, 0x02, 0xf5, 0x6f, 0xff, 0xda, 0x00, 0x0c, 0x03,
1703     0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x2e, 0x45, 0xff,
1704     0xc4, 0x00, 0x18, 0x11, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
1705     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x21,
1706     0x31, 0xff, 0xda, 0x00, 0x08, 0x01, 0x03, 0x01, 0x01, 0x3f, 0x10, 0x53,
1707     0x50, 0xba, 0x54, 0xc1, 0x67, 0x4f, 0xff, 0xc4, 0x00, 0x18, 0x11, 0x00,
1708     0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1709     0x00, 0x00, 0x00, 0x01, 0x11, 0x21, 0x00, 0x10, 0xff, 0xda, 0x00, 0x08,
1710     0x01, 0x02, 0x01, 0x01, 0x3f, 0x10, 0x18, 0x81, 0x5c, 0x04, 0x1a, 0xca,
1711     0x91, 0xbf, 0xff, 0xc4, 0x00, 0x1f, 0x10, 0x01, 0x00, 0x02, 0x01, 0x04,
1712     0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1713     0x00, 0x11, 0x31, 0x41, 0x61, 0x71, 0x91, 0x21, 0x81, 0xd1, 0xb1, 0xff,
1714     0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3f, 0x10, 0x1b, 0x30, 0xe9,
1715     0x58, 0xbe, 0x1a, 0xfd, 0x8a, 0xeb, 0x8b, 0x34, 0x74, 0x80, 0x4b, 0xb5,
1716     0xd5, 0xab, 0xcd, 0x46, 0x96, 0x2e, 0xec, 0xbd, 0xaa, 0x78, 0x47, 0x5c,
1717     0x47, 0xa7, 0x30, 0x49, 0xad, 0x88, 0x7c, 0x40, 0x74, 0x30, 0xff, 0x00,
1718     0x23, 0x1d, 0x03, 0x0b, 0xb7, 0xd4, 0xff, 0xd9};
1719 static const size_t kTest3JpgLen = 704;
1720 
1721 // test 4 is J422 vertical - not supported
1722 static const uint8_t kTest4Jpg[] = {
1723     0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
1724     0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43,
1725     0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d, 0x0e, 0x12,
1726     0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23,
1727     0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40,
1728     0x48, 0x5c, 0x4e, 0x40, 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51,
1729     0x57, 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
1730     0x78, 0x5c, 0x65, 0x67, 0x63, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x11, 0x12,
1731     0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
1732     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1733     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1734     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1735     0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
1736     0x63, 0x63, 0xff, 0xc2, 0x00, 0x11, 0x08, 0x00, 0x10, 0x00, 0x20, 0x03,
1737     0x01, 0x12, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00,
1738     0x18, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1739     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x01, 0x02, 0x03, 0xff,
1740     0xc4, 0x00, 0x16, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1741     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0xff,
1742     0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x10, 0x03, 0x10, 0x00, 0x00,
1743     0x01, 0xd2, 0x98, 0xe9, 0x03, 0x0c, 0x00, 0x46, 0x21, 0xd9, 0xff, 0xc4,
1744     0x00, 0x1b, 0x10, 0x00, 0x03, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00,
1745     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x11, 0x00, 0x03,
1746     0x10, 0x12, 0x13, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x05,
1747     0x02, 0x3b, 0x80, 0x6f, 0x56, 0x76, 0x56, 0x23, 0x87, 0x99, 0x0d, 0x26,
1748     0x62, 0xf6, 0xbf, 0xff, 0xc4, 0x00, 0x17, 0x11, 0x01, 0x01, 0x01, 0x01,
1749     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1750     0x00, 0x11, 0x01, 0x21, 0xff, 0xda, 0x00, 0x08, 0x01, 0x03, 0x01, 0x01,
1751     0x3f, 0x01, 0x98, 0xb1, 0xbd, 0x47, 0xff, 0xc4, 0x00, 0x18, 0x11, 0x00,
1752     0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1753     0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0x11, 0x21, 0xff, 0xda, 0x00, 0x08,
1754     0x01, 0x02, 0x01, 0x01, 0x3f, 0x01, 0xb6, 0x35, 0xa2, 0xe1, 0x47, 0xff,
1755     0xc4, 0x00, 0x1e, 0x10, 0x00, 0x02, 0x01, 0x03, 0x05, 0x00, 0x00, 0x00,
1756     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x21, 0x02,
1757     0x12, 0x32, 0x10, 0x31, 0x71, 0x81, 0xa1, 0xff, 0xda, 0x00, 0x08, 0x01,
1758     0x01, 0x00, 0x06, 0x3f, 0x02, 0x4b, 0xb3, 0x28, 0x32, 0xd2, 0xed, 0xf9,
1759     0x1d, 0x3e, 0x13, 0x51, 0x73, 0x83, 0xff, 0xc4, 0x00, 0x1c, 0x10, 0x01,
1760     0x01, 0x01, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1761     0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x21, 0x51, 0x31, 0x61, 0x81, 0xf0,
1762     0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3f, 0x21, 0x75, 0x6e,
1763     0x31, 0x94, 0x28, 0xf9, 0x30, 0xdc, 0x27, 0xdb, 0xa9, 0x01, 0xf3, 0xde,
1764     0x02, 0xa0, 0xed, 0x1e, 0x34, 0x68, 0x23, 0xf9, 0xc6, 0x48, 0x5d, 0x7a,
1765     0x35, 0x02, 0xf5, 0x6f, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02,
1766     0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x24, 0xaf, 0xff, 0xc4, 0x00, 0x19,
1767     0x11, 0x00, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1768     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x51, 0x21, 0x31, 0xff,
1769     0xda, 0x00, 0x08, 0x01, 0x03, 0x01, 0x01, 0x3f, 0x10, 0x59, 0x11, 0xca,
1770     0x42, 0x60, 0x9f, 0x69, 0xff, 0xc4, 0x00, 0x19, 0x11, 0x00, 0x02, 0x03,
1771     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1772     0x00, 0x00, 0x01, 0x11, 0x21, 0x31, 0x61, 0xff, 0xda, 0x00, 0x08, 0x01,
1773     0x02, 0x01, 0x01, 0x3f, 0x10, 0xb0, 0xd7, 0x27, 0x51, 0xb6, 0x41, 0xff,
1774     0xc4, 0x00, 0x1f, 0x10, 0x01, 0x00, 0x02, 0x01, 0x04, 0x03, 0x01, 0x00,
1775     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x31,
1776     0x41, 0x61, 0x71, 0x91, 0x21, 0x81, 0xd1, 0xb1, 0xff, 0xda, 0x00, 0x08,
1777     0x01, 0x01, 0x00, 0x01, 0x3f, 0x10, 0x1b, 0x30, 0xe9, 0x58, 0xbe, 0x1a,
1778     0xfd, 0x8a, 0xeb, 0x8b, 0x34, 0x74, 0x80, 0x4b, 0xb5, 0xd5, 0xab, 0xcd,
1779     0x46, 0x96, 0x2e, 0xec, 0xbd, 0xaa, 0x78, 0x47, 0x5c, 0x47, 0xa7, 0x30,
1780     0x49, 0xad, 0x88, 0x7c, 0x40, 0x74, 0x30, 0xff, 0x00, 0x23, 0x1d, 0x03,
1781     0x0b, 0xb7, 0xd4, 0xff, 0xd9};
1782 static const size_t kTest4JpgLen = 701;
1783 
TEST_F(LibYUVConvertTest,TestMJPGSize)1784 TEST_F(LibYUVConvertTest, TestMJPGSize) {
1785   int width = 0;
1786   int height = 0;
1787   int ret = MJPGSize(kTest2Jpg, kTest2JpgLen, &width, &height);
1788   EXPECT_EQ(0, ret);
1789 
1790   printf("test jpeg size %d x %d\n", width, height);
1791 }
1792 
TEST_F(LibYUVConvertTest,TestMJPGToI420)1793 TEST_F(LibYUVConvertTest, TestMJPGToI420) {
1794   int width = 0;
1795   int height = 0;
1796   int ret = MJPGSize(kTest2Jpg, kTest2JpgLen, &width, &height);
1797   EXPECT_EQ(0, ret);
1798 
1799   int half_width = (width + 1) / 2;
1800   int half_height = (height + 1) / 2;
1801   int benchmark_iterations = benchmark_iterations_ * benchmark_width_ *
1802                              benchmark_height_ / (width * height);
1803 
1804   align_buffer_page_end(dst_y, width * height);
1805   align_buffer_page_end(dst_u, half_width * half_height);
1806   align_buffer_page_end(dst_v, half_width * half_height);
1807   for (int times = 0; times < benchmark_iterations; ++times) {
1808     ret = MJPGToI420(kTest2Jpg, kTest2JpgLen, dst_y, width, dst_u, half_width,
1809                      dst_v, half_width, width, height, width, height);
1810   }
1811   // Expect sucesss
1812   EXPECT_EQ(0, ret);
1813 
1814   // Test result matches known hash value.
1815   uint32_t dst_y_hash = HashDjb2(dst_y, width * height, 5381);
1816   uint32_t dst_u_hash = HashDjb2(dst_u, half_width * half_height, 5381);
1817   uint32_t dst_v_hash = HashDjb2(dst_v, half_width * half_height, 5381);
1818   EXPECT_EQ(dst_y_hash, 2682851208u);
1819   EXPECT_EQ(dst_u_hash, 2501859930u);
1820   EXPECT_EQ(dst_v_hash, 2126459123u);
1821 
1822   free_aligned_buffer_page_end(dst_y);
1823   free_aligned_buffer_page_end(dst_u);
1824   free_aligned_buffer_page_end(dst_v);
1825 }
1826 
TEST_F(LibYUVConvertTest,TestMJPGToI420_NV21)1827 TEST_F(LibYUVConvertTest, TestMJPGToI420_NV21) {
1828   int width = 0;
1829   int height = 0;
1830   int ret = MJPGSize(kTest2Jpg, kTest2JpgLen, &width, &height);
1831   EXPECT_EQ(0, ret);
1832 
1833   int half_width = (width + 1) / 2;
1834   int half_height = (height + 1) / 2;
1835   int benchmark_iterations = benchmark_iterations_ * benchmark_width_ *
1836                              benchmark_height_ / (width * height);
1837 
1838   // Convert to NV21
1839   align_buffer_page_end(dst_y, width * height);
1840   align_buffer_page_end(dst_vu, half_width * half_height * 2);
1841 
1842   for (int times = 0; times < benchmark_iterations; ++times) {
1843     ret = MJPGToNV21(kTest2Jpg, kTest2JpgLen, dst_y, width, dst_vu,
1844                      half_width * 2, width, height, width, height);
1845   }
1846   // Expect sucesss
1847   EXPECT_EQ(0, ret);
1848 
1849   // Convert to I420
1850   align_buffer_page_end(dst2_y, width * height);
1851   align_buffer_page_end(dst2_u, half_width * half_height);
1852   align_buffer_page_end(dst2_v, half_width * half_height);
1853   for (int times = 0; times < benchmark_iterations; ++times) {
1854     ret = MJPGToI420(kTest2Jpg, kTest2JpgLen, dst2_y, width, dst2_u, half_width,
1855                      dst2_v, half_width, width, height, width, height);
1856   }
1857   // Expect sucesss
1858   EXPECT_EQ(0, ret);
1859 
1860   // Convert I420 to NV21
1861   align_buffer_page_end(dst3_y, width * height);
1862   align_buffer_page_end(dst3_vu, half_width * half_height * 2);
1863 
1864   I420ToNV21(dst2_y, width, dst2_u, half_width, dst2_v, half_width, dst3_y,
1865              width, dst3_vu, half_width * 2, width, height);
1866 
1867   for (int i = 0; i < width * height; ++i) {
1868     EXPECT_EQ(dst_y[i], dst3_y[i]);
1869   }
1870   for (int i = 0; i < half_width * half_height * 2; ++i) {
1871     EXPECT_EQ(dst_vu[i], dst3_vu[i]);
1872     EXPECT_EQ(dst_vu[i], dst3_vu[i]);
1873   }
1874 
1875   free_aligned_buffer_page_end(dst3_y);
1876   free_aligned_buffer_page_end(dst3_vu);
1877 
1878   free_aligned_buffer_page_end(dst2_y);
1879   free_aligned_buffer_page_end(dst2_u);
1880   free_aligned_buffer_page_end(dst2_v);
1881 
1882   free_aligned_buffer_page_end(dst_y);
1883   free_aligned_buffer_page_end(dst_vu);
1884 }
1885 
TEST_F(LibYUVConvertTest,TestMJPGToNV21_420)1886 TEST_F(LibYUVConvertTest, TestMJPGToNV21_420) {
1887   int width = 0;
1888   int height = 0;
1889   int ret = MJPGSize(kTest2Jpg, kTest2JpgLen, &width, &height);
1890   EXPECT_EQ(0, ret);
1891 
1892   int half_width = (width + 1) / 2;
1893   int half_height = (height + 1) / 2;
1894   int benchmark_iterations = benchmark_iterations_ * benchmark_width_ *
1895                              benchmark_height_ / (width * height);
1896 
1897   align_buffer_page_end(dst_y, width * height);
1898   align_buffer_page_end(dst_uv, half_width * half_height * 2);
1899   for (int times = 0; times < benchmark_iterations; ++times) {
1900     ret = MJPGToNV21(kTest2Jpg, kTest2JpgLen, dst_y, width, dst_uv,
1901                      half_width * 2, width, height, width, height);
1902   }
1903   // Expect sucesss
1904   EXPECT_EQ(0, ret);
1905 
1906   // Test result matches known hash value.
1907   uint32_t dst_y_hash = HashDjb2(dst_y, width * height, 5381);
1908   uint32_t dst_uv_hash = HashDjb2(dst_uv, half_width * half_height * 2, 5381);
1909   EXPECT_EQ(dst_y_hash, 2682851208u);
1910   EXPECT_EQ(dst_uv_hash, 1069662856u);
1911 
1912   free_aligned_buffer_page_end(dst_y);
1913   free_aligned_buffer_page_end(dst_uv);
1914 }
1915 
TEST_F(LibYUVConvertTest,TestMJPGToNV21_422)1916 TEST_F(LibYUVConvertTest, TestMJPGToNV21_422) {
1917   int width = 0;
1918   int height = 0;
1919   int ret = MJPGSize(kTest3Jpg, kTest3JpgLen, &width, &height);
1920   EXPECT_EQ(0, ret);
1921 
1922   int half_width = (width + 1) / 2;
1923   int half_height = (height + 1) / 2;
1924   int benchmark_iterations = benchmark_iterations_ * benchmark_width_ *
1925                              benchmark_height_ / (width * height);
1926 
1927   align_buffer_page_end(dst_y, width * height);
1928   align_buffer_page_end(dst_uv, half_width * half_height * 2);
1929   for (int times = 0; times < benchmark_iterations; ++times) {
1930     ret = MJPGToNV21(kTest3Jpg, kTest3JpgLen, dst_y, width, dst_uv,
1931                      half_width * 2, width, height, width, height);
1932   }
1933   // Expect sucesss
1934   EXPECT_EQ(0, ret);
1935 
1936   // Test result matches known hash value.
1937   uint32_t dst_y_hash = HashDjb2(dst_y, width * height, 5381);
1938   uint32_t dst_uv_hash = HashDjb2(dst_uv, half_width * half_height * 2, 5381);
1939   EXPECT_EQ(dst_y_hash, 2682851208u);
1940   EXPECT_EQ(dst_uv_hash, 3543430771u);
1941 
1942   free_aligned_buffer_page_end(dst_y);
1943   free_aligned_buffer_page_end(dst_uv);
1944 }
1945 
TEST_F(LibYUVConvertTest,TestMJPGToNV21_400)1946 TEST_F(LibYUVConvertTest, TestMJPGToNV21_400) {
1947   int width = 0;
1948   int height = 0;
1949   int ret = MJPGSize(kTest0Jpg, kTest0JpgLen, &width, &height);
1950   EXPECT_EQ(0, ret);
1951 
1952   int half_width = (width + 1) / 2;
1953   int half_height = (height + 1) / 2;
1954   int benchmark_iterations = benchmark_iterations_ * benchmark_width_ *
1955                              benchmark_height_ / (width * height);
1956 
1957   align_buffer_page_end(dst_y, width * height);
1958   align_buffer_page_end(dst_uv, half_width * half_height * 2);
1959   for (int times = 0; times < benchmark_iterations; ++times) {
1960     ret = MJPGToNV21(kTest0Jpg, kTest0JpgLen, dst_y, width, dst_uv,
1961                      half_width * 2, width, height, width, height);
1962   }
1963   // Expect sucesss
1964   EXPECT_EQ(0, ret);
1965 
1966   // Test result matches known hash value.
1967   uint32_t dst_y_hash = HashDjb2(dst_y, width * height, 5381);
1968   uint32_t dst_uv_hash = HashDjb2(dst_uv, half_width * half_height * 2, 5381);
1969   EXPECT_EQ(dst_y_hash, 330644005u);
1970   EXPECT_EQ(dst_uv_hash, 135214341u);
1971 
1972   free_aligned_buffer_page_end(dst_y);
1973   free_aligned_buffer_page_end(dst_uv);
1974 }
1975 
TEST_F(LibYUVConvertTest,TestMJPGToNV21_444)1976 TEST_F(LibYUVConvertTest, TestMJPGToNV21_444) {
1977   int width = 0;
1978   int height = 0;
1979   int ret = MJPGSize(kTest1Jpg, kTest1JpgLen, &width, &height);
1980   EXPECT_EQ(0, ret);
1981 
1982   int half_width = (width + 1) / 2;
1983   int half_height = (height + 1) / 2;
1984   int benchmark_iterations = benchmark_iterations_ * benchmark_width_ *
1985                              benchmark_height_ / (width * height);
1986 
1987   align_buffer_page_end(dst_y, width * height);
1988   align_buffer_page_end(dst_uv, half_width * half_height * 2);
1989   for (int times = 0; times < benchmark_iterations; ++times) {
1990     ret = MJPGToNV21(kTest1Jpg, kTest1JpgLen, dst_y, width, dst_uv,
1991                      half_width * 2, width, height, width, height);
1992   }
1993   // Expect sucesss
1994   EXPECT_EQ(0, ret);
1995 
1996   // Test result matches known hash value.
1997   uint32_t dst_y_hash = HashDjb2(dst_y, width * height, 5381);
1998   uint32_t dst_uv_hash = HashDjb2(dst_uv, half_width * half_height * 2, 5381);
1999   EXPECT_EQ(dst_y_hash, 2682851208u);
2000   EXPECT_EQ(dst_uv_hash, 506143297u);
2001 
2002   free_aligned_buffer_page_end(dst_y);
2003   free_aligned_buffer_page_end(dst_uv);
2004 }
2005 
TEST_F(LibYUVConvertTest,TestMJPGToARGB)2006 TEST_F(LibYUVConvertTest, TestMJPGToARGB) {
2007   int width = 0;
2008   int height = 0;
2009   int ret = MJPGSize(kTest3Jpg, kTest3JpgLen, &width, &height);
2010   EXPECT_EQ(0, ret);
2011 
2012   int benchmark_iterations = benchmark_iterations_ * benchmark_width_ *
2013                              benchmark_height_ / (width * height);
2014 
2015   align_buffer_page_end(dst_argb, width * height * 4);
2016   for (int times = 0; times < benchmark_iterations; ++times) {
2017     ret = MJPGToARGB(kTest3Jpg, kTest3JpgLen, dst_argb, width * 4, width,
2018                      height, width, height);
2019   }
2020   // Expect sucesss
2021   EXPECT_EQ(0, ret);
2022 
2023   // Test result matches known hash value.
2024   uint32_t dst_argb_hash = HashDjb2(dst_argb, width * height, 5381);
2025   EXPECT_EQ(dst_argb_hash, 2355976473u);
2026 
2027   free_aligned_buffer_page_end(dst_argb);
2028 }
2029 
ShowJPegInfo(const uint8_t * sample,size_t sample_size)2030 static int ShowJPegInfo(const uint8_t* sample, size_t sample_size) {
2031   MJpegDecoder mjpeg_decoder;
2032   LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
2033 
2034   int width = mjpeg_decoder.GetWidth();
2035   int height = mjpeg_decoder.GetHeight();
2036 
2037   // YUV420
2038   if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
2039       mjpeg_decoder.GetNumComponents() == 3 &&
2040       mjpeg_decoder.GetVertSampFactor(0) == 2 &&
2041       mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
2042       mjpeg_decoder.GetVertSampFactor(1) == 1 &&
2043       mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
2044       mjpeg_decoder.GetVertSampFactor(2) == 1 &&
2045       mjpeg_decoder.GetHorizSampFactor(2) == 1) {
2046     printf("JPeg is J420, %dx%d %d bytes\n", width, height,
2047            static_cast<int>(sample_size));
2048     // YUV422
2049   } else if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
2050              mjpeg_decoder.GetNumComponents() == 3 &&
2051              mjpeg_decoder.GetVertSampFactor(0) == 1 &&
2052              mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
2053              mjpeg_decoder.GetVertSampFactor(1) == 1 &&
2054              mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
2055              mjpeg_decoder.GetVertSampFactor(2) == 1 &&
2056              mjpeg_decoder.GetHorizSampFactor(2) == 1) {
2057     printf("JPeg is J422, %dx%d %d bytes\n", width, height,
2058            static_cast<int>(sample_size));
2059     // YUV444
2060   } else if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
2061              mjpeg_decoder.GetNumComponents() == 3 &&
2062              mjpeg_decoder.GetVertSampFactor(0) == 1 &&
2063              mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
2064              mjpeg_decoder.GetVertSampFactor(1) == 1 &&
2065              mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
2066              mjpeg_decoder.GetVertSampFactor(2) == 1 &&
2067              mjpeg_decoder.GetHorizSampFactor(2) == 1) {
2068     printf("JPeg is J444, %dx%d %d bytes\n", width, height,
2069            static_cast<int>(sample_size));
2070     // YUV400
2071   } else if (mjpeg_decoder.GetColorSpace() ==
2072                  MJpegDecoder::kColorSpaceGrayscale &&
2073              mjpeg_decoder.GetNumComponents() == 1 &&
2074              mjpeg_decoder.GetVertSampFactor(0) == 1 &&
2075              mjpeg_decoder.GetHorizSampFactor(0) == 1) {
2076     printf("JPeg is J400, %dx%d %d bytes\n", width, height,
2077            static_cast<int>(sample_size));
2078   } else {
2079     // Unknown colorspace.
2080     printf("JPeg is Unknown colorspace.\n");
2081   }
2082   mjpeg_decoder.UnloadFrame();
2083   return ret;
2084 }
2085 
TEST_F(LibYUVConvertTest,TestMJPGInfo)2086 TEST_F(LibYUVConvertTest, TestMJPGInfo) {
2087   EXPECT_EQ(1, ShowJPegInfo(kTest0Jpg, kTest0JpgLen));
2088   EXPECT_EQ(1, ShowJPegInfo(kTest1Jpg, kTest1JpgLen));
2089   EXPECT_EQ(1, ShowJPegInfo(kTest2Jpg, kTest2JpgLen));
2090   EXPECT_EQ(1, ShowJPegInfo(kTest3Jpg, kTest3JpgLen));
2091   EXPECT_EQ(1, ShowJPegInfo(kTest4Jpg,
2092                             kTest4JpgLen));  // Valid but unsupported.
2093 }
2094 #endif  // HAVE_JPEG
2095 
TEST_F(LibYUVConvertTest,NV12Crop)2096 TEST_F(LibYUVConvertTest, NV12Crop) {
2097   const int SUBSAMP_X = 2;
2098   const int SUBSAMP_Y = 2;
2099   const int kWidth = benchmark_width_;
2100   const int kHeight = benchmark_height_;
2101   const int crop_y =
2102       ((benchmark_height_ - (benchmark_height_ * 360 / 480)) / 2 + 1) & ~1;
2103   const int kDestWidth = benchmark_width_;
2104   const int kDestHeight = benchmark_height_ - crop_y * 2;
2105   const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);
2106   const int sample_size =
2107       kWidth * kHeight + kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y) * 2;
2108   align_buffer_page_end(src_y, sample_size);
2109   uint8_t* src_uv = src_y + kWidth * kHeight;
2110 
2111   align_buffer_page_end(dst_y, kDestWidth * kDestHeight);
2112   align_buffer_page_end(dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
2113                                    SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2114   align_buffer_page_end(dst_v, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
2115                                    SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2116 
2117   align_buffer_page_end(dst_y_2, kDestWidth * kDestHeight);
2118   align_buffer_page_end(dst_u_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
2119                                      SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2120   align_buffer_page_end(dst_v_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
2121                                      SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2122 
2123   for (int i = 0; i < kHeight * kWidth; ++i) {
2124     src_y[i] = (fastrand() & 0xff);
2125   }
2126   for (int i = 0; i < (SUBSAMPLE(kHeight, SUBSAMP_Y) * kStrideUV) * 2; ++i) {
2127     src_uv[i] = (fastrand() & 0xff);
2128   }
2129   memset(dst_y, 1, kDestWidth * kDestHeight);
2130   memset(dst_u, 2,
2131          SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2132   memset(dst_v, 3,
2133          SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2134   memset(dst_y_2, 1, kDestWidth * kDestHeight);
2135   memset(dst_u_2, 2,
2136          SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2137   memset(dst_v_2, 3,
2138          SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2139 
2140   ConvertToI420(src_y, sample_size, dst_y_2, kDestWidth, dst_u_2,
2141                 SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v_2,
2142                 SUBSAMPLE(kDestWidth, SUBSAMP_X), 0, crop_y, kWidth, kHeight,
2143                 kDestWidth, kDestHeight, libyuv::kRotate0, libyuv::FOURCC_NV12);
2144 
2145   NV12ToI420(src_y + crop_y * kWidth, kWidth,
2146              src_uv + (crop_y / 2) * kStrideUV * 2, kStrideUV * 2, dst_y,
2147              kDestWidth, dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v,
2148              SUBSAMPLE(kDestWidth, SUBSAMP_X), kDestWidth, kDestHeight);
2149 
2150   for (int i = 0; i < kDestHeight; ++i) {
2151     for (int j = 0; j < kDestWidth; ++j) {
2152       EXPECT_EQ(dst_y[i * kWidth + j], dst_y_2[i * kWidth + j]);
2153     }
2154   }
2155   for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
2156     for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
2157       EXPECT_EQ(dst_u[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
2158                 dst_u_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
2159     }
2160   }
2161   for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
2162     for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
2163       EXPECT_EQ(dst_v[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
2164                 dst_v_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
2165     }
2166   }
2167   free_aligned_buffer_page_end(dst_y);
2168   free_aligned_buffer_page_end(dst_u);
2169   free_aligned_buffer_page_end(dst_v);
2170   free_aligned_buffer_page_end(dst_y_2);
2171   free_aligned_buffer_page_end(dst_u_2);
2172   free_aligned_buffer_page_end(dst_v_2);
2173   free_aligned_buffer_page_end(src_y);
2174 }
2175 
TEST_F(LibYUVConvertTest,I420CropOddY)2176 TEST_F(LibYUVConvertTest, I420CropOddY) {
2177   const int SUBSAMP_X = 2;
2178   const int SUBSAMP_Y = 2;
2179   const int kWidth = benchmark_width_;
2180   const int kHeight = benchmark_height_;
2181   const int crop_y = 1;
2182   const int kDestWidth = benchmark_width_;
2183   const int kDestHeight = benchmark_height_ - crop_y * 2;
2184   const int kStrideU = SUBSAMPLE(kWidth, SUBSAMP_X);
2185   const int kStrideV = SUBSAMPLE(kWidth, SUBSAMP_X);
2186   const int sample_size = kWidth * kHeight +
2187                           kStrideU * SUBSAMPLE(kHeight, SUBSAMP_Y) +
2188                           kStrideV * SUBSAMPLE(kHeight, SUBSAMP_Y);
2189   align_buffer_page_end(src_y, sample_size);
2190   uint8_t* src_u = src_y + kWidth * kHeight;
2191   uint8_t* src_v = src_u + kStrideU * SUBSAMPLE(kHeight, SUBSAMP_Y);
2192 
2193   align_buffer_page_end(dst_y, kDestWidth * kDestHeight);
2194   align_buffer_page_end(dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
2195                                    SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2196   align_buffer_page_end(dst_v, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
2197                                    SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2198 
2199   for (int i = 0; i < kHeight * kWidth; ++i) {
2200     src_y[i] = (fastrand() & 0xff);
2201   }
2202   for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y) * kStrideU; ++i) {
2203     src_u[i] = (fastrand() & 0xff);
2204   }
2205   for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y) * kStrideV; ++i) {
2206     src_v[i] = (fastrand() & 0xff);
2207   }
2208   memset(dst_y, 1, kDestWidth * kDestHeight);
2209   memset(dst_u, 2,
2210          SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2211   memset(dst_v, 3,
2212          SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
2213 
2214   MaskCpuFlags(benchmark_cpu_info_);
2215   for (int i = 0; i < benchmark_iterations_; ++i) {
2216     ConvertToI420(src_y, sample_size, dst_y, kDestWidth, dst_u,
2217                   SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v,
2218                   SUBSAMPLE(kDestWidth, SUBSAMP_X), 0, crop_y, kWidth, kHeight,
2219                   kDestWidth, kDestHeight, libyuv::kRotate0,
2220                   libyuv::FOURCC_I420);
2221   }
2222 
2223   for (int i = 0; i < kDestHeight; ++i) {
2224     for (int j = 0; j < kDestWidth; ++j) {
2225       EXPECT_EQ(src_y[crop_y * kWidth + i * kWidth + j],
2226                 dst_y[i * kDestWidth + j]);
2227     }
2228   }
2229   for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
2230     for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
2231       EXPECT_EQ(src_u[(crop_y / 2 + i) * kStrideU + j],
2232                 dst_u[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
2233     }
2234   }
2235   for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
2236     for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
2237       EXPECT_EQ(src_v[(crop_y / 2 + i) * kStrideV + j],
2238                 dst_v[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
2239     }
2240   }
2241 
2242   free_aligned_buffer_page_end(dst_y);
2243   free_aligned_buffer_page_end(dst_u);
2244   free_aligned_buffer_page_end(dst_v);
2245   free_aligned_buffer_page_end(src_y);
2246 }
2247 
TEST_F(LibYUVConvertTest,TestYToARGB)2248 TEST_F(LibYUVConvertTest, TestYToARGB) {
2249   uint8_t y[32];
2250   uint8_t expectedg[32];
2251   for (int i = 0; i < 32; ++i) {
2252     y[i] = i * 5 + 17;
2253     expectedg[i] = static_cast<int>((y[i] - 16) * 1.164f + 0.5f);
2254   }
2255   uint8_t argb[32 * 4];
2256   YToARGB(y, 0, argb, 0, 32, 1);
2257 
2258   for (int i = 0; i < 32; ++i) {
2259     printf("%2d %d: %d <-> %d,%d,%d,%d\n", i, y[i], expectedg[i],
2260            argb[i * 4 + 0], argb[i * 4 + 1], argb[i * 4 + 2], argb[i * 4 + 3]);
2261   }
2262   for (int i = 0; i < 32; ++i) {
2263     EXPECT_EQ(expectedg[i], argb[i * 4 + 0]);
2264   }
2265 }
2266 
2267 static const uint8_t kNoDither4x4[16] = {
2268     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2269 };
2270 
TEST_F(LibYUVConvertTest,TestNoDither)2271 TEST_F(LibYUVConvertTest, TestNoDither) {
2272   align_buffer_page_end(src_argb, benchmark_width_ * benchmark_height_ * 4);
2273   align_buffer_page_end(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
2274   align_buffer_page_end(dst_rgb565dither,
2275                         benchmark_width_ * benchmark_height_ * 2);
2276   MemRandomize(src_argb, benchmark_width_ * benchmark_height_ * 4);
2277   MemRandomize(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
2278   MemRandomize(dst_rgb565dither, benchmark_width_ * benchmark_height_ * 2);
2279   ARGBToRGB565(src_argb, benchmark_width_ * 4, dst_rgb565, benchmark_width_ * 2,
2280                benchmark_width_, benchmark_height_);
2281   ARGBToRGB565Dither(src_argb, benchmark_width_ * 4, dst_rgb565dither,
2282                      benchmark_width_ * 2, kNoDither4x4, benchmark_width_,
2283                      benchmark_height_);
2284   for (int i = 0; i < benchmark_width_ * benchmark_height_ * 2; ++i) {
2285     EXPECT_EQ(dst_rgb565[i], dst_rgb565dither[i]);
2286   }
2287 
2288   free_aligned_buffer_page_end(src_argb);
2289   free_aligned_buffer_page_end(dst_rgb565);
2290   free_aligned_buffer_page_end(dst_rgb565dither);
2291 }
2292 
2293 // Ordered 4x4 dither for 888 to 565.  Values from 0 to 7.
2294 static const uint8_t kDither565_4x4[16] = {
2295     0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
2296 };
2297 
TEST_F(LibYUVConvertTest,TestDither)2298 TEST_F(LibYUVConvertTest, TestDither) {
2299   align_buffer_page_end(src_argb, benchmark_width_ * benchmark_height_ * 4);
2300   align_buffer_page_end(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
2301   align_buffer_page_end(dst_rgb565dither,
2302                         benchmark_width_ * benchmark_height_ * 2);
2303   align_buffer_page_end(dst_argb, benchmark_width_ * benchmark_height_ * 4);
2304   align_buffer_page_end(dst_argbdither,
2305                         benchmark_width_ * benchmark_height_ * 4);
2306   MemRandomize(src_argb, benchmark_width_ * benchmark_height_ * 4);
2307   MemRandomize(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
2308   MemRandomize(dst_rgb565dither, benchmark_width_ * benchmark_height_ * 2);
2309   MemRandomize(dst_argb, benchmark_width_ * benchmark_height_ * 4);
2310   MemRandomize(dst_argbdither, benchmark_width_ * benchmark_height_ * 4);
2311   ARGBToRGB565(src_argb, benchmark_width_ * 4, dst_rgb565, benchmark_width_ * 2,
2312                benchmark_width_, benchmark_height_);
2313   ARGBToRGB565Dither(src_argb, benchmark_width_ * 4, dst_rgb565dither,
2314                      benchmark_width_ * 2, kDither565_4x4, benchmark_width_,
2315                      benchmark_height_);
2316   RGB565ToARGB(dst_rgb565, benchmark_width_ * 2, dst_argb, benchmark_width_ * 4,
2317                benchmark_width_, benchmark_height_);
2318   RGB565ToARGB(dst_rgb565dither, benchmark_width_ * 2, dst_argbdither,
2319                benchmark_width_ * 4, benchmark_width_, benchmark_height_);
2320 
2321   for (int i = 0; i < benchmark_width_ * benchmark_height_ * 4; ++i) {
2322     EXPECT_NEAR(dst_argb[i], dst_argbdither[i], 9);
2323   }
2324   free_aligned_buffer_page_end(src_argb);
2325   free_aligned_buffer_page_end(dst_rgb565);
2326   free_aligned_buffer_page_end(dst_rgb565dither);
2327   free_aligned_buffer_page_end(dst_argb);
2328   free_aligned_buffer_page_end(dst_argbdither);
2329 }
2330 
2331 #define TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
2332                         YALIGN, W1280, DIFF, N, NEG, OFF, FMT_C, BPP_C)        \
2333   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##Dither##N) {                \
2334     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
2335     const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                   \
2336     const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                      \
2337     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                        \
2338     const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);             \
2339     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
2340     align_buffer_page_end(src_u, kSizeUV + OFF);                               \
2341     align_buffer_page_end(src_v, kSizeUV + OFF);                               \
2342     align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF);                \
2343     align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF);              \
2344     for (int i = 0; i < kWidth * kHeight; ++i) {                               \
2345       src_y[i + OFF] = (fastrand() & 0xff);                                    \
2346     }                                                                          \
2347     for (int i = 0; i < kSizeUV; ++i) {                                        \
2348       src_u[i + OFF] = (fastrand() & 0xff);                                    \
2349       src_v[i + OFF] = (fastrand() & 0xff);                                    \
2350     }                                                                          \
2351     memset(dst_argb_c + OFF, 1, kStrideB * kHeight);                           \
2352     memset(dst_argb_opt + OFF, 101, kStrideB * kHeight);                       \
2353     MaskCpuFlags(disable_cpu_flags_);                                          \
2354     FMT_PLANAR##To##FMT_B##Dither(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
2355                                   src_v + OFF, kStrideUV, dst_argb_c + OFF,    \
2356                                   kStrideB, NULL, kWidth, NEG kHeight);        \
2357     MaskCpuFlags(benchmark_cpu_info_);                                         \
2358     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
2359       FMT_PLANAR##To##FMT_B##Dither(                                           \
2360           src_y + OFF, kWidth, src_u + OFF, kStrideUV, src_v + OFF, kStrideUV, \
2361           dst_argb_opt + OFF, kStrideB, NULL, kWidth, NEG kHeight);            \
2362     }                                                                          \
2363     int max_diff = 0;                                                          \
2364     /* Convert to ARGB so 565 is expanded to bytes that can be compared. */    \
2365     align_buffer_page_end(dst_argb32_c, kWidth* BPP_C* kHeight);               \
2366     align_buffer_page_end(dst_argb32_opt, kWidth* BPP_C* kHeight);             \
2367     memset(dst_argb32_c, 2, kWidth* BPP_C* kHeight);                           \
2368     memset(dst_argb32_opt, 102, kWidth* BPP_C* kHeight);                       \
2369     FMT_B##To##FMT_C(dst_argb_c + OFF, kStrideB, dst_argb32_c, kWidth * BPP_C, \
2370                      kWidth, kHeight);                                         \
2371     FMT_B##To##FMT_C(dst_argb_opt + OFF, kStrideB, dst_argb32_opt,             \
2372                      kWidth * BPP_C, kWidth, kHeight);                         \
2373     for (int i = 0; i < kWidth * BPP_C * kHeight; ++i) {                       \
2374       int abs_diff = abs(static_cast<int>(dst_argb32_c[i]) -                   \
2375                          static_cast<int>(dst_argb32_opt[i]));                 \
2376       if (abs_diff > max_diff) {                                               \
2377         max_diff = abs_diff;                                                   \
2378       }                                                                        \
2379     }                                                                          \
2380     EXPECT_LE(max_diff, DIFF);                                                 \
2381     free_aligned_buffer_page_end(src_y);                                       \
2382     free_aligned_buffer_page_end(src_u);                                       \
2383     free_aligned_buffer_page_end(src_v);                                       \
2384     free_aligned_buffer_page_end(dst_argb_c);                                  \
2385     free_aligned_buffer_page_end(dst_argb_opt);                                \
2386     free_aligned_buffer_page_end(dst_argb32_c);                                \
2387     free_aligned_buffer_page_end(dst_argb32_opt);                              \
2388   }
2389 
2390 #define TESTPLANARTOBD(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,  \
2391                        YALIGN, DIFF, FMT_C, BPP_C)                             \
2392   TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,       \
2393                   YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, FMT_C,       \
2394                   BPP_C)                                                       \
2395   TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,       \
2396                   YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, FMT_C,     \
2397                   BPP_C)                                                       \
2398   TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,       \
2399                   YALIGN, benchmark_width_, DIFF, _Invert, -, 0, FMT_C, BPP_C) \
2400   TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,       \
2401                   YALIGN, benchmark_width_, DIFF, _Opt, +, 0, FMT_C, BPP_C)
2402 
2403 TESTPLANARTOBD(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4)
2404 
2405 #define TESTPTOB(NAME, UYVYTOI420, UYVYTONV12)                                \
2406   TEST_F(LibYUVConvertTest, NAME) {                                           \
2407     const int kWidth = benchmark_width_;                                      \
2408     const int kHeight = benchmark_height_;                                    \
2409                                                                               \
2410     align_buffer_page_end(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2) * kHeight);     \
2411     align_buffer_page_end(orig_y, kWidth* kHeight);                           \
2412     align_buffer_page_end(orig_u,                                             \
2413                           SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2));      \
2414     align_buffer_page_end(orig_v,                                             \
2415                           SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2));      \
2416                                                                               \
2417     align_buffer_page_end(dst_y_orig, kWidth* kHeight);                       \
2418     align_buffer_page_end(dst_uv_orig,                                        \
2419                           2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2));  \
2420                                                                               \
2421     align_buffer_page_end(dst_y, kWidth* kHeight);                            \
2422     align_buffer_page_end(dst_uv,                                             \
2423                           2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2));  \
2424                                                                               \
2425     MemRandomize(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2) * kHeight);              \
2426                                                                               \
2427     /* Convert UYVY to NV12 in 2 steps for reference */                       \
2428     libyuv::UYVYTOI420(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2), orig_y, kWidth,   \
2429                        orig_u, SUBSAMPLE(kWidth, 2), orig_v,                  \
2430                        SUBSAMPLE(kWidth, 2), kWidth, kHeight);                \
2431     libyuv::I420ToNV12(orig_y, kWidth, orig_u, SUBSAMPLE(kWidth, 2), orig_v,  \
2432                        SUBSAMPLE(kWidth, 2), dst_y_orig, kWidth, dst_uv_orig, \
2433                        2 * SUBSAMPLE(kWidth, 2), kWidth, kHeight);            \
2434                                                                               \
2435     /* Convert to NV12 */                                                     \
2436     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
2437       libyuv::UYVYTONV12(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2), dst_y, kWidth,  \
2438                          dst_uv, 2 * SUBSAMPLE(kWidth, 2), kWidth, kHeight);  \
2439     }                                                                         \
2440                                                                               \
2441     for (int i = 0; i < kWidth * kHeight; ++i) {                              \
2442       EXPECT_EQ(orig_y[i], dst_y[i]);                                         \
2443     }                                                                         \
2444     for (int i = 0; i < kWidth * kHeight; ++i) {                              \
2445       EXPECT_EQ(dst_y_orig[i], dst_y[i]);                                     \
2446     }                                                                         \
2447     for (int i = 0; i < 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2);     \
2448          ++i) {                                                               \
2449       EXPECT_EQ(dst_uv_orig[i], dst_uv[i]);                                   \
2450     }                                                                         \
2451                                                                               \
2452     free_aligned_buffer_page_end(orig_uyvy);                                  \
2453     free_aligned_buffer_page_end(orig_y);                                     \
2454     free_aligned_buffer_page_end(orig_u);                                     \
2455     free_aligned_buffer_page_end(orig_v);                                     \
2456     free_aligned_buffer_page_end(dst_y_orig);                                 \
2457     free_aligned_buffer_page_end(dst_uv_orig);                                \
2458     free_aligned_buffer_page_end(dst_y);                                      \
2459     free_aligned_buffer_page_end(dst_uv);                                     \
2460   }
2461 
TESTPTOB(TestYUY2ToNV12,YUY2ToI420,YUY2ToNV12)2462 TESTPTOB(TestYUY2ToNV12, YUY2ToI420, YUY2ToNV12)
2463 TESTPTOB(TestUYVYToNV12, UYVYToI420, UYVYToNV12)
2464 
2465 // Transitive tests.  A to B to C is same as A to C.
2466 
2467 #define TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
2468                        W1280, N, NEG, OFF, FMT_C, BPP_C)                      \
2469   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) {             \
2470     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                           \
2471     const int kHeight = benchmark_height_;                                    \
2472     const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B;                    \
2473     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                       \
2474     const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);            \
2475     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                      \
2476     align_buffer_page_end(src_u, kSizeUV + OFF);                              \
2477     align_buffer_page_end(src_v, kSizeUV + OFF);                              \
2478     align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF);               \
2479     for (int i = 0; i < kWidth * kHeight; ++i) {                              \
2480       src_y[i + OFF] = (fastrand() & 0xff);                                   \
2481     }                                                                         \
2482     for (int i = 0; i < kSizeUV; ++i) {                                       \
2483       src_u[i + OFF] = (fastrand() & 0xff);                                   \
2484       src_v[i + OFF] = (fastrand() & 0xff);                                   \
2485     }                                                                         \
2486     memset(dst_argb_b + OFF, 1, kStrideB * kHeight);                          \
2487     for (int i = 0; i < benchmark_iterations_; ++i) {                         \
2488       FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV,      \
2489                             src_v + OFF, kStrideUV, dst_argb_b + OFF,         \
2490                             kStrideB, kWidth, NEG kHeight);                   \
2491     }                                                                         \
2492     /* Convert to a 3rd format in 1 step and 2 steps and compare  */          \
2493     const int kStrideC = kWidth * BPP_C;                                      \
2494     align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF);               \
2495     align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF);              \
2496     memset(dst_argb_c + OFF, 2, kStrideC * kHeight);                          \
2497     memset(dst_argb_bc + OFF, 3, kStrideC * kHeight);                         \
2498     FMT_PLANAR##To##FMT_C(src_y + OFF, kWidth, src_u + OFF, kStrideUV,        \
2499                           src_v + OFF, kStrideUV, dst_argb_c + OFF, kStrideC, \
2500                           kWidth, NEG kHeight);                               \
2501     /* Convert B to C */                                                      \
2502     FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC, \
2503                      kWidth, kHeight);                                        \
2504     for (int i = 0; i < kStrideC * kHeight; ++i) {                            \
2505       EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_bc[i + OFF]);                   \
2506     }                                                                         \
2507     free_aligned_buffer_page_end(src_y);                                      \
2508     free_aligned_buffer_page_end(src_u);                                      \
2509     free_aligned_buffer_page_end(src_v);                                      \
2510     free_aligned_buffer_page_end(dst_argb_b);                                 \
2511     free_aligned_buffer_page_end(dst_argb_c);                                 \
2512     free_aligned_buffer_page_end(dst_argb_bc);                                \
2513   }
2514 
2515 #define TESTPLANARTOE(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
2516                       FMT_C, BPP_C)                                          \
2517   TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
2518                  benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C)             \
2519   TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
2520                  benchmark_width_, _Unaligned, +, 1, FMT_C, BPP_C)           \
2521   TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
2522                  benchmark_width_, _Invert, -, 0, FMT_C, BPP_C)              \
2523   TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
2524                  benchmark_width_, _Opt, +, 0, FMT_C, BPP_C)
2525 
2526 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ABGR, 4)
2527 TESTPLANARTOE(J420, 2, 2, ARGB, 1, 4, ARGB, 4)
2528 TESTPLANARTOE(J420, 2, 2, ABGR, 1, 4, ARGB, 4)
2529 TESTPLANARTOE(H420, 2, 2, ARGB, 1, 4, ARGB, 4)
2530 TESTPLANARTOE(H420, 2, 2, ABGR, 1, 4, ARGB, 4)
2531 TESTPLANARTOE(I420, 2, 2, BGRA, 1, 4, ARGB, 4)
2532 TESTPLANARTOE(I420, 2, 2, ABGR, 1, 4, ARGB, 4)
2533 TESTPLANARTOE(I420, 2, 2, RGBA, 1, 4, ARGB, 4)
2534 TESTPLANARTOE(I420, 2, 2, RGB24, 1, 3, ARGB, 4)
2535 TESTPLANARTOE(I420, 2, 2, RAW, 1, 3, RGB24, 3)
2536 TESTPLANARTOE(I420, 2, 2, RGB24, 1, 3, RAW, 3)
2537 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, RAW, 3)
2538 TESTPLANARTOE(I420, 2, 2, RAW, 1, 3, ARGB, 4)
2539 TESTPLANARTOE(H420, 2, 2, RGB24, 1, 3, ARGB, 4)
2540 TESTPLANARTOE(H420, 2, 2, RAW, 1, 3, RGB24, 3)
2541 TESTPLANARTOE(H420, 2, 2, RGB24, 1, 3, RAW, 3)
2542 TESTPLANARTOE(H420, 2, 2, ARGB, 1, 4, RAW, 3)
2543 TESTPLANARTOE(H420, 2, 2, RAW, 1, 3, ARGB, 4)
2544 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, RGB565, 2)
2545 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ARGB1555, 2)
2546 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ARGB4444, 2)
2547 TESTPLANARTOE(I422, 2, 1, ARGB, 1, 4, RGB565, 2)
2548 TESTPLANARTOE(J422, 2, 1, ARGB, 1, 4, ARGB, 4)
2549 TESTPLANARTOE(J422, 2, 1, ABGR, 1, 4, ARGB, 4)
2550 TESTPLANARTOE(H422, 2, 1, ARGB, 1, 4, ARGB, 4)
2551 TESTPLANARTOE(H422, 2, 1, ABGR, 1, 4, ARGB, 4)
2552 TESTPLANARTOE(I422, 2, 1, BGRA, 1, 4, ARGB, 4)
2553 TESTPLANARTOE(I422, 2, 1, ABGR, 1, 4, ARGB, 4)
2554 TESTPLANARTOE(I422, 2, 1, RGBA, 1, 4, ARGB, 4)
2555 TESTPLANARTOE(I444, 1, 1, ARGB, 1, 4, ARGB, 4)
2556 TESTPLANARTOE(J444, 1, 1, ARGB, 1, 4, ARGB, 4)
2557 TESTPLANARTOE(I444, 1, 1, ABGR, 1, 4, ARGB, 4)
2558 TESTPLANARTOE(I420, 2, 2, YUY2, 2, 4, ARGB, 4)
2559 TESTPLANARTOE(I420, 2, 2, UYVY, 2, 4, ARGB, 4)
2560 TESTPLANARTOE(I422, 2, 1, YUY2, 2, 4, ARGB, 4)
2561 TESTPLANARTOE(I422, 2, 1, UYVY, 2, 4, ARGB, 4)
2562 
2563 #define TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
2564                         W1280, N, NEG, OFF, FMT_C, BPP_C, ATTEN)               \
2565   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) {              \
2566     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
2567     const int kHeight = benchmark_height_;                                     \
2568     const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B;                     \
2569     const int kSizeUV =                                                        \
2570         SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y);          \
2571     align_buffer_page_end(src_y, kWidth* kHeight + OFF);                       \
2572     align_buffer_page_end(src_u, kSizeUV + OFF);                               \
2573     align_buffer_page_end(src_v, kSizeUV + OFF);                               \
2574     align_buffer_page_end(src_a, kWidth* kHeight + OFF);                       \
2575     align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF);                \
2576     for (int i = 0; i < kWidth * kHeight; ++i) {                               \
2577       src_y[i + OFF] = (fastrand() & 0xff);                                    \
2578       src_a[i + OFF] = (fastrand() & 0xff);                                    \
2579     }                                                                          \
2580     for (int i = 0; i < kSizeUV; ++i) {                                        \
2581       src_u[i + OFF] = (fastrand() & 0xff);                                    \
2582       src_v[i + OFF] = (fastrand() & 0xff);                                    \
2583     }                                                                          \
2584     memset(dst_argb_b + OFF, 1, kStrideB * kHeight);                           \
2585     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
2586       FMT_PLANAR##To##FMT_B(                                                   \
2587           src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SUBSAMP_X),      \
2588           src_v + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), src_a + OFF, kWidth,      \
2589           dst_argb_b + OFF, kStrideB, kWidth, NEG kHeight, ATTEN);             \
2590     }                                                                          \
2591     /* Convert to a 3rd format in 1 step and 2 steps and compare  */           \
2592     const int kStrideC = kWidth * BPP_C;                                       \
2593     align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF);                \
2594     align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF);               \
2595     memset(dst_argb_c + OFF, 2, kStrideC * kHeight);                           \
2596     memset(dst_argb_bc + OFF, 3, kStrideC * kHeight);                          \
2597     FMT_PLANAR##To##FMT_C(                                                     \
2598         src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SUBSAMP_X),        \
2599         src_v + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), src_a + OFF, kWidth,        \
2600         dst_argb_c + OFF, kStrideC, kWidth, NEG kHeight, ATTEN);               \
2601     /* Convert B to C */                                                       \
2602     FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC,  \
2603                      kWidth, kHeight);                                         \
2604     for (int i = 0; i < kStrideC * kHeight; ++i) {                             \
2605       EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_bc[i + OFF]);                    \
2606     }                                                                          \
2607     free_aligned_buffer_page_end(src_y);                                       \
2608     free_aligned_buffer_page_end(src_u);                                       \
2609     free_aligned_buffer_page_end(src_v);                                       \
2610     free_aligned_buffer_page_end(src_a);                                       \
2611     free_aligned_buffer_page_end(dst_argb_b);                                  \
2612     free_aligned_buffer_page_end(dst_argb_c);                                  \
2613     free_aligned_buffer_page_end(dst_argb_bc);                                 \
2614   }
2615 
2616 #define TESTQPLANARTOE(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
2617                        FMT_C, BPP_C)                                          \
2618   TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
2619                   benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C, 0)          \
2620   TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
2621                   benchmark_width_, _Unaligned, +, 1, FMT_C, BPP_C, 0)        \
2622   TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
2623                   benchmark_width_, _Invert, -, 0, FMT_C, BPP_C, 0)           \
2624   TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
2625                   benchmark_width_, _Opt, +, 0, FMT_C, BPP_C, 0)              \
2626   TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
2627                   benchmark_width_, _Premult, +, 0, FMT_C, BPP_C, 1)
2628 
2629 TESTQPLANARTOE(I420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4)
2630 TESTQPLANARTOE(I420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4)
2631 
2632 #define TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, W1280, N, NEG, \
2633                       OFF, FMT_C, BPP_C)                                       \
2634   TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##_##FMT_C##N) {                   \
2635     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                            \
2636     const int kHeight = benchmark_height_;                                     \
2637     const int kStrideA = SUBSAMPLE(kWidth, SUB_A) * BPP_A;                     \
2638     const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B;                     \
2639     align_buffer_page_end(src_argb_a, kStrideA* kHeight + OFF);                \
2640     align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF);                \
2641     MemRandomize(src_argb_a + OFF, kStrideA * kHeight);                        \
2642     memset(dst_argb_b + OFF, 1, kStrideB * kHeight);                           \
2643     for (int i = 0; i < benchmark_iterations_; ++i) {                          \
2644       FMT_A##To##FMT_B(src_argb_a + OFF, kStrideA, dst_argb_b + OFF, kStrideB, \
2645                        kWidth, NEG kHeight);                                   \
2646     }                                                                          \
2647     /* Convert to a 3rd format in 1 step and 2 steps and compare  */           \
2648     const int kStrideC = kWidth * BPP_C;                                       \
2649     align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF);                \
2650     align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF);               \
2651     memset(dst_argb_c + OFF, 2, kStrideC * kHeight);                           \
2652     memset(dst_argb_bc + OFF, 3, kStrideC * kHeight);                          \
2653     FMT_A##To##FMT_C(src_argb_a + OFF, kStrideA, dst_argb_c + OFF, kStrideC,   \
2654                      kWidth, NEG kHeight);                                     \
2655     /* Convert B to C */                                                       \
2656     FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC,  \
2657                      kWidth, kHeight);                                         \
2658     for (int i = 0; i < kStrideC * kHeight; i += 4) {                          \
2659       EXPECT_EQ(dst_argb_c[i + OFF + 0], dst_argb_bc[i + OFF + 0]);            \
2660       EXPECT_EQ(dst_argb_c[i + OFF + 1], dst_argb_bc[i + OFF + 1]);            \
2661       EXPECT_EQ(dst_argb_c[i + OFF + 2], dst_argb_bc[i + OFF + 2]);            \
2662       EXPECT_NEAR(dst_argb_c[i + OFF + 3], dst_argb_bc[i + OFF + 3], 64);      \
2663     }                                                                          \
2664     free_aligned_buffer_page_end(src_argb_a);                                  \
2665     free_aligned_buffer_page_end(dst_argb_b);                                  \
2666     free_aligned_buffer_page_end(dst_argb_c);                                  \
2667     free_aligned_buffer_page_end(dst_argb_bc);                                 \
2668   }
2669 
2670 #define TESTPLANETOE(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, FMT_C, BPP_C) \
2671   TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B,                    \
2672                 benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C)              \
2673   TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_,  \
2674                 _Unaligned, +, 1, FMT_C, BPP_C)                              \
2675   TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_,  \
2676                 _Invert, -, 0, FMT_C, BPP_C)                                 \
2677   TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_,  \
2678                 _Opt, +, 0, FMT_C, BPP_C)
2679 
2680 // Caveat: Destination needs to be 4 bytes
2681 TESTPLANETOE(ARGB, 1, 4, AR30, 1, 4, ARGB, 4)
2682 TESTPLANETOE(ABGR, 1, 4, AR30, 1, 4, ABGR, 4)
2683 TESTPLANETOE(AR30, 1, 4, ARGB, 1, 4, ABGR, 4)
2684 TESTPLANETOE(AR30, 1, 4, ABGR, 1, 4, ARGB, 4)
2685 TESTPLANETOE(ARGB, 1, 4, AB30, 1, 4, ARGB, 4)
2686 TESTPLANETOE(ABGR, 1, 4, AB30, 1, 4, ABGR, 4)
2687 TESTPLANETOE(AB30, 1, 4, ARGB, 1, 4, ABGR, 4)
2688 TESTPLANETOE(AB30, 1, 4, ABGR, 1, 4, ARGB, 4)
2689 
2690 TEST_F(LibYUVConvertTest, RotateWithARGBSource) {
2691   // 2x2 frames
2692   uint32_t src[4];
2693   uint32_t dst[4];
2694   // some random input
2695   src[0] = 0x11000000;
2696   src[1] = 0x00450000;
2697   src[2] = 0x00009f00;
2698   src[3] = 0x000000ff;
2699   // zeros on destination
2700   dst[0] = 0x00000000;
2701   dst[1] = 0x00000000;
2702   dst[2] = 0x00000000;
2703   dst[3] = 0x00000000;
2704 
2705   int r = ConvertToARGB(reinterpret_cast<uint8_t*>(src),
2706                         16,  // input size
2707                         reinterpret_cast<uint8_t*>(dst),
2708                         8,  // destination stride
2709                         0,  // crop_x
2710                         0,  // crop_y
2711                         2,  // width
2712                         2,  // height
2713                         2,  // crop width
2714                         2,  // crop height
2715                         kRotate90, FOURCC_ARGB);
2716 
2717   EXPECT_EQ(r, 0);
2718   // 90 degrees rotation, no conversion
2719   EXPECT_EQ(dst[0], src[2]);
2720   EXPECT_EQ(dst[1], src[0]);
2721   EXPECT_EQ(dst[2], src[3]);
2722   EXPECT_EQ(dst[3], src[1]);
2723 }
2724 
2725 #ifdef HAS_ARGBTOAR30ROW_AVX2
TEST_F(LibYUVConvertTest,ARGBToAR30Row_Opt)2726 TEST_F(LibYUVConvertTest, ARGBToAR30Row_Opt) {
2727   // ARGBToAR30Row_AVX2 expects a multiple of 8 pixels.
2728   const int kPixels = (benchmark_width_ * benchmark_height_ + 7) & ~7;
2729   align_buffer_page_end(src, kPixels * 4);
2730   align_buffer_page_end(dst_opt, kPixels * 4);
2731   align_buffer_page_end(dst_c, kPixels * 4);
2732   MemRandomize(src, kPixels * 4);
2733   memset(dst_opt, 0, kPixels * 4);
2734   memset(dst_c, 1, kPixels * 4);
2735 
2736   ARGBToAR30Row_C(src, dst_c, kPixels);
2737 
2738   int has_avx2 = TestCpuFlag(kCpuHasAVX2);
2739   int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
2740   for (int i = 0; i < benchmark_iterations_; ++i) {
2741     if (has_avx2) {
2742       ARGBToAR30Row_AVX2(src, dst_opt, kPixels);
2743     } else if (has_ssse3) {
2744       ARGBToAR30Row_SSSE3(src, dst_opt, kPixels);
2745     } else {
2746       ARGBToAR30Row_C(src, dst_opt, kPixels);
2747     }
2748   }
2749   for (int i = 0; i < kPixels * 4; ++i) {
2750     EXPECT_EQ(dst_opt[i], dst_c[i]);
2751   }
2752 
2753   free_aligned_buffer_page_end(src);
2754   free_aligned_buffer_page_end(dst_opt);
2755   free_aligned_buffer_page_end(dst_c);
2756 }
2757 #endif  // HAS_ARGBTOAR30ROW_AVX2
2758 
2759 #ifdef HAS_ABGRTOAR30ROW_AVX2
TEST_F(LibYUVConvertTest,ABGRToAR30Row_Opt)2760 TEST_F(LibYUVConvertTest, ABGRToAR30Row_Opt) {
2761   // ABGRToAR30Row_AVX2 expects a multiple of 8 pixels.
2762   const int kPixels = (benchmark_width_ * benchmark_height_ + 7) & ~7;
2763   align_buffer_page_end(src, kPixels * 4);
2764   align_buffer_page_end(dst_opt, kPixels * 4);
2765   align_buffer_page_end(dst_c, kPixels * 4);
2766   MemRandomize(src, kPixels * 4);
2767   memset(dst_opt, 0, kPixels * 4);
2768   memset(dst_c, 1, kPixels * 4);
2769 
2770   ABGRToAR30Row_C(src, dst_c, kPixels);
2771 
2772   int has_avx2 = TestCpuFlag(kCpuHasAVX2);
2773   int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
2774   for (int i = 0; i < benchmark_iterations_; ++i) {
2775     if (has_avx2) {
2776       ABGRToAR30Row_AVX2(src, dst_opt, kPixels);
2777     } else if (has_ssse3) {
2778       ABGRToAR30Row_SSSE3(src, dst_opt, kPixels);
2779     } else {
2780       ABGRToAR30Row_C(src, dst_opt, kPixels);
2781     }
2782   }
2783   for (int i = 0; i < kPixels * 4; ++i) {
2784     EXPECT_EQ(dst_opt[i], dst_c[i]);
2785   }
2786 
2787   free_aligned_buffer_page_end(src);
2788   free_aligned_buffer_page_end(dst_opt);
2789   free_aligned_buffer_page_end(dst_c);
2790 }
2791 #endif  // HAS_ABGRTOAR30ROW_AVX2
2792 
2793 // TODO(fbarchard): Fix clamping issue affected by U channel.
2794 #define TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,   \
2795                          ALIGN, YALIGN, W1280, DIFF, N, NEG, SOFF, DOFF)   \
2796   TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                    \
2797     const int kWidth = ((W1280) > 0) ? (W1280) : 1;                        \
2798     const int kHeight = ALIGNINT(benchmark_height_, YALIGN);               \
2799     const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                  \
2800     const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                    \
2801     const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);         \
2802     const int kBpc = 2;                                                    \
2803     align_buffer_page_end(src_y, kWidth* kHeight* kBpc + SOFF);            \
2804     align_buffer_page_end(src_u, kSizeUV* kBpc + SOFF);                    \
2805     align_buffer_page_end(src_v, kSizeUV* kBpc + SOFF);                    \
2806     align_buffer_page_end(dst_argb_c, kStrideB* kHeight + DOFF);           \
2807     align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + DOFF);         \
2808     for (int i = 0; i < kWidth * kHeight; ++i) {                           \
2809       reinterpret_cast<uint16_t*>(src_y + SOFF)[i] = (fastrand() & 0x3ff); \
2810     }                                                                      \
2811     for (int i = 0; i < kSizeUV; ++i) {                                    \
2812       reinterpret_cast<uint16_t*>(src_u + SOFF)[i] = (fastrand() & 0x3ff); \
2813       reinterpret_cast<uint16_t*>(src_v + SOFF)[i] = (fastrand() & 0x3ff); \
2814     }                                                                      \
2815     memset(dst_argb_c + DOFF, 1, kStrideB * kHeight);                      \
2816     memset(dst_argb_opt + DOFF, 101, kStrideB * kHeight);                  \
2817     MaskCpuFlags(disable_cpu_flags_);                                      \
2818     FMT_PLANAR##To##FMT_B(                                                 \
2819         reinterpret_cast<uint16_t*>(src_y + SOFF), kWidth,                 \
2820         reinterpret_cast<uint16_t*>(src_u + SOFF), kStrideUV,              \
2821         reinterpret_cast<uint16_t*>(src_v + SOFF), kStrideUV,              \
2822         dst_argb_c + DOFF, kStrideB, kWidth, NEG kHeight);                 \
2823     MaskCpuFlags(benchmark_cpu_info_);                                     \
2824     for (int i = 0; i < benchmark_iterations_; ++i) {                      \
2825       FMT_PLANAR##To##FMT_B(                                               \
2826           reinterpret_cast<uint16_t*>(src_y + SOFF), kWidth,               \
2827           reinterpret_cast<uint16_t*>(src_u + SOFF), kStrideUV,            \
2828           reinterpret_cast<uint16_t*>(src_v + SOFF), kStrideUV,            \
2829           dst_argb_opt + DOFF, kStrideB, kWidth, NEG kHeight);             \
2830     }                                                                      \
2831     int max_diff = 0;                                                      \
2832     for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) {                   \
2833       int abs_diff = abs(static_cast<int>(dst_argb_c[i + DOFF]) -          \
2834                          static_cast<int>(dst_argb_opt[i + DOFF]));        \
2835       if (abs_diff > max_diff) {                                           \
2836         max_diff = abs_diff;                                               \
2837       }                                                                    \
2838     }                                                                      \
2839     EXPECT_LE(max_diff, DIFF);                                             \
2840     free_aligned_buffer_page_end(src_y);                                   \
2841     free_aligned_buffer_page_end(src_u);                                   \
2842     free_aligned_buffer_page_end(src_v);                                   \
2843     free_aligned_buffer_page_end(dst_argb_c);                              \
2844     free_aligned_buffer_page_end(dst_argb_opt);                            \
2845   }
2846 
2847 #define TESTPLANAR16TOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
2848                         YALIGN, DIFF)                                          \
2849   TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
2850                    YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, 0)          \
2851   TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
2852                    YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, 1)        \
2853   TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
2854                    YALIGN, benchmark_width_, DIFF, _Invert, -, 0, 0)           \
2855   TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
2856                    YALIGN, benchmark_width_, DIFF, _Opt, +, 0, 0)
2857 
2858 TESTPLANAR16TOB(I010, 2, 2, ARGB, 4, 4, 1, 2)
2859 TESTPLANAR16TOB(I010, 2, 2, ABGR, 4, 4, 1, 2)
2860 TESTPLANAR16TOB(I010, 2, 2, AR30, 4, 4, 1, 2)
2861 TESTPLANAR16TOB(I010, 2, 2, AB30, 4, 4, 1, 2)
2862 TESTPLANAR16TOB(H010, 2, 2, ARGB, 4, 4, 1, 2)
2863 TESTPLANAR16TOB(H010, 2, 2, ABGR, 4, 4, 1, 2)
2864 TESTPLANAR16TOB(H010, 2, 2, AR30, 4, 4, 1, 2)
2865 TESTPLANAR16TOB(H010, 2, 2, AB30, 4, 4, 1, 2)
2866 
Clamp(int y)2867 static int Clamp(int y) {
2868   if (y < 0) {
2869     y = 0;
2870   }
2871   if (y > 255) {
2872     y = 255;
2873   }
2874   return y;
2875 }
2876 
Clamp10(int y)2877 static int Clamp10(int y) {
2878   if (y < 0) {
2879     y = 0;
2880   }
2881   if (y > 1023) {
2882     y = 1023;
2883   }
2884   return y;
2885 }
2886 
2887 // Test 8 bit YUV to 8 bit RGB
TEST_F(LibYUVConvertTest,TestH420ToARGB)2888 TEST_F(LibYUVConvertTest, TestH420ToARGB) {
2889   const int kSize = 256;
2890   int histogram_b[256];
2891   int histogram_g[256];
2892   int histogram_r[256];
2893   memset(histogram_b, 0, sizeof(histogram_b));
2894   memset(histogram_g, 0, sizeof(histogram_g));
2895   memset(histogram_r, 0, sizeof(histogram_r));
2896   align_buffer_page_end(orig_yuv, kSize + kSize / 2 * 2);
2897   align_buffer_page_end(argb_pixels, kSize * 4);
2898   uint8_t* orig_y = orig_yuv;
2899   uint8_t* orig_u = orig_y + kSize;
2900   uint8_t* orig_v = orig_u + kSize / 2;
2901 
2902   // Test grey scale
2903   for (int i = 0; i < kSize; ++i) {
2904     orig_y[i] = i;
2905   }
2906   for (int i = 0; i < kSize / 2; ++i) {
2907     orig_u[i] = 128;  // 128 is 0.
2908     orig_v[i] = 128;
2909   }
2910 
2911   H420ToARGB(orig_y, 0, orig_u, 0, orig_v, 0, argb_pixels, 0, kSize, 1);
2912 
2913   for (int i = 0; i < kSize; ++i) {
2914     int b = argb_pixels[i * 4 + 0];
2915     int g = argb_pixels[i * 4 + 1];
2916     int r = argb_pixels[i * 4 + 2];
2917     int a = argb_pixels[i * 4 + 3];
2918     ++histogram_b[b];
2919     ++histogram_g[g];
2920     ++histogram_r[r];
2921     int expected_y = Clamp(static_cast<int>((i - 16) * 1.164f));
2922     EXPECT_NEAR(b, expected_y, 1);
2923     EXPECT_NEAR(g, expected_y, 1);
2924     EXPECT_NEAR(r, expected_y, 1);
2925     EXPECT_EQ(a, 255);
2926   }
2927 
2928   int count_b = 0;
2929   int count_g = 0;
2930   int count_r = 0;
2931   for (int i = 0; i < kSize; ++i) {
2932     if (histogram_b[i]) {
2933       ++count_b;
2934     }
2935     if (histogram_g[i]) {
2936       ++count_g;
2937     }
2938     if (histogram_r[i]) {
2939       ++count_r;
2940     }
2941   }
2942   printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2943 
2944   free_aligned_buffer_page_end(orig_yuv);
2945   free_aligned_buffer_page_end(argb_pixels);
2946 }
2947 
2948 // Test 10 bit YUV to 8 bit RGB
TEST_F(LibYUVConvertTest,TestH010ToARGB)2949 TEST_F(LibYUVConvertTest, TestH010ToARGB) {
2950   const int kSize = 1024;
2951   int histogram_b[1024];
2952   int histogram_g[1024];
2953   int histogram_r[1024];
2954   memset(histogram_b, 0, sizeof(histogram_b));
2955   memset(histogram_g, 0, sizeof(histogram_g));
2956   memset(histogram_r, 0, sizeof(histogram_r));
2957   align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2);
2958   align_buffer_page_end(argb_pixels, kSize * 4);
2959   uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv);
2960   uint16_t* orig_u = orig_y + kSize;
2961   uint16_t* orig_v = orig_u + kSize / 2;
2962 
2963   // Test grey scale
2964   for (int i = 0; i < kSize; ++i) {
2965     orig_y[i] = i;
2966   }
2967   for (int i = 0; i < kSize / 2; ++i) {
2968     orig_u[i] = 512;  // 512 is 0.
2969     orig_v[i] = 512;
2970   }
2971 
2972   H010ToARGB(orig_y, 0, orig_u, 0, orig_v, 0, argb_pixels, 0, kSize, 1);
2973 
2974   for (int i = 0; i < kSize; ++i) {
2975     int b = argb_pixels[i * 4 + 0];
2976     int g = argb_pixels[i * 4 + 1];
2977     int r = argb_pixels[i * 4 + 2];
2978     int a = argb_pixels[i * 4 + 3];
2979     ++histogram_b[b];
2980     ++histogram_g[g];
2981     ++histogram_r[r];
2982     int expected_y = Clamp(static_cast<int>((i - 64) * 1.164f / 4));
2983     EXPECT_NEAR(b, expected_y, 1);
2984     EXPECT_NEAR(g, expected_y, 1);
2985     EXPECT_NEAR(r, expected_y, 1);
2986     EXPECT_EQ(a, 255);
2987   }
2988 
2989   int count_b = 0;
2990   int count_g = 0;
2991   int count_r = 0;
2992   for (int i = 0; i < kSize; ++i) {
2993     if (histogram_b[i]) {
2994       ++count_b;
2995     }
2996     if (histogram_g[i]) {
2997       ++count_g;
2998     }
2999     if (histogram_r[i]) {
3000       ++count_r;
3001     }
3002   }
3003   printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
3004 
3005   free_aligned_buffer_page_end(orig_yuv);
3006   free_aligned_buffer_page_end(argb_pixels);
3007 }
3008 
3009 // Test 10 bit YUV to 10 bit RGB
3010 // Caveat: Result is near due to float rounding in expected
3011 // result.
TEST_F(LibYUVConvertTest,TestH010ToAR30)3012 TEST_F(LibYUVConvertTest, TestH010ToAR30) {
3013   const int kSize = 1024;
3014   int histogram_b[1024];
3015   int histogram_g[1024];
3016   int histogram_r[1024];
3017   memset(histogram_b, 0, sizeof(histogram_b));
3018   memset(histogram_g, 0, sizeof(histogram_g));
3019   memset(histogram_r, 0, sizeof(histogram_r));
3020 
3021   align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2);
3022   align_buffer_page_end(ar30_pixels, kSize * 4);
3023   uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv);
3024   uint16_t* orig_u = orig_y + kSize;
3025   uint16_t* orig_v = orig_u + kSize / 2;
3026 
3027   // Test grey scale
3028   for (int i = 0; i < kSize; ++i) {
3029     orig_y[i] = i;
3030   }
3031   for (int i = 0; i < kSize / 2; ++i) {
3032     orig_u[i] = 512;  // 512 is 0.
3033     orig_v[i] = 512;
3034   }
3035 
3036   H010ToAR30(orig_y, 0, orig_u, 0, orig_v, 0, ar30_pixels, 0, kSize, 1);
3037 
3038   for (int i = 0; i < kSize; ++i) {
3039     int b10 = reinterpret_cast<uint32_t*>(ar30_pixels)[i] & 1023;
3040     int g10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 10) & 1023;
3041     int r10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 20) & 1023;
3042     int a2 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 30) & 3;
3043     ++histogram_b[b10];
3044     ++histogram_g[g10];
3045     ++histogram_r[r10];
3046     int expected_y = Clamp10(static_cast<int>((i - 64) * 1.164f));
3047     EXPECT_NEAR(b10, expected_y, 4);
3048     EXPECT_NEAR(g10, expected_y, 4);
3049     EXPECT_NEAR(r10, expected_y, 4);
3050     EXPECT_EQ(a2, 3);
3051   }
3052 
3053   int count_b = 0;
3054   int count_g = 0;
3055   int count_r = 0;
3056   for (int i = 0; i < kSize; ++i) {
3057     if (histogram_b[i]) {
3058       ++count_b;
3059     }
3060     if (histogram_g[i]) {
3061       ++count_g;
3062     }
3063     if (histogram_r[i]) {
3064       ++count_r;
3065     }
3066   }
3067   printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
3068 
3069   free_aligned_buffer_page_end(orig_yuv);
3070   free_aligned_buffer_page_end(ar30_pixels);
3071 }
3072 
3073 // Test 10 bit YUV to 10 bit RGB
3074 // Caveat: Result is near due to float rounding in expected
3075 // result.
TEST_F(LibYUVConvertTest,TestH010ToAB30)3076 TEST_F(LibYUVConvertTest, TestH010ToAB30) {
3077   const int kSize = 1024;
3078   int histogram_b[1024];
3079   int histogram_g[1024];
3080   int histogram_r[1024];
3081   memset(histogram_b, 0, sizeof(histogram_b));
3082   memset(histogram_g, 0, sizeof(histogram_g));
3083   memset(histogram_r, 0, sizeof(histogram_r));
3084 
3085   align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2);
3086   align_buffer_page_end(ab30_pixels, kSize * 4);
3087   uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv);
3088   uint16_t* orig_u = orig_y + kSize;
3089   uint16_t* orig_v = orig_u + kSize / 2;
3090 
3091   // Test grey scale
3092   for (int i = 0; i < kSize; ++i) {
3093     orig_y[i] = i;
3094   }
3095   for (int i = 0; i < kSize / 2; ++i) {
3096     orig_u[i] = 512;  // 512 is 0.
3097     orig_v[i] = 512;
3098   }
3099 
3100   H010ToAB30(orig_y, 0, orig_u, 0, orig_v, 0, ab30_pixels, 0, kSize, 1);
3101 
3102   for (int i = 0; i < kSize; ++i) {
3103     int r10 = reinterpret_cast<uint32_t*>(ab30_pixels)[i] & 1023;
3104     int g10 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 10) & 1023;
3105     int b10 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 20) & 1023;
3106     int a2 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 30) & 3;
3107     ++histogram_b[b10];
3108     ++histogram_g[g10];
3109     ++histogram_r[r10];
3110     int expected_y = Clamp10(static_cast<int>((i - 64) * 1.164f));
3111     EXPECT_NEAR(b10, expected_y, 4);
3112     EXPECT_NEAR(g10, expected_y, 4);
3113     EXPECT_NEAR(r10, expected_y, 4);
3114     EXPECT_EQ(a2, 3);
3115   }
3116 
3117   int count_b = 0;
3118   int count_g = 0;
3119   int count_r = 0;
3120   for (int i = 0; i < kSize; ++i) {
3121     if (histogram_b[i]) {
3122       ++count_b;
3123     }
3124     if (histogram_g[i]) {
3125       ++count_g;
3126     }
3127     if (histogram_r[i]) {
3128       ++count_r;
3129     }
3130   }
3131   printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
3132 
3133   free_aligned_buffer_page_end(orig_yuv);
3134   free_aligned_buffer_page_end(ab30_pixels);
3135 }
3136 
3137 // Test 8 bit YUV to 10 bit RGB
TEST_F(LibYUVConvertTest,TestH420ToAR30)3138 TEST_F(LibYUVConvertTest, TestH420ToAR30) {
3139   const int kSize = 256;
3140   const int kHistSize = 1024;
3141   int histogram_b[kHistSize];
3142   int histogram_g[kHistSize];
3143   int histogram_r[kHistSize];
3144   memset(histogram_b, 0, sizeof(histogram_b));
3145   memset(histogram_g, 0, sizeof(histogram_g));
3146   memset(histogram_r, 0, sizeof(histogram_r));
3147   align_buffer_page_end(orig_yuv, kSize + kSize / 2 * 2);
3148   align_buffer_page_end(ar30_pixels, kSize * 4);
3149   uint8_t* orig_y = orig_yuv;
3150   uint8_t* orig_u = orig_y + kSize;
3151   uint8_t* orig_v = orig_u + kSize / 2;
3152 
3153   // Test grey scale
3154   for (int i = 0; i < kSize; ++i) {
3155     orig_y[i] = i;
3156   }
3157   for (int i = 0; i < kSize / 2; ++i) {
3158     orig_u[i] = 128;  // 128 is 0.
3159     orig_v[i] = 128;
3160   }
3161 
3162   H420ToAR30(orig_y, 0, orig_u, 0, orig_v, 0, ar30_pixels, 0, kSize, 1);
3163 
3164   for (int i = 0; i < kSize; ++i) {
3165     int b10 = reinterpret_cast<uint32_t*>(ar30_pixels)[i] & 1023;
3166     int g10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 10) & 1023;
3167     int r10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 20) & 1023;
3168     int a2 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 30) & 3;
3169     ++histogram_b[b10];
3170     ++histogram_g[g10];
3171     ++histogram_r[r10];
3172     int expected_y = Clamp10(static_cast<int>((i - 16) * 1.164f * 4.f));
3173     EXPECT_NEAR(b10, expected_y, 4);
3174     EXPECT_NEAR(g10, expected_y, 4);
3175     EXPECT_NEAR(r10, expected_y, 4);
3176     EXPECT_EQ(a2, 3);
3177   }
3178 
3179   int count_b = 0;
3180   int count_g = 0;
3181   int count_r = 0;
3182   for (int i = 0; i < kHistSize; ++i) {
3183     if (histogram_b[i]) {
3184       ++count_b;
3185     }
3186     if (histogram_g[i]) {
3187       ++count_g;
3188     }
3189     if (histogram_r[i]) {
3190       ++count_r;
3191     }
3192   }
3193   printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
3194 
3195   free_aligned_buffer_page_end(orig_yuv);
3196   free_aligned_buffer_page_end(ar30_pixels);
3197 }
3198 
3199 // Test RGB24 to ARGB and back to RGB24
TEST_F(LibYUVConvertTest,TestARGBToRGB24)3200 TEST_F(LibYUVConvertTest, TestARGBToRGB24) {
3201   const int kSize = 256;
3202   align_buffer_page_end(orig_rgb24, kSize * 3);
3203   align_buffer_page_end(argb_pixels, kSize * 4);
3204   align_buffer_page_end(dest_rgb24, kSize * 3);
3205 
3206   // Test grey scale
3207   for (int i = 0; i < kSize * 3; ++i) {
3208     orig_rgb24[i] = i;
3209   }
3210 
3211   RGB24ToARGB(orig_rgb24, 0, argb_pixels, 0, kSize, 1);
3212   ARGBToRGB24(argb_pixels, 0, dest_rgb24, 0, kSize, 1);
3213 
3214   for (int i = 0; i < kSize * 3; ++i) {
3215     EXPECT_EQ(orig_rgb24[i], dest_rgb24[i]);
3216   }
3217 
3218   free_aligned_buffer_page_end(orig_rgb24);
3219   free_aligned_buffer_page_end(argb_pixels);
3220   free_aligned_buffer_page_end(dest_rgb24);
3221 }
3222 
3223 }  // namespace libyuv
3224