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 "libyuv/convert.h"
12
13 #include "libyuv/basic_types.h"
14 #include "libyuv/cpu_id.h"
15 #include "libyuv/format_conversion.h"
16 #ifdef HAVE_JPEG
17 #include "libyuv/mjpeg_decoder.h"
18 #endif
19 #include "libyuv/planar_functions.h"
20 #include "libyuv/rotate.h"
21 #include "libyuv/video_common.h"
22 #include "libyuv/row.h"
23
24 #ifdef __cplusplus
25 namespace libyuv {
26 extern "C" {
27 #endif
28
29 // Copy I420 with optional flipping
30 LIBYUV_API
I420Copy(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)31 int I420Copy(const uint8* src_y, int src_stride_y,
32 const uint8* src_u, int src_stride_u,
33 const uint8* src_v, int src_stride_v,
34 uint8* dst_y, int dst_stride_y,
35 uint8* dst_u, int dst_stride_u,
36 uint8* dst_v, int dst_stride_v,
37 int width, int height) {
38 if (!src_y || !src_u || !src_v ||
39 !dst_y || !dst_u || !dst_v ||
40 width <= 0 || height == 0) {
41 return -1;
42 }
43 // Negative height means invert the image.
44 if (height < 0) {
45 height = -height;
46 int halfheight = (height + 1) >> 1;
47 src_y = src_y + (height - 1) * src_stride_y;
48 src_u = src_u + (halfheight - 1) * src_stride_u;
49 src_v = src_v + (halfheight - 1) * src_stride_v;
50 src_stride_y = -src_stride_y;
51 src_stride_u = -src_stride_u;
52 src_stride_v = -src_stride_v;
53 }
54
55 int halfwidth = (width + 1) >> 1;
56 int halfheight = (height + 1) >> 1;
57 if (dst_y) {
58 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
59 }
60 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
61 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
62 return 0;
63 }
64
65 // Move to row_win etc.
66 #if !defined(YUV_DISABLE_ASM) && defined(_M_IX86)
67 #define HAS_HALFROW_SSE2
68 __declspec(naked) __declspec(align(16))
HalfRow_SSE2(const uint8 * src_uv,int src_uv_stride,uint8 * dst_uv,int pix)69 static void HalfRow_SSE2(const uint8* src_uv, int src_uv_stride,
70 uint8* dst_uv, int pix) {
71 __asm {
72 push edi
73 mov eax, [esp + 4 + 4] // src_uv
74 mov edx, [esp + 4 + 8] // src_uv_stride
75 mov edi, [esp + 4 + 12] // dst_v
76 mov ecx, [esp + 4 + 16] // pix
77 sub edi, eax
78
79 align 16
80 convertloop:
81 movdqa xmm0, [eax]
82 pavgb xmm0, [eax + edx]
83 sub ecx, 16
84 movdqa [eax + edi], xmm0
85 lea eax, [eax + 16]
86 jg convertloop
87 pop edi
88 ret
89 }
90 }
91
92 #elif !defined(YUV_DISABLE_ASM) && (defined(__x86_64__) || defined(__i386__))
93 #define HAS_HALFROW_SSE2
HalfRow_SSE2(const uint8 * src_uv,int src_uv_stride,uint8 * dst_uv,int pix)94 static void HalfRow_SSE2(const uint8* src_uv, int src_uv_stride,
95 uint8* dst_uv, int pix) {
96 asm volatile (
97 "sub %0,%1 \n"
98 ".p2align 4 \n"
99 "1: \n"
100 "movdqa (%0),%%xmm0 \n"
101 "pavgb (%0,%3),%%xmm0 \n"
102 "sub $0x10,%2 \n"
103 "movdqa %%xmm0,(%0,%1) \n"
104 "lea 0x10(%0),%0 \n"
105 "jg 1b \n"
106 : "+r"(src_uv), // %0
107 "+r"(dst_uv), // %1
108 "+r"(pix) // %2
109 : "r"(static_cast<intptr_t>(src_uv_stride)) // %3
110 : "memory", "cc"
111 #if defined(__SSE2__)
112 , "xmm0"
113 #endif
114 );
115 }
116 #endif
117
HalfRow_C(const uint8 * src_uv,int src_uv_stride,uint8 * dst_uv,int pix)118 static void HalfRow_C(const uint8* src_uv, int src_uv_stride,
119 uint8* dst_uv, int pix) {
120 for (int x = 0; x < pix; ++x) {
121 dst_uv[x] = (src_uv[x] + src_uv[src_uv_stride + x] + 1) >> 1;
122 }
123 }
124
125 LIBYUV_API
I422ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)126 int I422ToI420(const uint8* src_y, int src_stride_y,
127 const uint8* src_u, int src_stride_u,
128 const uint8* src_v, int src_stride_v,
129 uint8* dst_y, int dst_stride_y,
130 uint8* dst_u, int dst_stride_u,
131 uint8* dst_v, int dst_stride_v,
132 int width, int height) {
133 if (!src_y || !src_u || !src_v ||
134 !dst_y || !dst_u || !dst_v ||
135 width <= 0 || height == 0) {
136 return -1;
137 }
138 // Negative height means invert the image.
139 if (height < 0) {
140 height = -height;
141 src_y = src_y + (height - 1) * src_stride_y;
142 src_u = src_u + (height - 1) * src_stride_u;
143 src_v = src_v + (height - 1) * src_stride_v;
144 src_stride_y = -src_stride_y;
145 src_stride_u = -src_stride_u;
146 src_stride_v = -src_stride_v;
147 }
148 int halfwidth = (width + 1) >> 1;
149 void (*HalfRow)(const uint8* src_uv, int src_uv_stride,
150 uint8* dst_uv, int pix) = HalfRow_C;
151 #if defined(HAS_HALFROW_SSE2)
152 if (TestCpuFlag(kCpuHasSSE2) &&
153 IS_ALIGNED(halfwidth, 16) &&
154 IS_ALIGNED(src_u, 16) && IS_ALIGNED(src_stride_u, 16) &&
155 IS_ALIGNED(src_v, 16) && IS_ALIGNED(src_stride_v, 16) &&
156 IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
157 IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
158 HalfRow = HalfRow_SSE2;
159 }
160 #endif
161
162 // Copy Y plane
163 if (dst_y) {
164 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
165 }
166
167 // SubSample U plane.
168 int y;
169 for (y = 0; y < height - 1; y += 2) {
170 HalfRow(src_u, src_stride_u, dst_u, halfwidth);
171 src_u += src_stride_u * 2;
172 dst_u += dst_stride_u;
173 }
174 if (height & 1) {
175 HalfRow(src_u, 0, dst_u, halfwidth);
176 }
177
178 // SubSample V plane.
179 for (y = 0; y < height - 1; y += 2) {
180 HalfRow(src_v, src_stride_v, dst_v, halfwidth);
181 src_v += src_stride_v * 2;
182 dst_v += dst_stride_v;
183 }
184 if (height & 1) {
185 HalfRow(src_v, 0, dst_v, halfwidth);
186 }
187 return 0;
188 }
189
190 // Blends 32x2 pixels to 16x1
191 // source in scale.cc
192 #if !defined(YUV_DISABLE_ASM) && (defined(__ARM_NEON__) || defined(LIBYUV_NEON))
193 #define HAS_SCALEROWDOWN2_NEON
194 void ScaleRowDown2Int_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
195 uint8* dst, int dst_width);
196 #elif !defined(YUV_DISABLE_ASM) && \
197 (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
198
199 void ScaleRowDown2Int_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
200 uint8* dst_ptr, int dst_width);
201 #endif
202 void ScaleRowDown2Int_C(const uint8* src_ptr, ptrdiff_t src_stride,
203 uint8* dst_ptr, int dst_width);
204
205 LIBYUV_API
I444ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)206 int I444ToI420(const uint8* src_y, int src_stride_y,
207 const uint8* src_u, int src_stride_u,
208 const uint8* src_v, int src_stride_v,
209 uint8* dst_y, int dst_stride_y,
210 uint8* dst_u, int dst_stride_u,
211 uint8* dst_v, int dst_stride_v,
212 int width, int height) {
213 if (!src_y || !src_u || !src_v ||
214 !dst_y || !dst_u || !dst_v ||
215 width <= 0 || height == 0) {
216 return -1;
217 }
218 // Negative height means invert the image.
219 if (height < 0) {
220 height = -height;
221 src_y = src_y + (height - 1) * src_stride_y;
222 src_u = src_u + (height - 1) * src_stride_u;
223 src_v = src_v + (height - 1) * src_stride_v;
224 src_stride_y = -src_stride_y;
225 src_stride_u = -src_stride_u;
226 src_stride_v = -src_stride_v;
227 }
228 int halfwidth = (width + 1) >> 1;
229 void (*ScaleRowDown2)(const uint8* src_ptr, ptrdiff_t src_stride,
230 uint8* dst_ptr, int dst_width) = ScaleRowDown2Int_C;
231 #if defined(HAS_SCALEROWDOWN2_NEON)
232 if (TestCpuFlag(kCpuHasNEON) &&
233 IS_ALIGNED(halfwidth, 16)) {
234 ScaleRowDown2 = ScaleRowDown2Int_NEON;
235 }
236 #elif defined(HAS_SCALEROWDOWN2_SSE2)
237 if (TestCpuFlag(kCpuHasSSE2) &&
238 IS_ALIGNED(halfwidth, 16) &&
239 IS_ALIGNED(src_u, 16) && IS_ALIGNED(src_stride_u, 16) &&
240 IS_ALIGNED(src_v, 16) && IS_ALIGNED(src_stride_v, 16) &&
241 IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
242 IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
243 ScaleRowDown2 = ScaleRowDown2Int_SSE2;
244 }
245 #endif
246
247 // Copy Y plane
248 if (dst_y) {
249 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
250 }
251
252 // SubSample U plane.
253 int y;
254 for (y = 0; y < height - 1; y += 2) {
255 ScaleRowDown2(src_u, src_stride_u, dst_u, halfwidth);
256 src_u += src_stride_u * 2;
257 dst_u += dst_stride_u;
258 }
259 if (height & 1) {
260 ScaleRowDown2(src_u, 0, dst_u, halfwidth);
261 }
262
263 // SubSample V plane.
264 for (y = 0; y < height - 1; y += 2) {
265 ScaleRowDown2(src_v, src_stride_v, dst_v, halfwidth);
266 src_v += src_stride_v * 2;
267 dst_v += dst_stride_v;
268 }
269 if (height & 1) {
270 ScaleRowDown2(src_v, 0, dst_v, halfwidth);
271 }
272 return 0;
273 }
274
275 // use Bilinear for upsampling chroma
276 void ScalePlaneBilinear(int src_width, int src_height,
277 int dst_width, int dst_height,
278 int src_stride, int dst_stride,
279 const uint8* src_ptr, uint8* dst_ptr);
280
281 // 411 chroma is 1/4 width, 1x height
282 // 420 chroma is 1/2 width, 1/2 height
283 LIBYUV_API
I411ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)284 int I411ToI420(const uint8* src_y, int src_stride_y,
285 const uint8* src_u, int src_stride_u,
286 const uint8* src_v, int src_stride_v,
287 uint8* dst_y, int dst_stride_y,
288 uint8* dst_u, int dst_stride_u,
289 uint8* dst_v, int dst_stride_v,
290 int width, int height) {
291 if (!src_y || !src_u || !src_v ||
292 !dst_y || !dst_u || !dst_v ||
293 width <= 0 || height == 0) {
294 return -1;
295 }
296 // Negative height means invert the image.
297 if (height < 0) {
298 height = -height;
299 dst_y = dst_y + (height - 1) * dst_stride_y;
300 dst_u = dst_u + (height - 1) * dst_stride_u;
301 dst_v = dst_v + (height - 1) * dst_stride_v;
302 dst_stride_y = -dst_stride_y;
303 dst_stride_u = -dst_stride_u;
304 dst_stride_v = -dst_stride_v;
305 }
306
307 // Copy Y plane
308 if (dst_y) {
309 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
310 }
311
312 int halfwidth = (width + 1) >> 1;
313 int halfheight = (height + 1) >> 1;
314 int quarterwidth = (width + 3) >> 2;
315
316 // Resample U plane.
317 ScalePlaneBilinear(quarterwidth, height, // from 1/4 width, 1x height
318 halfwidth, halfheight, // to 1/2 width, 1/2 height
319 src_stride_u,
320 dst_stride_u,
321 src_u, dst_u);
322
323 // Resample V plane.
324 ScalePlaneBilinear(quarterwidth, height, // from 1/4 width, 1x height
325 halfwidth, halfheight, // to 1/2 width, 1/2 height
326 src_stride_v,
327 dst_stride_v,
328 src_v, dst_v);
329 return 0;
330 }
331
332 // I400 is greyscale typically used in MJPG
333 LIBYUV_API
I400ToI420(const uint8 * src_y,int src_stride_y,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)334 int I400ToI420(const uint8* src_y, int src_stride_y,
335 uint8* dst_y, int dst_stride_y,
336 uint8* dst_u, int dst_stride_u,
337 uint8* dst_v, int dst_stride_v,
338 int width, int height) {
339 if (!src_y || !dst_y || !dst_u || !dst_v ||
340 width <= 0 || height == 0) {
341 return -1;
342 }
343 // Negative height means invert the image.
344 if (height < 0) {
345 height = -height;
346 src_y = src_y + (height - 1) * src_stride_y;
347 src_stride_y = -src_stride_y;
348 }
349 int halfwidth = (width + 1) >> 1;
350 int halfheight = (height + 1) >> 1;
351 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
352 SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
353 SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
354 return 0;
355 }
356
CopyPlane2(const uint8 * src,int src_stride_0,int src_stride_1,uint8 * dst,int dst_stride_frame,int width,int height)357 static void CopyPlane2(const uint8* src, int src_stride_0, int src_stride_1,
358 uint8* dst, int dst_stride_frame,
359 int width, int height) {
360 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
361 #if defined(HAS_COPYROW_NEON)
362 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 64)) {
363 CopyRow = CopyRow_NEON;
364 }
365 #elif defined(HAS_COPYROW_X86)
366 if (IS_ALIGNED(width, 4)) {
367 CopyRow = CopyRow_X86;
368 #if defined(HAS_COPYROW_SSE2)
369 if (TestCpuFlag(kCpuHasSSE2) &&
370 IS_ALIGNED(width, 32) && IS_ALIGNED(src, 16) &&
371 IS_ALIGNED(src_stride_0, 16) && IS_ALIGNED(src_stride_1, 16) &&
372 IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride_frame, 16)) {
373 CopyRow = CopyRow_SSE2;
374 }
375 #endif
376 }
377 #endif
378
379 // Copy plane
380 for (int y = 0; y < height - 1; y += 2) {
381 CopyRow(src, dst, width);
382 CopyRow(src + src_stride_0, dst + dst_stride_frame, width);
383 src += src_stride_0 + src_stride_1;
384 dst += dst_stride_frame * 2;
385 }
386 if (height & 1) {
387 CopyRow(src, dst, width);
388 }
389 }
390
391 // Support converting from FOURCC_M420
392 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
393 // easy conversion to I420.
394 // M420 format description:
395 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
396 // Chroma is half width / half height. (420)
397 // src_stride_m420 is row planar. Normally this will be the width in pixels.
398 // The UV plane is half width, but 2 values, so src_stride_m420 applies to
399 // this as well as the two Y planes.
X420ToI420(const uint8 * src_y,int src_stride_y0,int src_stride_y1,const uint8 * src_uv,int src_stride_uv,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)400 static int X420ToI420(const uint8* src_y,
401 int src_stride_y0, int src_stride_y1,
402 const uint8* src_uv, int src_stride_uv,
403 uint8* dst_y, int dst_stride_y,
404 uint8* dst_u, int dst_stride_u,
405 uint8* dst_v, int dst_stride_v,
406 int width, int height) {
407 if (!src_y || !src_uv ||
408 !dst_y || !dst_u || !dst_v ||
409 width <= 0 || height == 0) {
410 return -1;
411 }
412 // Negative height means invert the image.
413 if (height < 0) {
414 height = -height;
415 int halfheight = (height + 1) >> 1;
416 dst_y = dst_y + (height - 1) * dst_stride_y;
417 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
418 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
419 dst_stride_y = -dst_stride_y;
420 dst_stride_u = -dst_stride_u;
421 dst_stride_v = -dst_stride_v;
422 }
423
424 int halfwidth = (width + 1) >> 1;
425 void (*SplitUV)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) =
426 SplitUV_C;
427 #if defined(HAS_SPLITUV_NEON)
428 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(halfwidth, 16)) {
429 SplitUV = SplitUV_NEON;
430 }
431 #elif defined(HAS_SPLITUV_SSE2)
432 if (TestCpuFlag(kCpuHasSSE2) &&
433 IS_ALIGNED(halfwidth, 16) &&
434 IS_ALIGNED(src_uv, 16) && IS_ALIGNED(src_stride_uv, 16) &&
435 IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
436 IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
437 SplitUV = SplitUV_SSE2;
438 }
439 #endif
440
441 if (dst_y) {
442 CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
443 width, height);
444 }
445
446 int halfheight = (height + 1) >> 1;
447 for (int y = 0; y < halfheight; ++y) {
448 // Copy a row of UV.
449 SplitUV(src_uv, dst_u, dst_v, halfwidth);
450 dst_u += dst_stride_u;
451 dst_v += dst_stride_v;
452 src_uv += src_stride_uv;
453 }
454 return 0;
455 }
456
457 // Convert NV12 to I420.
458 LIBYUV_API
NV12ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_uv,int src_stride_uv,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)459 int NV12ToI420(const uint8* src_y, int src_stride_y,
460 const uint8* src_uv, int src_stride_uv,
461 uint8* dst_y, int dst_stride_y,
462 uint8* dst_u, int dst_stride_u,
463 uint8* dst_v, int dst_stride_v,
464 int width, int height) {
465 return X420ToI420(src_y, src_stride_y, src_stride_y,
466 src_uv, src_stride_uv,
467 dst_y, dst_stride_y,
468 dst_u, dst_stride_u,
469 dst_v, dst_stride_v,
470 width, height);
471 }
472
473 // Convert M420 to I420.
474 LIBYUV_API
M420ToI420(const uint8 * src_m420,int src_stride_m420,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)475 int M420ToI420(const uint8* src_m420, int src_stride_m420,
476 uint8* dst_y, int dst_stride_y,
477 uint8* dst_u, int dst_stride_u,
478 uint8* dst_v, int dst_stride_v,
479 int width, int height) {
480 return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
481 src_m420 + src_stride_m420 * 2, src_stride_m420 * 3,
482 dst_y, dst_stride_y,
483 dst_u, dst_stride_u,
484 dst_v, dst_stride_v,
485 width, height);
486 }
487
488 // Convert Q420 to I420.
489 // Format is rows of YY/YUYV
490 LIBYUV_API
Q420ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_yuy2,int src_stride_yuy2,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)491 int Q420ToI420(const uint8* src_y, int src_stride_y,
492 const uint8* src_yuy2, int src_stride_yuy2,
493 uint8* dst_y, int dst_stride_y,
494 uint8* dst_u, int dst_stride_u,
495 uint8* dst_v, int dst_stride_v,
496 int width, int height) {
497 if (!src_y || !src_yuy2 ||
498 !dst_y || !dst_u || !dst_v ||
499 width <= 0 || height == 0) {
500 return -1;
501 }
502 // Negative height means invert the image.
503 if (height < 0) {
504 height = -height;
505 int halfheight = (height + 1) >> 1;
506 dst_y = dst_y + (height - 1) * dst_stride_y;
507 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
508 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
509 dst_stride_y = -dst_stride_y;
510 dst_stride_u = -dst_stride_u;
511 dst_stride_v = -dst_stride_v;
512 }
513 // CopyRow for rows of just Y in Q420 copied to Y plane of I420.
514 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
515 #if defined(HAS_COPYROW_NEON)
516 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 64)) {
517 CopyRow = CopyRow_NEON;
518 }
519 #endif
520 #if defined(HAS_COPYROW_X86)
521 if (IS_ALIGNED(width, 4)) {
522 CopyRow = CopyRow_X86;
523 }
524 #endif
525 #if defined(HAS_COPYROW_SSE2)
526 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
527 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
528 IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
529 CopyRow = CopyRow_SSE2;
530 }
531 #endif
532
533 void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
534 int pix) = YUY2ToUV422Row_C;
535 void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
536 YUY2ToYRow_C;
537 #if defined(HAS_YUY2TOYROW_SSE2)
538 if (TestCpuFlag(kCpuHasSSE2)) {
539 if (width > 16) {
540 YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
541 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
542 }
543 if (IS_ALIGNED(width, 16)) {
544 YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
545 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
546 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
547 YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
548 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
549 YUY2ToYRow = YUY2ToYRow_SSE2;
550 }
551 }
552 }
553 }
554 #elif defined(HAS_YUY2TOYROW_NEON)
555 if (TestCpuFlag(kCpuHasNEON)) {
556 if (width > 8) {
557 YUY2ToYRow = YUY2ToYRow_Any_NEON;
558 if (width > 16) {
559 YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
560 }
561 }
562 if (IS_ALIGNED(width, 16)) {
563 YUY2ToYRow = YUY2ToYRow_NEON;
564 YUY2ToUV422Row = YUY2ToUV422Row_NEON;
565 }
566 }
567 #endif
568
569 for (int y = 0; y < height - 1; y += 2) {
570 CopyRow(src_y, dst_y, width);
571 src_y += src_stride_y;
572 dst_y += dst_stride_y;
573
574 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
575 YUY2ToYRow(src_yuy2, dst_y, width);
576 src_yuy2 += src_stride_yuy2;
577 dst_y += dst_stride_y;
578 dst_u += dst_stride_u;
579 dst_v += dst_stride_v;
580 }
581 if (height & 1) {
582 CopyRow(src_y, dst_y, width);
583 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
584 }
585 return 0;
586 }
587
588 // Test if over reading on source is safe.
589 // TODO(fbarchard): Find more efficient solution to safely do odd sizes.
590 // Macros to control read policy, from slowest to fastest:
591 // READSAFE_NEVER - disables read ahead on systems with strict memory reads
592 // READSAFE_ODDHEIGHT - last row of odd height done with C.
593 // This policy assumes that the caller handles the last row of an odd height
594 // image using C.
595 // READSAFE_PAGE - enable read ahead within same page.
596 // A page is 4096 bytes. When reading ahead, if the last pixel is near the
597 // end the page, and a read spans the page into the next page, a memory
598 // exception can occur if that page has not been allocated, or is a guard
599 // page. This setting ensures the overread is within the same page.
600 // READSAFE_ALWAYS - enables read ahead on systems without memory exceptions
601 // or where buffers are padded by 64 bytes.
602
603 #if defined(HAS_RGB24TOARGBROW_SSSE3) || \
604 defined(HAS_RGB24TOARGBROW_SSSE3) || \
605 defined(HAS_RAWTOARGBROW_SSSE3) || \
606 defined(HAS_RGB565TOARGBROW_SSE2) || \
607 defined(HAS_ARGB1555TOARGBROW_SSE2) || \
608 defined(HAS_ARGB4444TOARGBROW_SSE2)
609
610 #define READSAFE_ODDHEIGHT
611
TestReadSafe(const uint8 * src_yuy2,int src_stride_yuy2,int width,int height,int bpp,int overread)612 static bool TestReadSafe(const uint8* src_yuy2, int src_stride_yuy2,
613 int width, int height, int bpp, int overread) {
614 if (width > kMaxStride) {
615 return false;
616 }
617 #if defined(READSAFE_ALWAYS)
618 return true;
619 #elif defined(READSAFE_NEVER)
620 return false;
621 #elif defined(READSAFE_ODDHEIGHT)
622 if (!(width & 15) ||
623 (src_stride_yuy2 >= 0 && (height & 1) && width * bpp >= overread)) {
624 return true;
625 }
626 return false;
627 #elif defined(READSAFE_PAGE)
628 if (src_stride_yuy2 >= 0) {
629 src_yuy2 += (height - 1) * src_stride_yuy2;
630 }
631 uintptr_t last_adr = (uintptr_t)(src_yuy2) + width * bpp - 1;
632 uintptr_t last_read_adr = last_adr + overread - 1;
633 if (((last_adr ^ last_read_adr) & ~4095) == 0) {
634 return true;
635 }
636 return false;
637 #endif
638 }
639 #endif
640
641 // Convert YUY2 to I420.
642 LIBYUV_API
YUY2ToI420(const uint8 * src_yuy2,int src_stride_yuy2,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)643 int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
644 uint8* dst_y, int dst_stride_y,
645 uint8* dst_u, int dst_stride_u,
646 uint8* dst_v, int dst_stride_v,
647 int width, int height) {
648 // Negative height means invert the image.
649 if (height < 0) {
650 height = -height;
651 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
652 src_stride_yuy2 = -src_stride_yuy2;
653 }
654 void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2,
655 uint8* dst_u, uint8* dst_v, int pix);
656 void (*YUY2ToYRow)(const uint8* src_yuy2,
657 uint8* dst_y, int pix);
658 YUY2ToYRow = YUY2ToYRow_C;
659 YUY2ToUVRow = YUY2ToUVRow_C;
660 #if defined(HAS_YUY2TOYROW_SSE2)
661 if (TestCpuFlag(kCpuHasSSE2)) {
662 if (width > 16) {
663 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
664 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
665 }
666 if (IS_ALIGNED(width, 16)) {
667 YUY2ToUVRow = YUY2ToUVRow_Unaligned_SSE2;
668 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
669 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
670 YUY2ToUVRow = YUY2ToUVRow_SSE2;
671 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
672 YUY2ToYRow = YUY2ToYRow_SSE2;
673 }
674 }
675 }
676 }
677 #elif defined(HAS_YUY2TOYROW_NEON)
678 if (TestCpuFlag(kCpuHasNEON)) {
679 if (width > 8) {
680 YUY2ToYRow = YUY2ToYRow_Any_NEON;
681 if (width > 16) {
682 YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
683 }
684 }
685 if (IS_ALIGNED(width, 16)) {
686 YUY2ToYRow = YUY2ToYRow_NEON;
687 YUY2ToUVRow = YUY2ToUVRow_NEON;
688 }
689 }
690 #endif
691
692 for (int y = 0; y < height - 1; y += 2) {
693 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
694 YUY2ToYRow(src_yuy2, dst_y, width);
695 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
696 src_yuy2 += src_stride_yuy2 * 2;
697 dst_y += dst_stride_y * 2;
698 dst_u += dst_stride_u;
699 dst_v += dst_stride_v;
700 }
701 if (height & 1) {
702 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
703 YUY2ToYRow(src_yuy2, dst_y, width);
704 }
705 return 0;
706 }
707
708 // Convert UYVY to I420.
709 LIBYUV_API
UYVYToI420(const uint8 * src_uyvy,int src_stride_uyvy,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)710 int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
711 uint8* dst_y, int dst_stride_y,
712 uint8* dst_u, int dst_stride_u,
713 uint8* dst_v, int dst_stride_v,
714 int width, int height) {
715 // Negative height means invert the image.
716 if (height < 0) {
717 height = -height;
718 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
719 src_stride_uyvy = -src_stride_uyvy;
720 }
721 void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
722 uint8* dst_u, uint8* dst_v, int pix);
723 void (*UYVYToYRow)(const uint8* src_uyvy,
724 uint8* dst_y, int pix);
725 UYVYToYRow = UYVYToYRow_C;
726 UYVYToUVRow = UYVYToUVRow_C;
727 #if defined(HAS_UYVYTOYROW_SSE2)
728 if (TestCpuFlag(kCpuHasSSE2)) {
729 if (width > 16) {
730 UYVYToUVRow = UYVYToUVRow_Any_SSE2;
731 UYVYToYRow = UYVYToYRow_Any_SSE2;
732 }
733 if (IS_ALIGNED(width, 16)) {
734 UYVYToUVRow = UYVYToUVRow_Unaligned_SSE2;
735 UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
736 if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
737 UYVYToUVRow = UYVYToUVRow_SSE2;
738 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
739 UYVYToYRow = UYVYToYRow_SSE2;
740 }
741 }
742 }
743 }
744 #elif defined(HAS_UYVYTOYROW_NEON)
745 if (TestCpuFlag(kCpuHasNEON)) {
746 if (width > 8) {
747 UYVYToYRow = UYVYToYRow_Any_NEON;
748 if (width > 16) {
749 UYVYToUVRow = UYVYToUVRow_Any_NEON;
750 }
751 }
752 if (IS_ALIGNED(width, 16)) {
753 UYVYToYRow = UYVYToYRow_NEON;
754 UYVYToUVRow = UYVYToUVRow_NEON;
755 }
756 }
757 #endif
758
759 for (int y = 0; y < height - 1; y += 2) {
760 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
761 UYVYToYRow(src_uyvy, dst_y, width);
762 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
763 src_uyvy += src_stride_uyvy * 2;
764 dst_y += dst_stride_y * 2;
765 dst_u += dst_stride_u;
766 dst_v += dst_stride_v;
767 }
768 if (height & 1) {
769 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
770 UYVYToYRow(src_uyvy, dst_y, width);
771 }
772 return 0;
773 }
774
775 // Visual C x86 or GCC little endian.
776 #if defined(__x86_64__) || defined(_M_X64) || \
777 defined(__i386__) || defined(_M_IX86) || \
778 defined(__arm__) || defined(_M_ARM) || \
779 (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
780 #define LIBYUV_LITTLE_ENDIAN
781 #endif
782
783 #ifdef LIBYUV_LITTLE_ENDIAN
784 #define READWORD(p) (*reinterpret_cast<const uint32*>(p))
785 #else
READWORD(const uint8 * p)786 static inline uint32 READWORD(const uint8* p) {
787 return static_cast<uint32>(p[0]) |
788 (static_cast<uint32>(p[1]) << 8) |
789 (static_cast<uint32>(p[2]) << 16) |
790 (static_cast<uint32>(p[3]) << 24);
791 }
792 #endif
793
794 // Must be multiple of 6 pixels. Will over convert to handle remainder.
795 // https://developer.apple.com/quicktime/icefloe/dispatch019.html#v210
V210ToUYVYRow_C(const uint8 * src_v210,uint8 * dst_uyvy,int width)796 static void V210ToUYVYRow_C(const uint8* src_v210, uint8* dst_uyvy, int width) {
797 for (int x = 0; x < width; x += 6) {
798 uint32 w = READWORD(src_v210 + 0);
799 dst_uyvy[0] = (w >> 2) & 0xff;
800 dst_uyvy[1] = (w >> 12) & 0xff;
801 dst_uyvy[2] = (w >> 22) & 0xff;
802
803 w = READWORD(src_v210 + 4);
804 dst_uyvy[3] = (w >> 2) & 0xff;
805 dst_uyvy[4] = (w >> 12) & 0xff;
806 dst_uyvy[5] = (w >> 22) & 0xff;
807
808 w = READWORD(src_v210 + 8);
809 dst_uyvy[6] = (w >> 2) & 0xff;
810 dst_uyvy[7] = (w >> 12) & 0xff;
811 dst_uyvy[8] = (w >> 22) & 0xff;
812
813 w = READWORD(src_v210 + 12);
814 dst_uyvy[9] = (w >> 2) & 0xff;
815 dst_uyvy[10] = (w >> 12) & 0xff;
816 dst_uyvy[11] = (w >> 22) & 0xff;
817
818 src_v210 += 16;
819 dst_uyvy += 12;
820 }
821 }
822
823 // Convert V210 to I420.
824 // V210 is 10 bit version of UYVY. 16 bytes to store 6 pixels.
825 // With is multiple of 48.
826 LIBYUV_API
V210ToI420(const uint8 * src_v210,int src_stride_v210,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)827 int V210ToI420(const uint8* src_v210, int src_stride_v210,
828 uint8* dst_y, int dst_stride_y,
829 uint8* dst_u, int dst_stride_u,
830 uint8* dst_v, int dst_stride_v,
831 int width, int height) {
832 if (width * 2 * 2 > kMaxStride) { // 2 rows of UYVY are required.
833 return -1;
834 } else if (!src_v210 || !dst_y || !dst_u || !dst_v ||
835 width <= 0 || height == 0) {
836 return -1;
837 }
838 // Negative height means invert the image.
839 if (height < 0) {
840 height = -height;
841 src_v210 = src_v210 + (height - 1) * src_stride_v210;
842 src_stride_v210 = -src_stride_v210;
843 }
844 SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
845 void (*V210ToUYVYRow)(const uint8* src_v210, uint8* dst_uyvy, int pix);
846 V210ToUYVYRow = V210ToUYVYRow_C;
847
848 void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
849 uint8* dst_u, uint8* dst_v, int pix);
850 void (*UYVYToYRow)(const uint8* src_uyvy,
851 uint8* dst_y, int pix);
852 UYVYToYRow = UYVYToYRow_C;
853 UYVYToUVRow = UYVYToUVRow_C;
854 #if defined(HAS_UYVYTOYROW_SSE2)
855 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16)) {
856 UYVYToUVRow = UYVYToUVRow_SSE2;
857 UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
858 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
859 UYVYToYRow = UYVYToYRow_SSE2;
860 }
861 }
862 #elif defined(HAS_UYVYTOYROW_NEON)
863 if (TestCpuFlag(kCpuHasNEON)) {
864 if (width > 8) {
865 UYVYToYRow = UYVYToYRow_Any_NEON;
866 if (width > 16) {
867 UYVYToUVRow = UYVYToUVRow_Any_NEON;
868 }
869 }
870 if (IS_ALIGNED(width, 16)) {
871 UYVYToYRow = UYVYToYRow_NEON;
872 UYVYToUVRow = UYVYToUVRow_NEON;
873 }
874 }
875 #endif
876
877 #if defined(HAS_UYVYTOYROW_SSE2)
878 if (TestCpuFlag(kCpuHasSSE2)) {
879 if (width > 16) {
880 UYVYToUVRow = UYVYToUVRow_Any_SSE2;
881 UYVYToYRow = UYVYToYRow_Any_SSE2;
882 }
883 if (IS_ALIGNED(width, 16)) {
884 UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
885 UYVYToUVRow = UYVYToUVRow_SSE2;
886 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
887 UYVYToYRow = UYVYToYRow_SSE2;
888 }
889 }
890 }
891 #elif defined(HAS_UYVYTOYROW_NEON)
892 if (TestCpuFlag(kCpuHasNEON)) {
893 if (width > 8) {
894 UYVYToYRow = UYVYToYRow_Any_NEON;
895 if (width > 16) {
896 UYVYToUVRow = UYVYToUVRow_Any_NEON;
897 }
898 }
899 if (IS_ALIGNED(width, 16)) {
900 UYVYToYRow = UYVYToYRow_NEON;
901 UYVYToUVRow = UYVYToUVRow_NEON;
902 }
903 }
904 #endif
905
906 for (int y = 0; y < height - 1; y += 2) {
907 V210ToUYVYRow(src_v210, row, width);
908 V210ToUYVYRow(src_v210 + src_stride_v210, row + kMaxStride, width);
909 UYVYToUVRow(row, kMaxStride, dst_u, dst_v, width);
910 UYVYToYRow(row, dst_y, width);
911 UYVYToYRow(row + kMaxStride, dst_y + dst_stride_y, width);
912 src_v210 += src_stride_v210 * 2;
913 dst_y += dst_stride_y * 2;
914 dst_u += dst_stride_u;
915 dst_v += dst_stride_v;
916 }
917 if (height & 1) {
918 V210ToUYVYRow(src_v210, row, width);
919 UYVYToUVRow(row, 0, dst_u, dst_v, width);
920 UYVYToYRow(row, dst_y, width);
921 }
922 return 0;
923 }
924
925 LIBYUV_API
ARGBToI420(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)926 int ARGBToI420(const uint8* src_argb, int src_stride_argb,
927 uint8* dst_y, int dst_stride_y,
928 uint8* dst_u, int dst_stride_u,
929 uint8* dst_v, int dst_stride_v,
930 int width, int height) {
931 if (!src_argb ||
932 !dst_y || !dst_u || !dst_v ||
933 width <= 0 || height == 0) {
934 return -1;
935 }
936 // Negative height means invert the image.
937 if (height < 0) {
938 height = -height;
939 src_argb = src_argb + (height - 1) * src_stride_argb;
940 src_stride_argb = -src_stride_argb;
941 }
942 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix);
943 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
944 uint8* dst_u, uint8* dst_v, int width);
945
946 ARGBToYRow = ARGBToYRow_C;
947 ARGBToUVRow = ARGBToUVRow_C;
948 #if defined(HAS_ARGBTOYROW_SSSE3)
949 if (TestCpuFlag(kCpuHasSSSE3)) {
950 if (width > 16) {
951 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
952 ARGBToYRow = ARGBToYRow_Any_SSSE3;
953 }
954 if (IS_ALIGNED(width, 16)) {
955 ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3;
956 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
957 if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
958 ARGBToUVRow = ARGBToUVRow_SSSE3;
959 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
960 ARGBToYRow = ARGBToYRow_SSSE3;
961 }
962 }
963 }
964 }
965 #endif
966
967 for (int y = 0; y < height - 1; y += 2) {
968 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
969 ARGBToYRow(src_argb, dst_y, width);
970 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
971 src_argb += src_stride_argb * 2;
972 dst_y += dst_stride_y * 2;
973 dst_u += dst_stride_u;
974 dst_v += dst_stride_v;
975 }
976 if (height & 1) {
977 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
978 ARGBToYRow(src_argb, dst_y, width);
979 }
980 return 0;
981 }
982
983 LIBYUV_API
BGRAToI420(const uint8 * src_bgra,int src_stride_bgra,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)984 int BGRAToI420(const uint8* src_bgra, int src_stride_bgra,
985 uint8* dst_y, int dst_stride_y,
986 uint8* dst_u, int dst_stride_u,
987 uint8* dst_v, int dst_stride_v,
988 int width, int height) {
989 if (!src_bgra ||
990 !dst_y || !dst_u || !dst_v ||
991 width <= 0 || height == 0) {
992 return -1;
993 }
994 // Negative height means invert the image.
995 if (height < 0) {
996 height = -height;
997 src_bgra = src_bgra + (height - 1) * src_stride_bgra;
998 src_stride_bgra = -src_stride_bgra;
999 }
1000 void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix);
1001 void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra,
1002 uint8* dst_u, uint8* dst_v, int width);
1003
1004 BGRAToYRow = BGRAToYRow_C;
1005 BGRAToUVRow = BGRAToUVRow_C;
1006 #if defined(HAS_BGRATOYROW_SSSE3)
1007 if (TestCpuFlag(kCpuHasSSSE3)) {
1008 if (width > 16) {
1009 BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
1010 BGRAToYRow = BGRAToYRow_Any_SSSE3;
1011 }
1012 if (IS_ALIGNED(width, 16)) {
1013 BGRAToUVRow = BGRAToUVRow_Unaligned_SSSE3;
1014 BGRAToYRow = BGRAToYRow_Unaligned_SSSE3;
1015 if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16)) {
1016 BGRAToUVRow = BGRAToUVRow_SSSE3;
1017 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1018 BGRAToYRow = BGRAToYRow_SSSE3;
1019 }
1020 }
1021 }
1022 }
1023 #endif
1024
1025 for (int y = 0; y < height - 1; y += 2) {
1026 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
1027 BGRAToYRow(src_bgra, dst_y, width);
1028 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
1029 src_bgra += src_stride_bgra * 2;
1030 dst_y += dst_stride_y * 2;
1031 dst_u += dst_stride_u;
1032 dst_v += dst_stride_v;
1033 }
1034 if (height & 1) {
1035 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
1036 BGRAToYRow(src_bgra, dst_y, width);
1037 }
1038 return 0;
1039 }
1040
1041 LIBYUV_API
ABGRToI420(const uint8 * src_abgr,int src_stride_abgr,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1042 int ABGRToI420(const uint8* src_abgr, int src_stride_abgr,
1043 uint8* dst_y, int dst_stride_y,
1044 uint8* dst_u, int dst_stride_u,
1045 uint8* dst_v, int dst_stride_v,
1046 int width, int height) {
1047 if (!src_abgr ||
1048 !dst_y || !dst_u || !dst_v ||
1049 width <= 0 || height == 0) {
1050 return -1;
1051 }
1052 // Negative height means invert the image.
1053 if (height < 0) {
1054 height = -height;
1055 src_abgr = src_abgr + (height - 1) * src_stride_abgr;
1056 src_stride_abgr = -src_stride_abgr;
1057 }
1058 void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix);
1059 void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr,
1060 uint8* dst_u, uint8* dst_v, int width);
1061
1062 ABGRToYRow = ABGRToYRow_C;
1063 ABGRToUVRow = ABGRToUVRow_C;
1064 #if defined(HAS_ABGRTOYROW_SSSE3)
1065 if (TestCpuFlag(kCpuHasSSSE3)) {
1066 if (width > 16) {
1067 ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
1068 ABGRToYRow = ABGRToYRow_Any_SSSE3;
1069 }
1070 if (IS_ALIGNED(width, 16)) {
1071 ABGRToUVRow = ABGRToUVRow_Unaligned_SSSE3;
1072 ABGRToYRow = ABGRToYRow_Unaligned_SSSE3;
1073 if (IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16)) {
1074 ABGRToUVRow = ABGRToUVRow_SSSE3;
1075 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1076 ABGRToYRow = ABGRToYRow_SSSE3;
1077 }
1078 }
1079 }
1080 }
1081 #endif
1082
1083 for (int y = 0; y < height - 1; y += 2) {
1084 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
1085 ABGRToYRow(src_abgr, dst_y, width);
1086 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
1087 src_abgr += src_stride_abgr * 2;
1088 dst_y += dst_stride_y * 2;
1089 dst_u += dst_stride_u;
1090 dst_v += dst_stride_v;
1091 }
1092 if (height & 1) {
1093 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
1094 ABGRToYRow(src_abgr, dst_y, width);
1095 }
1096 return 0;
1097 }
1098
1099 LIBYUV_API
RGBAToI420(const uint8 * src_rgba,int src_stride_rgba,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1100 int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
1101 uint8* dst_y, int dst_stride_y,
1102 uint8* dst_u, int dst_stride_u,
1103 uint8* dst_v, int dst_stride_v,
1104 int width, int height) {
1105 if (!src_rgba ||
1106 !dst_y || !dst_u || !dst_v ||
1107 width <= 0 || height == 0) {
1108 return -1;
1109 }
1110 // Negative height means invert the image.
1111 if (height < 0) {
1112 height = -height;
1113 src_rgba = src_rgba + (height - 1) * src_stride_rgba;
1114 src_stride_rgba = -src_stride_rgba;
1115 }
1116 void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix);
1117 void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba,
1118 uint8* dst_u, uint8* dst_v, int width);
1119
1120 RGBAToYRow = RGBAToYRow_C;
1121 RGBAToUVRow = RGBAToUVRow_C;
1122 #if defined(HAS_RGBATOYROW_SSSE3)
1123 if (TestCpuFlag(kCpuHasSSSE3)) {
1124 if (width > 16) {
1125 RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
1126 RGBAToYRow = RGBAToYRow_Any_SSSE3;
1127 }
1128 if (IS_ALIGNED(width, 16)) {
1129 RGBAToUVRow = RGBAToUVRow_Unaligned_SSSE3;
1130 RGBAToYRow = RGBAToYRow_Unaligned_SSSE3;
1131 if (IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16)) {
1132 RGBAToUVRow = RGBAToUVRow_SSSE3;
1133 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1134 RGBAToYRow = RGBAToYRow_SSSE3;
1135 }
1136 }
1137 }
1138 }
1139 #endif
1140
1141 for (int y = 0; y < height - 1; y += 2) {
1142 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
1143 RGBAToYRow(src_rgba, dst_y, width);
1144 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
1145 src_rgba += src_stride_rgba * 2;
1146 dst_y += dst_stride_y * 2;
1147 dst_u += dst_stride_u;
1148 dst_v += dst_stride_v;
1149 }
1150 if (height & 1) {
1151 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
1152 RGBAToYRow(src_rgba, dst_y, width);
1153 }
1154 return 0;
1155 }
1156
1157 LIBYUV_API
RGB24ToI420(const uint8 * src_rgb24,int src_stride_rgb24,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1158 int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
1159 uint8* dst_y, int dst_stride_y,
1160 uint8* dst_u, int dst_stride_u,
1161 uint8* dst_v, int dst_stride_v,
1162 int width, int height) {
1163 if (width * 4 > kMaxStride) { // Row buffer is required.
1164 return -1;
1165 } else if (!src_rgb24 ||
1166 !dst_y || !dst_u || !dst_v ||
1167 width <= 0 || height == 0) {
1168 return -1;
1169 }
1170 // Negative height means invert the image.
1171 if (height < 0) {
1172 height = -height;
1173 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
1174 src_stride_rgb24 = -src_stride_rgb24;
1175 }
1176 SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
1177 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix);
1178
1179 RGB24ToARGBRow = RGB24ToARGBRow_C;
1180 #if defined(HAS_RGB24TOARGBROW_SSSE3)
1181 if (TestCpuFlag(kCpuHasSSSE3) &&
1182 TestReadSafe(src_rgb24, src_stride_rgb24, width, height, 3, 48)) {
1183 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1184 }
1185 #endif
1186
1187 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix);
1188 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1189 uint8* dst_u, uint8* dst_v, int width);
1190
1191 ARGBToYRow = ARGBToYRow_C;
1192 ARGBToUVRow = ARGBToUVRow_C;
1193 #if defined(HAS_ARGBTOYROW_SSSE3)
1194 if (TestCpuFlag(kCpuHasSSSE3)) {
1195 if (width > 16) {
1196 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1197 }
1198 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1199 if (IS_ALIGNED(width, 16)) {
1200 ARGBToUVRow = ARGBToUVRow_SSSE3;
1201 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1202 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1203 ARGBToYRow = ARGBToYRow_SSSE3;
1204 }
1205 }
1206 }
1207 #endif
1208
1209 for (int y = 0; y < height - 1; y += 2) {
1210 RGB24ToARGBRow(src_rgb24, row, width);
1211 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kMaxStride, width);
1212 ARGBToUVRow(row, kMaxStride, dst_u, dst_v, width);
1213 ARGBToYRow(row, dst_y, width);
1214 ARGBToYRow(row + kMaxStride, dst_y + dst_stride_y, width);
1215 src_rgb24 += src_stride_rgb24 * 2;
1216 dst_y += dst_stride_y * 2;
1217 dst_u += dst_stride_u;
1218 dst_v += dst_stride_v;
1219 }
1220 if (height & 1) {
1221 RGB24ToARGBRow_C(src_rgb24, row, width);
1222 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1223 ARGBToYRow(row, dst_y, width);
1224 }
1225 return 0;
1226 }
1227
1228 LIBYUV_API
RAWToI420(const uint8 * src_raw,int src_stride_raw,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1229 int RAWToI420(const uint8* src_raw, int src_stride_raw,
1230 uint8* dst_y, int dst_stride_y,
1231 uint8* dst_u, int dst_stride_u,
1232 uint8* dst_v, int dst_stride_v,
1233 int width, int height) {
1234 if (width * 4 > kMaxStride) { // Row buffer is required.
1235 return -1;
1236 } else if (!src_raw ||
1237 !dst_y || !dst_u || !dst_v ||
1238 width <= 0 || height == 0) {
1239 return -1;
1240 }
1241 // Negative height means invert the image.
1242 if (height < 0) {
1243 height = -height;
1244 src_raw = src_raw + (height - 1) * src_stride_raw;
1245 src_stride_raw = -src_stride_raw;
1246 }
1247 SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
1248 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix);
1249
1250 RAWToARGBRow = RAWToARGBRow_C;
1251 #if defined(HAS_RAWTOARGBROW_SSSE3)
1252 if (TestCpuFlag(kCpuHasSSSE3) &&
1253 TestReadSafe(src_raw, src_stride_raw, width, height, 3, 48)) {
1254 RAWToARGBRow = RAWToARGBRow_SSSE3;
1255 }
1256 #endif
1257
1258 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix);
1259 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1260 uint8* dst_u, uint8* dst_v, int width);
1261
1262 ARGBToYRow = ARGBToYRow_C;
1263 ARGBToUVRow = ARGBToUVRow_C;
1264 #if defined(HAS_ARGBTOYROW_SSSE3)
1265 if (TestCpuFlag(kCpuHasSSSE3)) {
1266 if (width > 16) {
1267 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1268 }
1269 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1270 if (IS_ALIGNED(width, 16)) {
1271 ARGBToUVRow = ARGBToUVRow_SSSE3;
1272 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1273 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1274 ARGBToYRow = ARGBToYRow_SSSE3;
1275 }
1276 }
1277 }
1278 #endif
1279
1280 for (int y = 0; y < height - 1; y += 2) {
1281 RAWToARGBRow(src_raw, row, width);
1282 RAWToARGBRow(src_raw + src_stride_raw, row + kMaxStride, width);
1283 ARGBToUVRow(row, kMaxStride, dst_u, dst_v, width);
1284 ARGBToYRow(row, dst_y, width);
1285 ARGBToYRow(row + kMaxStride, dst_y + dst_stride_y, width);
1286 src_raw += src_stride_raw * 2;
1287 dst_y += dst_stride_y * 2;
1288 dst_u += dst_stride_u;
1289 dst_v += dst_stride_v;
1290 }
1291 if (height & 1) {
1292 RAWToARGBRow_C(src_raw, row, width);
1293 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1294 ARGBToYRow(row, dst_y, width);
1295 }
1296 return 0;
1297 }
1298
1299 LIBYUV_API
RGB565ToI420(const uint8 * src_rgb565,int src_stride_rgb565,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1300 int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
1301 uint8* dst_y, int dst_stride_y,
1302 uint8* dst_u, int dst_stride_u,
1303 uint8* dst_v, int dst_stride_v,
1304 int width, int height) {
1305 if (width * 4 > kMaxStride) { // Row buffer is required.
1306 return -1;
1307 } else if (!src_rgb565 ||
1308 !dst_y || !dst_u || !dst_v ||
1309 width <= 0 || height == 0) {
1310 return -1;
1311 }
1312 // Negative height means invert the image.
1313 if (height < 0) {
1314 height = -height;
1315 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1316 src_stride_rgb565 = -src_stride_rgb565;
1317 }
1318 SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
1319 void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix);
1320
1321 RGB565ToARGBRow = RGB565ToARGBRow_C;
1322 #if defined(HAS_RGB565TOARGBROW_SSE2)
1323 if (TestCpuFlag(kCpuHasSSE2) &&
1324 TestReadSafe(src_rgb565, src_stride_rgb565, width, height, 2, 16)) {
1325 RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1326 }
1327 #endif
1328
1329 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix);
1330 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1331 uint8* dst_u, uint8* dst_v, int width);
1332
1333 ARGBToYRow = ARGBToYRow_C;
1334 ARGBToUVRow = ARGBToUVRow_C;
1335 #if defined(HAS_ARGBTOYROW_SSSE3)
1336 if (TestCpuFlag(kCpuHasSSSE3)) {
1337 if (width > 16) {
1338 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1339 }
1340 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1341 if (IS_ALIGNED(width, 16)) {
1342 ARGBToUVRow = ARGBToUVRow_SSSE3;
1343 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1344 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1345 ARGBToYRow = ARGBToYRow_SSSE3;
1346 }
1347 }
1348 }
1349 #endif
1350
1351 for (int y = 0; y < height - 1; y += 2) {
1352 RGB565ToARGBRow(src_rgb565, row, width);
1353 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kMaxStride, width);
1354 ARGBToUVRow(row, kMaxStride, dst_u, dst_v, width);
1355 ARGBToYRow(row, dst_y, width);
1356 ARGBToYRow(row + kMaxStride, dst_y + dst_stride_y, width);
1357 src_rgb565 += src_stride_rgb565 * 2;
1358 dst_y += dst_stride_y * 2;
1359 dst_u += dst_stride_u;
1360 dst_v += dst_stride_v;
1361 }
1362 if (height & 1) {
1363 RGB565ToARGBRow_C(src_rgb565, row, width);
1364 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1365 ARGBToYRow(row, dst_y, width);
1366 }
1367 return 0;
1368 }
1369
1370 LIBYUV_API
ARGB1555ToI420(const uint8 * src_argb1555,int src_stride_argb1555,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1371 int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
1372 uint8* dst_y, int dst_stride_y,
1373 uint8* dst_u, int dst_stride_u,
1374 uint8* dst_v, int dst_stride_v,
1375 int width, int height) {
1376 if (width * 4 > kMaxStride) { // Row buffer is required.
1377 return -1;
1378 } else if (!src_argb1555 ||
1379 !dst_y || !dst_u || !dst_v ||
1380 width <= 0 || height == 0) {
1381 return -1;
1382 }
1383 // Negative height means invert the image.
1384 if (height < 0) {
1385 height = -height;
1386 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1387 src_stride_argb1555 = -src_stride_argb1555;
1388 }
1389 SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
1390 void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix);
1391
1392 ARGB1555ToARGBRow = ARGB1555ToARGBRow_C;
1393 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1394 if (TestCpuFlag(kCpuHasSSE2) &&
1395 TestReadSafe(src_argb1555, src_stride_argb1555, width, height, 2, 16)) {
1396 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1397 }
1398 #endif
1399
1400 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix);
1401 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1402 uint8* dst_u, uint8* dst_v, int width);
1403
1404 ARGBToYRow = ARGBToYRow_C;
1405 ARGBToUVRow = ARGBToUVRow_C;
1406 #if defined(HAS_ARGBTOYROW_SSSE3)
1407 if (TestCpuFlag(kCpuHasSSSE3)) {
1408 if (width > 16) {
1409 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1410 }
1411 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1412 if (IS_ALIGNED(width, 16)) {
1413 ARGBToUVRow = ARGBToUVRow_SSSE3;
1414 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1415 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1416 ARGBToYRow = ARGBToYRow_SSSE3;
1417 }
1418 }
1419 }
1420 #endif
1421
1422 for (int y = 0; y < height - 1; y += 2) {
1423 ARGB1555ToARGBRow(src_argb1555, row, width);
1424 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555,
1425 row + kMaxStride, width);
1426 ARGBToUVRow(row, kMaxStride, dst_u, dst_v, width);
1427 ARGBToYRow(row, dst_y, width);
1428 ARGBToYRow(row + kMaxStride, dst_y + dst_stride_y, width);
1429 src_argb1555 += src_stride_argb1555 * 2;
1430 dst_y += dst_stride_y * 2;
1431 dst_u += dst_stride_u;
1432 dst_v += dst_stride_v;
1433 }
1434 if (height & 1) {
1435 ARGB1555ToARGBRow_C(src_argb1555, row, width);
1436 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1437 ARGBToYRow(row, dst_y, width);
1438 }
1439 return 0;
1440 }
1441
1442 LIBYUV_API
ARGB4444ToI420(const uint8 * src_argb4444,int src_stride_argb4444,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1443 int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
1444 uint8* dst_y, int dst_stride_y,
1445 uint8* dst_u, int dst_stride_u,
1446 uint8* dst_v, int dst_stride_v,
1447 int width, int height) {
1448 if (width * 4 > kMaxStride) { // Row buffer is required.
1449 return -1;
1450 } else if (!src_argb4444 ||
1451 !dst_y || !dst_u || !dst_v ||
1452 width <= 0 || height == 0) {
1453 return -1;
1454 }
1455 // Negative height means invert the image.
1456 if (height < 0) {
1457 height = -height;
1458 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1459 src_stride_argb4444 = -src_stride_argb4444;
1460 }
1461 SIMD_ALIGNED(uint8 row[kMaxStride * 2]);
1462 void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix);
1463
1464 ARGB4444ToARGBRow = ARGB4444ToARGBRow_C;
1465 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1466 if (TestCpuFlag(kCpuHasSSE2) &&
1467 TestReadSafe(src_argb4444, src_stride_argb4444, width, height, 2, 16)) {
1468 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1469 }
1470 #endif
1471
1472 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix);
1473 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1474 uint8* dst_u, uint8* dst_v, int width);
1475
1476 ARGBToYRow = ARGBToYRow_C;
1477 ARGBToUVRow = ARGBToUVRow_C;
1478 #if defined(HAS_ARGBTOYROW_SSSE3)
1479 if (TestCpuFlag(kCpuHasSSSE3)) {
1480 if (width > 16) {
1481 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1482 }
1483 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1484 if (IS_ALIGNED(width, 16)) {
1485 ARGBToUVRow = ARGBToUVRow_SSSE3;
1486 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1487 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1488 ARGBToYRow = ARGBToYRow_SSSE3;
1489 }
1490 }
1491 }
1492 #endif
1493
1494 for (int y = 0; y < height - 1; y += 2) {
1495 ARGB4444ToARGBRow(src_argb4444, row, width);
1496 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444,
1497 row + kMaxStride, width);
1498 ARGBToUVRow(row, kMaxStride, dst_u, dst_v, width);
1499 ARGBToYRow(row, dst_y, width);
1500 ARGBToYRow(row + kMaxStride, dst_y + dst_stride_y, width);
1501 src_argb4444 += src_stride_argb4444 * 2;
1502 dst_y += dst_stride_y * 2;
1503 dst_u += dst_stride_u;
1504 dst_v += dst_stride_v;
1505 }
1506 if (height & 1) {
1507 ARGB4444ToARGBRow_C(src_argb4444, row, width);
1508 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1509 ARGBToYRow(row, dst_y, width);
1510 }
1511 return 0;
1512 }
1513
1514 #ifdef HAVE_JPEG
1515 struct I420Buffers {
1516 uint8* y;
1517 int y_stride;
1518 uint8* u;
1519 int u_stride;
1520 uint8* v;
1521 int v_stride;
1522 int w;
1523 int h;
1524 };
1525
JpegCopyI420(void * opaque,const uint8 * const * data,const int * strides,int rows)1526 static void JpegCopyI420(void* opaque,
1527 const uint8* const* data,
1528 const int* strides,
1529 int rows) {
1530 I420Buffers* dest = static_cast<I420Buffers*>(opaque);
1531 I420Copy(data[0], strides[0],
1532 data[1], strides[1],
1533 data[2], strides[2],
1534 dest->y, dest->y_stride,
1535 dest->u, dest->u_stride,
1536 dest->v, dest->v_stride,
1537 dest->w, rows);
1538 dest->y += rows * dest->y_stride;
1539 dest->u += ((rows + 1) >> 1) * dest->u_stride;
1540 dest->v += ((rows + 1) >> 1) * dest->v_stride;
1541 dest->h -= rows;
1542 }
1543
JpegI422ToI420(void * opaque,const uint8 * const * data,const int * strides,int rows)1544 static void JpegI422ToI420(void* opaque,
1545 const uint8* const* data,
1546 const int* strides,
1547 int rows) {
1548 I420Buffers* dest = static_cast<I420Buffers*>(opaque);
1549 I422ToI420(data[0], strides[0],
1550 data[1], strides[1],
1551 data[2], strides[2],
1552 dest->y, dest->y_stride,
1553 dest->u, dest->u_stride,
1554 dest->v, dest->v_stride,
1555 dest->w, rows);
1556 dest->y += rows * dest->y_stride;
1557 dest->u += ((rows + 1) >> 1) * dest->u_stride;
1558 dest->v += ((rows + 1) >> 1) * dest->v_stride;
1559 dest->h -= rows;
1560 }
1561
JpegI444ToI420(void * opaque,const uint8 * const * data,const int * strides,int rows)1562 static void JpegI444ToI420(void* opaque,
1563 const uint8* const* data,
1564 const int* strides,
1565 int rows) {
1566 I420Buffers* dest = static_cast<I420Buffers*>(opaque);
1567 I444ToI420(data[0], strides[0],
1568 data[1], strides[1],
1569 data[2], strides[2],
1570 dest->y, dest->y_stride,
1571 dest->u, dest->u_stride,
1572 dest->v, dest->v_stride,
1573 dest->w, rows);
1574 dest->y += rows * dest->y_stride;
1575 dest->u += ((rows + 1) >> 1) * dest->u_stride;
1576 dest->v += ((rows + 1) >> 1) * dest->v_stride;
1577 dest->h -= rows;
1578 }
1579
JpegI411ToI420(void * opaque,const uint8 * const * data,const int * strides,int rows)1580 static void JpegI411ToI420(void* opaque,
1581 const uint8* const* data,
1582 const int* strides,
1583 int rows) {
1584 I420Buffers* dest = static_cast<I420Buffers*>(opaque);
1585 I411ToI420(data[0], strides[0],
1586 data[1], strides[1],
1587 data[2], strides[2],
1588 dest->y, dest->y_stride,
1589 dest->u, dest->u_stride,
1590 dest->v, dest->v_stride,
1591 dest->w, rows);
1592 dest->y += rows * dest->y_stride;
1593 dest->u += ((rows + 1) >> 1) * dest->u_stride;
1594 dest->v += ((rows + 1) >> 1) * dest->v_stride;
1595 dest->h -= rows;
1596 }
1597
JpegI400ToI420(void * opaque,const uint8 * const * data,const int * strides,int rows)1598 static void JpegI400ToI420(void* opaque,
1599 const uint8* const* data,
1600 const int* strides,
1601 int rows) {
1602 I420Buffers* dest = static_cast<I420Buffers*>(opaque);
1603 I400ToI420(data[0], strides[0],
1604 dest->y, dest->y_stride,
1605 dest->u, dest->u_stride,
1606 dest->v, dest->v_stride,
1607 dest->w, rows);
1608 dest->y += rows * dest->y_stride;
1609 dest->u += ((rows + 1) >> 1) * dest->u_stride;
1610 dest->v += ((rows + 1) >> 1) * dest->v_stride;
1611 dest->h -= rows;
1612 }
1613
1614 // MJPG (Motion JPeg) to I420
1615 // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
1616 LIBYUV_API
MJPGToI420(const uint8 * sample,size_t sample_size,uint8 * y,int y_stride,uint8 * u,int u_stride,uint8 * v,int v_stride,int w,int h,int dw,int dh)1617 int MJPGToI420(const uint8* sample,
1618 size_t sample_size,
1619 uint8* y, int y_stride,
1620 uint8* u, int u_stride,
1621 uint8* v, int v_stride,
1622 int w, int h,
1623 int dw, int dh) {
1624 if (sample_size == kUnknownDataSize) {
1625 // ERROR: MJPEG frame size unknown
1626 return -1;
1627 }
1628
1629 // TODO(fbarchard): Port to C
1630 MJpegDecoder mjpeg_decoder;
1631 bool ret = mjpeg_decoder.LoadFrame(sample, sample_size);
1632 if (ret && (mjpeg_decoder.GetWidth() != w ||
1633 mjpeg_decoder.GetHeight() != h)) {
1634 // ERROR: MJPEG frame has unexpected dimensions
1635 mjpeg_decoder.UnloadFrame();
1636 return 1; // runtime failure
1637 }
1638 if (ret) {
1639 I420Buffers bufs = { y, y_stride, u, u_stride, v, v_stride, dw, dh };
1640 // YUV420
1641 if (mjpeg_decoder.GetColorSpace() ==
1642 MJpegDecoder::kColorSpaceYCbCr &&
1643 mjpeg_decoder.GetNumComponents() == 3 &&
1644 mjpeg_decoder.GetVertSampFactor(0) == 2 &&
1645 mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
1646 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
1647 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
1648 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
1649 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
1650 ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dw, dh);
1651 // YUV422
1652 } else if (mjpeg_decoder.GetColorSpace() ==
1653 MJpegDecoder::kColorSpaceYCbCr &&
1654 mjpeg_decoder.GetNumComponents() == 3 &&
1655 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
1656 mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
1657 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
1658 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
1659 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
1660 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
1661 ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dw, dh);
1662 // YUV444
1663 } else if (mjpeg_decoder.GetColorSpace() ==
1664 MJpegDecoder::kColorSpaceYCbCr &&
1665 mjpeg_decoder.GetNumComponents() == 3 &&
1666 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
1667 mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
1668 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
1669 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
1670 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
1671 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
1672 ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dw, dh);
1673 // YUV411
1674 } else if (mjpeg_decoder.GetColorSpace() ==
1675 MJpegDecoder::kColorSpaceYCbCr &&
1676 mjpeg_decoder.GetNumComponents() == 3 &&
1677 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
1678 mjpeg_decoder.GetHorizSampFactor(0) == 4 &&
1679 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
1680 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
1681 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
1682 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
1683 ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToI420, &bufs, dw, dh);
1684 // YUV400
1685 } else if (mjpeg_decoder.GetColorSpace() ==
1686 MJpegDecoder::kColorSpaceGrayscale &&
1687 mjpeg_decoder.GetNumComponents() == 1 &&
1688 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
1689 mjpeg_decoder.GetHorizSampFactor(0) == 1) {
1690 ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dw, dh);
1691 } else {
1692 // TODO(fbarchard): Implement conversion for any other colorspace/sample
1693 // factors that occur in practice. 411 is supported by libjpeg
1694 // ERROR: Unable to convert MJPEG frame because format is not supported
1695 mjpeg_decoder.UnloadFrame();
1696 return 1;
1697 }
1698 }
1699 return 0;
1700 }
1701 #endif
1702
1703 // Convert camera sample to I420 with cropping, rotation and vertical flip.
1704 // src_width is used for source stride computation
1705 // src_height is used to compute location of planes, and indicate inversion
1706 // sample_size is measured in bytes and is the size of the frame.
1707 // With MJPEG it is the compressed size of the frame.
1708 LIBYUV_API
ConvertToI420(const uint8 * sample,size_t sample_size,uint8 * y,int y_stride,uint8 * u,int u_stride,uint8 * v,int v_stride,int crop_x,int crop_y,int src_width,int src_height,int dst_width,int dst_height,RotationMode rotation,uint32 format)1709 int ConvertToI420(const uint8* sample,
1710 #ifdef HAVE_JPEG
1711 size_t sample_size,
1712 #else
1713 size_t /* sample_size */,
1714 #endif
1715 uint8* y, int y_stride,
1716 uint8* u, int u_stride,
1717 uint8* v, int v_stride,
1718 int crop_x, int crop_y,
1719 int src_width, int src_height,
1720 int dst_width, int dst_height,
1721 RotationMode rotation,
1722 uint32 format) {
1723 if (!y || !u || !v || !sample ||
1724 src_width <= 0 || dst_width <= 0 ||
1725 src_height == 0 || dst_height == 0) {
1726 return -1;
1727 }
1728 int aligned_src_width = (src_width + 1) & ~1;
1729 const uint8* src;
1730 const uint8* src_uv;
1731 int abs_src_height = (src_height < 0) ? -src_height : src_height;
1732 int inv_dst_height = (dst_height < 0) ? -dst_height : dst_height;
1733 if (src_height < 0) {
1734 inv_dst_height = -inv_dst_height;
1735 }
1736 int r = 0;
1737
1738 // One pass rotation is available for some formats. For the rest, convert
1739 // to I420 (with optional vertical flipping) into a temporary I420 buffer,
1740 // and then rotate the I420 to the final destination buffer.
1741 // For in-place conversion, if destination y is same as source sample,
1742 // also enable temporary buffer.
1743 bool need_buf = (rotation && format != FOURCC_I420 &&
1744 format != FOURCC_NV12 && format != FOURCC_NV21 &&
1745 format != FOURCC_YU12 && format != FOURCC_YV12) || y == sample;
1746 uint8* tmp_y = y;
1747 uint8* tmp_u = u;
1748 uint8* tmp_v = v;
1749 int tmp_y_stride = y_stride;
1750 int tmp_u_stride = u_stride;
1751 int tmp_v_stride = v_stride;
1752 uint8* buf = NULL;
1753 int abs_dst_height = (dst_height < 0) ? -dst_height : dst_height;
1754 if (need_buf) {
1755 int y_size = dst_width * abs_dst_height;
1756 int uv_size = ((dst_width + 1) / 2) * ((abs_dst_height + 1) / 2);
1757 buf = new uint8[y_size + uv_size * 2];
1758 if (!buf) {
1759 return 1; // Out of memory runtime error.
1760 }
1761 y = buf;
1762 u = y + y_size;
1763 v = u + uv_size;
1764 y_stride = dst_width;
1765 u_stride = v_stride = ((dst_width + 1) / 2);
1766 }
1767
1768 switch (format) {
1769 // Single plane formats
1770 case FOURCC_YUY2:
1771 src = sample + (aligned_src_width * crop_y + crop_x) * 2;
1772 r = YUY2ToI420(src, aligned_src_width * 2,
1773 y, y_stride,
1774 u, u_stride,
1775 v, v_stride,
1776 dst_width, inv_dst_height);
1777 break;
1778 case FOURCC_UYVY:
1779 src = sample + (aligned_src_width * crop_y + crop_x) * 2;
1780 r = UYVYToI420(src, aligned_src_width * 2,
1781 y, y_stride,
1782 u, u_stride,
1783 v, v_stride,
1784 dst_width, inv_dst_height);
1785 break;
1786 case FOURCC_V210:
1787 // stride is multiple of 48 pixels (128 bytes).
1788 // pixels come in groups of 6 = 16 bytes
1789 src = sample + (aligned_src_width + 47) / 48 * 128 * crop_y +
1790 crop_x / 6 * 16;
1791 r = V210ToI420(src, (aligned_src_width + 47) / 48 * 128,
1792 y, y_stride,
1793 u, u_stride,
1794 v, v_stride,
1795 dst_width, inv_dst_height);
1796 break;
1797 case FOURCC_24BG:
1798 src = sample + (src_width * crop_y + crop_x) * 3;
1799 r = RGB24ToI420(src, src_width * 3,
1800 y, y_stride,
1801 u, u_stride,
1802 v, v_stride,
1803 dst_width, inv_dst_height);
1804 break;
1805 case FOURCC_RAW:
1806 src = sample + (src_width * crop_y + crop_x) * 3;
1807 r = RAWToI420(src, src_width * 3,
1808 y, y_stride,
1809 u, u_stride,
1810 v, v_stride,
1811 dst_width, inv_dst_height);
1812 break;
1813 case FOURCC_ARGB:
1814 src = sample + (src_width * crop_y + crop_x) * 4;
1815 r = ARGBToI420(src, src_width * 4,
1816 y, y_stride,
1817 u, u_stride,
1818 v, v_stride,
1819 dst_width, inv_dst_height);
1820 break;
1821 case FOURCC_BGRA:
1822 src = sample + (src_width * crop_y + crop_x) * 4;
1823 r = BGRAToI420(src, src_width * 4,
1824 y, y_stride,
1825 u, u_stride,
1826 v, v_stride,
1827 dst_width, inv_dst_height);
1828 break;
1829 case FOURCC_ABGR:
1830 src = sample + (src_width * crop_y + crop_x) * 4;
1831 r = ABGRToI420(src, src_width * 4,
1832 y, y_stride,
1833 u, u_stride,
1834 v, v_stride,
1835 dst_width, inv_dst_height);
1836 break;
1837 case FOURCC_RGBA:
1838 src = sample + (src_width * crop_y + crop_x) * 4;
1839 r = RGBAToI420(src, src_width * 4,
1840 y, y_stride,
1841 u, u_stride,
1842 v, v_stride,
1843 dst_width, inv_dst_height);
1844 break;
1845 case FOURCC_RGBP:
1846 src = sample + (src_width * crop_y + crop_x) * 2;
1847 r = RGB565ToI420(src, src_width * 2,
1848 y, y_stride,
1849 u, u_stride,
1850 v, v_stride,
1851 dst_width, inv_dst_height);
1852 break;
1853 case FOURCC_RGBO:
1854 src = sample + (src_width * crop_y + crop_x) * 2;
1855 r = ARGB1555ToI420(src, src_width * 2,
1856 y, y_stride,
1857 u, u_stride,
1858 v, v_stride,
1859 dst_width, inv_dst_height);
1860 break;
1861 case FOURCC_R444:
1862 src = sample + (src_width * crop_y + crop_x) * 2;
1863 r = ARGB4444ToI420(src, src_width * 2,
1864 y, y_stride,
1865 u, u_stride,
1866 v, v_stride,
1867 dst_width, inv_dst_height);
1868 break;
1869 // TODO(fbarchard): Support cropping Bayer by odd numbers
1870 // by adjusting fourcc.
1871 case FOURCC_BGGR:
1872 src = sample + (src_width * crop_y + crop_x);
1873 r = BayerBGGRToI420(src, src_width,
1874 y, y_stride,
1875 u, u_stride,
1876 v, v_stride,
1877 dst_width, inv_dst_height);
1878 break;
1879
1880 case FOURCC_GBRG:
1881 src = sample + (src_width * crop_y + crop_x);
1882 r = BayerGBRGToI420(src, src_width,
1883 y, y_stride,
1884 u, u_stride,
1885 v, v_stride,
1886 dst_width, inv_dst_height);
1887 break;
1888
1889 case FOURCC_GRBG:
1890 src = sample + (src_width * crop_y + crop_x);
1891 r = BayerGRBGToI420(src, src_width,
1892 y, y_stride,
1893 u, u_stride,
1894 v, v_stride,
1895 dst_width, inv_dst_height);
1896 break;
1897
1898 case FOURCC_RGGB:
1899 src = sample + (src_width * crop_y + crop_x);
1900 r = BayerRGGBToI420(src, src_width,
1901 y, y_stride,
1902 u, u_stride,
1903 v, v_stride,
1904 dst_width, inv_dst_height);
1905 break;
1906
1907 case FOURCC_I400:
1908 src = sample + src_width * crop_y + crop_x;
1909 r = I400ToI420(src, src_width,
1910 y, y_stride,
1911 u, u_stride,
1912 v, v_stride,
1913 dst_width, inv_dst_height);
1914 break;
1915
1916 // Biplanar formats
1917 case FOURCC_NV12:
1918 src = sample + (src_width * crop_y + crop_x);
1919 src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
1920 r = NV12ToI420Rotate(src, src_width,
1921 src_uv, aligned_src_width,
1922 y, y_stride,
1923 u, u_stride,
1924 v, v_stride,
1925 dst_width, inv_dst_height, rotation);
1926 break;
1927 case FOURCC_NV21:
1928 src = sample + (src_width * crop_y + crop_x);
1929 src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
1930 // Call NV12 but with u and v parameters swapped.
1931 r = NV12ToI420Rotate(src, src_width,
1932 src_uv, aligned_src_width,
1933 y, y_stride,
1934 v, v_stride,
1935 u, u_stride,
1936 dst_width, inv_dst_height, rotation);
1937 break;
1938 case FOURCC_M420:
1939 src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
1940 r = M420ToI420(src, src_width,
1941 y, y_stride,
1942 u, u_stride,
1943 v, v_stride,
1944 dst_width, inv_dst_height);
1945 break;
1946 case FOURCC_Q420:
1947 src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x;
1948 src_uv = sample + (src_width + aligned_src_width * 2) * crop_y +
1949 src_width + crop_x * 2;
1950 r = Q420ToI420(src, src_width * 3,
1951 src_uv, src_width * 3,
1952 y, y_stride,
1953 u, u_stride,
1954 v, v_stride,
1955 dst_width, inv_dst_height);
1956 break;
1957 // Triplanar formats
1958 case FOURCC_I420:
1959 case FOURCC_YU12:
1960 case FOURCC_YV12: {
1961 const uint8* src_y = sample + (src_width * crop_y + crop_x);
1962 const uint8* src_u;
1963 const uint8* src_v;
1964 int halfwidth = (src_width + 1) / 2;
1965 int halfheight = (abs_src_height + 1) / 2;
1966 if (format == FOURCC_YV12) {
1967 src_v = sample + src_width * abs_src_height +
1968 (halfwidth * crop_y + crop_x) / 2;
1969 src_u = sample + src_width * abs_src_height +
1970 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
1971 } else {
1972 src_u = sample + src_width * abs_src_height +
1973 (halfwidth * crop_y + crop_x) / 2;
1974 src_v = sample + src_width * abs_src_height +
1975 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
1976 }
1977 r = I420Rotate(src_y, src_width,
1978 src_u, halfwidth,
1979 src_v, halfwidth,
1980 y, y_stride,
1981 u, u_stride,
1982 v, v_stride,
1983 dst_width, inv_dst_height, rotation);
1984 break;
1985 }
1986 case FOURCC_I422:
1987 case FOURCC_YV16: {
1988 const uint8* src_y = sample + src_width * crop_y + crop_x;
1989 const uint8* src_u;
1990 const uint8* src_v;
1991 int halfwidth = (src_width + 1) / 2;
1992 if (format == FOURCC_YV16) {
1993 src_v = sample + src_width * abs_src_height +
1994 halfwidth * crop_y + crop_x / 2;
1995 src_u = sample + src_width * abs_src_height +
1996 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
1997 } else {
1998 src_u = sample + src_width * abs_src_height +
1999 halfwidth * crop_y + crop_x / 2;
2000 src_v = sample + src_width * abs_src_height +
2001 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
2002 }
2003 r = I422ToI420(src_y, src_width,
2004 src_u, halfwidth,
2005 src_v, halfwidth,
2006 y, y_stride,
2007 u, u_stride,
2008 v, v_stride,
2009 dst_width, inv_dst_height);
2010 break;
2011 }
2012 case FOURCC_I444:
2013 case FOURCC_YV24: {
2014 const uint8* src_y = sample + src_width * crop_y + crop_x;
2015 const uint8* src_u;
2016 const uint8* src_v;
2017 if (format == FOURCC_YV24) {
2018 src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
2019 src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
2020 } else {
2021 src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
2022 src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
2023 }
2024 r = I444ToI420(src_y, src_width,
2025 src_u, src_width,
2026 src_v, src_width,
2027 y, y_stride,
2028 u, u_stride,
2029 v, v_stride,
2030 dst_width, inv_dst_height);
2031 break;
2032 }
2033 case FOURCC_I411: {
2034 int quarterwidth = (src_width + 3) / 4;
2035 const uint8* src_y = sample + src_width * crop_y + crop_x;
2036 const uint8* src_u = sample + src_width * abs_src_height +
2037 quarterwidth * crop_y + crop_x / 4;
2038 const uint8* src_v = sample + src_width * abs_src_height +
2039 quarterwidth * (abs_src_height + crop_y) + crop_x / 4;
2040 r = I411ToI420(src_y, src_width,
2041 src_u, quarterwidth,
2042 src_v, quarterwidth,
2043 y, y_stride,
2044 u, u_stride,
2045 v, v_stride,
2046 dst_width, inv_dst_height);
2047 break;
2048 }
2049 #ifdef HAVE_JPEG
2050 case FOURCC_MJPG:
2051 r = MJPGToI420(sample, sample_size,
2052 y, y_stride,
2053 u, u_stride,
2054 v, v_stride,
2055 src_width, abs_src_height, dst_width, inv_dst_height);
2056 break;
2057 #endif
2058 default:
2059 r = -1; // unknown fourcc - return failure code.
2060 }
2061
2062 if (need_buf) {
2063 if (!r) {
2064 r = I420Rotate(y, y_stride,
2065 u, u_stride,
2066 v, v_stride,
2067 tmp_y, tmp_y_stride,
2068 tmp_u, tmp_u_stride,
2069 tmp_v, tmp_v_stride,
2070 dst_width, abs_dst_height, rotation);
2071 }
2072 delete buf;
2073 }
2074
2075 return r;
2076 }
2077
2078 #ifdef __cplusplus
2079 } // extern "C"
2080 } // namespace libyuv
2081 #endif
2082