• 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 "libyuv/convert_argb.h"
12 
13 #include <string.h>  // for memset()
14 
15 #include "libyuv/cpu_id.h"
16 #include "libyuv/format_conversion.h"
17 #ifdef HAVE_JPEG
18 #include "libyuv/mjpeg_decoder.h"
19 #endif
20 #include "libyuv/rotate_argb.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 ARGB with optional flipping
30 LIBYUV_API
ARGBCopy(const uint8 * src_argb,int src_stride_argb,uint8 * dst_argb,int dst_stride_argb,int width,int height)31 int ARGBCopy(const uint8* src_argb, int src_stride_argb,
32              uint8* dst_argb, int dst_stride_argb,
33              int width, int height) {
34   if (!src_argb || !dst_argb ||
35       width <= 0 || height == 0) {
36     return -1;
37   }
38   // Negative height means invert the image.
39   if (height < 0) {
40     height = -height;
41     src_argb = src_argb + (height - 1) * src_stride_argb;
42     src_stride_argb = -src_stride_argb;
43   }
44 
45   CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
46             width * 4, height);
47   return 0;
48 }
49 
50 // Convert I444 to ARGB.
51 LIBYUV_API
I444ToARGB(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_argb,int dst_stride_argb,int width,int height)52 int I444ToARGB(const uint8* src_y, int src_stride_y,
53                const uint8* src_u, int src_stride_u,
54                const uint8* src_v, int src_stride_v,
55                uint8* dst_argb, int dst_stride_argb,
56                int width, int height) {
57   if (!src_y || !src_u || !src_v ||
58       !dst_argb ||
59       width <= 0 || height == 0) {
60     return -1;
61   }
62   // Negative height means invert the image.
63   if (height < 0) {
64     height = -height;
65     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
66     dst_stride_argb = -dst_stride_argb;
67   }
68   void (*I444ToARGBRow)(const uint8* y_buf,
69                         const uint8* u_buf,
70                         const uint8* v_buf,
71                         uint8* rgb_buf,
72                         int width) = I444ToARGBRow_C;
73 #if defined(HAS_I444TOARGBROW_SSSE3)
74   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
75     I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
76     if (IS_ALIGNED(width, 8)) {
77       I444ToARGBRow = I444ToARGBRow_Unaligned_SSSE3;
78       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
79         I444ToARGBRow = I444ToARGBRow_SSSE3;
80       }
81     }
82   }
83 #endif
84 
85   for (int y = 0; y < height; ++y) {
86     I444ToARGBRow(src_y, src_u, src_v, dst_argb, width);
87     dst_argb += dst_stride_argb;
88     src_y += src_stride_y;
89     src_u += src_stride_u;
90     src_v += src_stride_v;
91   }
92   return 0;
93 }
94 
95 // Convert I422 to ARGB.
96 LIBYUV_API
I422ToARGB(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_argb,int dst_stride_argb,int width,int height)97 int I422ToARGB(const uint8* src_y, int src_stride_y,
98                const uint8* src_u, int src_stride_u,
99                const uint8* src_v, int src_stride_v,
100                uint8* dst_argb, int dst_stride_argb,
101                int width, int height) {
102   if (!src_y || !src_u || !src_v ||
103       !dst_argb ||
104       width <= 0 || height == 0) {
105     return -1;
106   }
107   // Negative height means invert the image.
108   if (height < 0) {
109     height = -height;
110     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
111     dst_stride_argb = -dst_stride_argb;
112   }
113   void (*I422ToARGBRow)(const uint8* y_buf,
114                         const uint8* u_buf,
115                         const uint8* v_buf,
116                         uint8* rgb_buf,
117                         int width) = I422ToARGBRow_C;
118 #if defined(HAS_I422TOARGBROW_NEON)
119   if (TestCpuFlag(kCpuHasNEON)) {
120     I422ToARGBRow = I422ToARGBRow_Any_NEON;
121     if (IS_ALIGNED(width, 16)) {
122       I422ToARGBRow = I422ToARGBRow_NEON;
123     }
124   }
125 #elif defined(HAS_I422TOARGBROW_SSSE3)
126   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
127     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
128     if (IS_ALIGNED(width, 8)) {
129       I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3;
130       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
131         I422ToARGBRow = I422ToARGBRow_SSSE3;
132       }
133     }
134   }
135 #endif
136 
137   for (int y = 0; y < height; ++y) {
138     I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
139     dst_argb += dst_stride_argb;
140     src_y += src_stride_y;
141     src_u += src_stride_u;
142     src_v += src_stride_v;
143   }
144   return 0;
145 }
146 
147 // Convert I411 to ARGB.
148 LIBYUV_API
I411ToARGB(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_argb,int dst_stride_argb,int width,int height)149 int I411ToARGB(const uint8* src_y, int src_stride_y,
150                const uint8* src_u, int src_stride_u,
151                const uint8* src_v, int src_stride_v,
152                uint8* dst_argb, int dst_stride_argb,
153                int width, int height) {
154   if (!src_y || !src_u || !src_v ||
155       !dst_argb ||
156       width <= 0 || height == 0) {
157     return -1;
158   }
159   // Negative height means invert the image.
160   if (height < 0) {
161     height = -height;
162     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
163     dst_stride_argb = -dst_stride_argb;
164   }
165   void (*I411ToARGBRow)(const uint8* y_buf,
166                         const uint8* u_buf,
167                         const uint8* v_buf,
168                         uint8* rgb_buf,
169                         int width) = I411ToARGBRow_C;
170 #if defined(HAS_I411TOARGBROW_SSSE3)
171   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
172     I411ToARGBRow = I411ToARGBRow_Any_SSSE3;
173     if (IS_ALIGNED(width, 8)) {
174       I411ToARGBRow = I411ToARGBRow_Unaligned_SSSE3;
175       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
176         I411ToARGBRow = I411ToARGBRow_SSSE3;
177       }
178     }
179   }
180 #endif
181 
182   for (int y = 0; y < height; ++y) {
183     I411ToARGBRow(src_y, src_u, src_v, dst_argb, width);
184     dst_argb += dst_stride_argb;
185     src_y += src_stride_y;
186     src_u += src_stride_u;
187     src_v += src_stride_v;
188   }
189   return 0;
190 }
191 
192 
193 // Convert I400 to ARGB.
194 LIBYUV_API
I400ToARGB_Reference(const uint8 * src_y,int src_stride_y,uint8 * dst_argb,int dst_stride_argb,int width,int height)195 int I400ToARGB_Reference(const uint8* src_y, int src_stride_y,
196                          uint8* dst_argb, int dst_stride_argb,
197                          int width, int height) {
198   if (!src_y || !dst_argb ||
199       width <= 0 || height == 0) {
200     return -1;
201   }
202   // Negative height means invert the image.
203   if (height < 0) {
204     height = -height;
205     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
206     dst_stride_argb = -dst_stride_argb;
207   }
208   void (*YToARGBRow)(const uint8* y_buf,
209                      uint8* rgb_buf,
210                      int width) = YToARGBRow_C;
211 #if defined(HAS_YTOARGBROW_SSE2)
212   if (TestCpuFlag(kCpuHasSSE2) &&
213       IS_ALIGNED(width, 8) &&
214       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
215     YToARGBRow = YToARGBRow_SSE2;
216   }
217 #endif
218 
219   for (int y = 0; y < height; ++y) {
220     YToARGBRow(src_y, dst_argb, width);
221     dst_argb += dst_stride_argb;
222     src_y += src_stride_y;
223   }
224   return 0;
225 }
226 
227 // Convert I400 to ARGB.
228 LIBYUV_API
I400ToARGB(const uint8 * src_y,int src_stride_y,uint8 * dst_argb,int dst_stride_argb,int width,int height)229 int I400ToARGB(const uint8* src_y, int src_stride_y,
230                uint8* dst_argb, int dst_stride_argb,
231                int width, int height) {
232   if (!src_y || !dst_argb ||
233       width <= 0 || height == 0) {
234     return -1;
235   }
236   // Negative height means invert the image.
237   if (height < 0) {
238     height = -height;
239     src_y = src_y + (height - 1) * src_stride_y;
240     src_stride_y = -src_stride_y;
241   }
242   void (*I400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int pix) =
243       I400ToARGBRow_C;
244 #if defined(HAS_I400TOARGBROW_SSE2)
245   if (TestCpuFlag(kCpuHasSSE2) &&
246       IS_ALIGNED(width, 8) &&
247       IS_ALIGNED(src_y, 8) && IS_ALIGNED(src_stride_y, 8) &&
248       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
249     I400ToARGBRow = I400ToARGBRow_SSE2;
250   }
251 #endif
252 
253   for (int y = 0; y < height; ++y) {
254     I400ToARGBRow(src_y, dst_argb, width);
255     src_y += src_stride_y;
256     dst_argb += dst_stride_argb;
257   }
258   return 0;
259 }
260 
261 // Convert BGRA to ARGB.
262 LIBYUV_API
BGRAToARGB(const uint8 * src_bgra,int src_stride_bgra,uint8 * dst_argb,int dst_stride_argb,int width,int height)263 int BGRAToARGB(const uint8* src_bgra, int src_stride_bgra,
264                uint8* dst_argb, int dst_stride_argb,
265                int width, int height) {
266   if (!src_bgra || !dst_argb ||
267       width <= 0 || height == 0) {
268     return -1;
269   }
270   // Negative height means invert the image.
271   if (height < 0) {
272     height = -height;
273     src_bgra = src_bgra + (height - 1) * src_stride_bgra;
274     src_stride_bgra = -src_stride_bgra;
275   }
276   void (*BGRAToARGBRow)(const uint8* src_bgra, uint8* dst_argb, int pix) =
277       BGRAToARGBRow_C;
278 #if defined(HAS_BGRATOARGBROW_SSSE3)
279   if (TestCpuFlag(kCpuHasSSSE3) &&
280       IS_ALIGNED(width, 4) &&
281       IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16) &&
282       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
283     BGRAToARGBRow = BGRAToARGBRow_SSSE3;
284   }
285 #endif
286 
287   for (int y = 0; y < height; ++y) {
288     BGRAToARGBRow(src_bgra, dst_argb, width);
289     src_bgra += src_stride_bgra;
290     dst_argb += dst_stride_argb;
291   }
292   return 0;
293 }
294 
295 // Convert ABGR to ARGB.
296 LIBYUV_API
ABGRToARGB(const uint8 * src_abgr,int src_stride_abgr,uint8 * dst_argb,int dst_stride_argb,int width,int height)297 int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr,
298                uint8* dst_argb, int dst_stride_argb,
299                int width, int height) {
300   if (!src_abgr || !dst_argb ||
301       width <= 0 || height == 0) {
302     return -1;
303   }
304   // Negative height means invert the image.
305   if (height < 0) {
306     height = -height;
307     src_abgr = src_abgr + (height - 1) * src_stride_abgr;
308     src_stride_abgr = -src_stride_abgr;
309   }
310   void (*ABGRToARGBRow)(const uint8* src_abgr, uint8* dst_argb, int pix) =
311       ABGRToARGBRow_C;
312 #if defined(HAS_ABGRTOARGBROW_SSSE3)
313   if (TestCpuFlag(kCpuHasSSSE3) &&
314       IS_ALIGNED(width, 4) &&
315       IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16) &&
316       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
317     ABGRToARGBRow = ABGRToARGBRow_SSSE3;
318   }
319 #endif
320 
321   for (int y = 0; y < height; ++y) {
322     ABGRToARGBRow(src_abgr, dst_argb, width);
323     src_abgr += src_stride_abgr;
324     dst_argb += dst_stride_argb;
325   }
326   return 0;
327 }
328 
329 // Convert RGBA to ARGB.
330 LIBYUV_API
RGBAToARGB(const uint8 * src_rgba,int src_stride_rgba,uint8 * dst_argb,int dst_stride_argb,int width,int height)331 int RGBAToARGB(const uint8* src_rgba, int src_stride_rgba,
332                uint8* dst_argb, int dst_stride_argb,
333                int width, int height) {
334   if (!src_rgba || !dst_argb ||
335       width <= 0 || height == 0) {
336     return -1;
337   }
338   // Negative height means invert the image.
339   if (height < 0) {
340     height = -height;
341     src_rgba = src_rgba + (height - 1) * src_stride_rgba;
342     src_stride_rgba = -src_stride_rgba;
343   }
344   void (*RGBAToARGBRow)(const uint8* src_rgba, uint8* dst_argb, int pix) =
345       RGBAToARGBRow_C;
346 #if defined(HAS_RGBATOARGBROW_SSSE3)
347   if (TestCpuFlag(kCpuHasSSSE3) &&
348       IS_ALIGNED(width, 4) &&
349       IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16) &&
350       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
351     RGBAToARGBRow = RGBAToARGBRow_SSSE3;
352   }
353 #endif
354 
355   for (int y = 0; y < height; ++y) {
356     RGBAToARGBRow(src_rgba, dst_argb, width);
357     src_rgba += src_stride_rgba;
358     dst_argb += dst_stride_argb;
359   }
360   return 0;
361 }
362 
363 // Convert RAW to ARGB.
364 LIBYUV_API
RAWToARGB(const uint8 * src_raw,int src_stride_raw,uint8 * dst_argb,int dst_stride_argb,int width,int height)365 int RAWToARGB(const uint8* src_raw, int src_stride_raw,
366               uint8* dst_argb, int dst_stride_argb,
367               int width, int height) {
368   if (!src_raw || !dst_argb ||
369       width <= 0 || height == 0) {
370     return -1;
371   }
372   // Negative height means invert the image.
373   if (height < 0) {
374     height = -height;
375     src_raw = src_raw + (height - 1) * src_stride_raw;
376     src_stride_raw = -src_stride_raw;
377   }
378   void (*RAWToARGBRow)(const uint8* src_raw, uint8* dst_argb, int pix) =
379       RAWToARGBRow_C;
380 #if defined(HAS_RAWTOARGBROW_SSSE3)
381   if (TestCpuFlag(kCpuHasSSSE3) &&
382       IS_ALIGNED(width, 16) &&
383       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
384     RAWToARGBRow = RAWToARGBRow_SSSE3;
385   }
386 #endif
387 
388   for (int y = 0; y < height; ++y) {
389     RAWToARGBRow(src_raw, dst_argb, width);
390     src_raw += src_stride_raw;
391     dst_argb += dst_stride_argb;
392   }
393   return 0;
394 }
395 
396 // Convert RGB24 to ARGB.
397 LIBYUV_API
RGB24ToARGB(const uint8 * src_rgb24,int src_stride_rgb24,uint8 * dst_argb,int dst_stride_argb,int width,int height)398 int RGB24ToARGB(const uint8* src_rgb24, int src_stride_rgb24,
399                 uint8* dst_argb, int dst_stride_argb,
400                 int width, int height) {
401   if (!src_rgb24 || !dst_argb ||
402       width <= 0 || height == 0) {
403     return -1;
404   }
405   // Negative height means invert the image.
406   if (height < 0) {
407     height = -height;
408     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
409     src_stride_rgb24 = -src_stride_rgb24;
410   }
411   void (*RGB24ToARGBRow)(const uint8* src_rgb24, uint8* dst_argb, int pix) =
412       RGB24ToARGBRow_C;
413 #if defined(HAS_RGB24TOARGBROW_SSSE3)
414   if (TestCpuFlag(kCpuHasSSSE3) &&
415       IS_ALIGNED(width, 16) &&
416       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
417     RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
418   }
419 #endif
420 
421   for (int y = 0; y < height; ++y) {
422     RGB24ToARGBRow(src_rgb24, dst_argb, width);
423     src_rgb24 += src_stride_rgb24;
424     dst_argb += dst_stride_argb;
425   }
426   return 0;
427 }
428 
429 // Convert RGB565 to ARGB.
430 LIBYUV_API
RGB565ToARGB(const uint8 * src_rgb565,int src_stride_rgb565,uint8 * dst_argb,int dst_stride_argb,int width,int height)431 int RGB565ToARGB(const uint8* src_rgb565, int src_stride_rgb565,
432                  uint8* dst_argb, int dst_stride_argb,
433                  int width, int height) {
434   if (!src_rgb565 || !dst_argb ||
435       width <= 0 || height == 0) {
436     return -1;
437   }
438   // Negative height means invert the image.
439   if (height < 0) {
440     height = -height;
441     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
442     src_stride_rgb565 = -src_stride_rgb565;
443   }
444   void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int pix) =
445       RGB565ToARGBRow_C;
446 #if defined(HAS_RGB565TOARGBROW_SSE2)
447   if (TestCpuFlag(kCpuHasSSE2) &&
448       IS_ALIGNED(width, 8) &&
449       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
450     RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
451   }
452 #endif
453 
454   for (int y = 0; y < height; ++y) {
455     RGB565ToARGBRow(src_rgb565, dst_argb, width);
456     src_rgb565 += src_stride_rgb565;
457     dst_argb += dst_stride_argb;
458   }
459   return 0;
460 }
461 
462 // Convert ARGB1555 to ARGB.
463 LIBYUV_API
ARGB1555ToARGB(const uint8 * src_argb1555,int src_stride_argb1555,uint8 * dst_argb,int dst_stride_argb,int width,int height)464 int ARGB1555ToARGB(const uint8* src_argb1555, int src_stride_argb1555,
465                    uint8* dst_argb, int dst_stride_argb,
466                    int width, int height) {
467   if (!src_argb1555 || !dst_argb ||
468        width <= 0 || height == 0) {
469     return -1;
470   }
471   // Negative height means invert the image.
472   if (height < 0) {
473     height = -height;
474     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
475     src_stride_argb1555 = -src_stride_argb1555;
476   }
477   void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb,
478                             int pix) = ARGB1555ToARGBRow_C;
479 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
480   if (TestCpuFlag(kCpuHasSSE2) &&
481       IS_ALIGNED(width, 8) &&
482       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
483     ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
484   }
485 #endif
486 
487   for (int y = 0; y < height; ++y) {
488     ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
489     src_argb1555 += src_stride_argb1555;
490     dst_argb += dst_stride_argb;
491   }
492   return 0;
493 }
494 
495 // Convert ARGB4444 to ARGB.
496 LIBYUV_API
ARGB4444ToARGB(const uint8 * src_argb4444,int src_stride_argb4444,uint8 * dst_argb,int dst_stride_argb,int width,int height)497 int ARGB4444ToARGB(const uint8* src_argb4444, int src_stride_argb4444,
498                    uint8* dst_argb, int dst_stride_argb,
499                    int width, int height) {
500   if (!src_argb4444 || !dst_argb ||
501       width <= 0 || height == 0) {
502     return -1;
503   }
504   // Negative height means invert the image.
505   if (height < 0) {
506     height = -height;
507     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
508     src_stride_argb4444 = -src_stride_argb4444;
509   }
510   void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb,
511                             int pix) = ARGB4444ToARGBRow_C;
512 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
513   if (TestCpuFlag(kCpuHasSSE2) &&
514       IS_ALIGNED(width, 8) &&
515       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
516     ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
517   }
518 #endif
519 
520   for (int y = 0; y < height; ++y) {
521     ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
522     src_argb4444 += src_stride_argb4444;
523     dst_argb += dst_stride_argb;
524   }
525   return 0;
526 }
527 
528 // Convert NV12 to ARGB.
529 LIBYUV_API
NV12ToARGB(const uint8 * src_y,int src_stride_y,const uint8 * src_uv,int src_stride_uv,uint8 * dst_argb,int dst_stride_argb,int width,int height)530 int NV12ToARGB(const uint8* src_y, int src_stride_y,
531                const uint8* src_uv, int src_stride_uv,
532                uint8* dst_argb, int dst_stride_argb,
533                int width, int height) {
534   if (!src_y || !src_uv || !dst_argb ||
535       width <= 0 || height == 0) {
536     return -1;
537   }
538   // Negative height means invert the image.
539   if (height < 0) {
540     height = -height;
541     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
542     dst_stride_argb = -dst_stride_argb;
543   }
544   void (*NV12ToARGBRow)(const uint8* y_buf,
545                         const uint8* uv_buf,
546                         uint8* rgb_buf,
547                         int width) = NV12ToARGBRow_C;
548 #if defined(HAS_NV12TOARGBROW_SSSE3)
549   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
550     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
551     if (IS_ALIGNED(width, 8)) {
552       NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3;
553       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
554         NV12ToARGBRow = NV12ToARGBRow_SSSE3;
555       }
556     }
557   }
558 #endif
559 #if defined(HAS_NV12TOARGBROW_NEON)
560   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
561     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
562     if (IS_ALIGNED(width, 8)) {
563       NV12ToARGBRow = NV12ToARGBRow_NEON;
564     }
565   }
566 #endif
567 
568   for (int y = 0; y < height; ++y) {
569     NV12ToARGBRow(src_y, src_uv, dst_argb, width);
570     dst_argb += dst_stride_argb;
571     src_y += src_stride_y;
572     if (y & 1) {
573       src_uv += src_stride_uv;
574     }
575   }
576   return 0;
577 }
578 
579 // Convert NV21 to ARGB.
580 LIBYUV_API
NV21ToARGB(const uint8 * src_y,int src_stride_y,const uint8 * src_uv,int src_stride_uv,uint8 * dst_argb,int dst_stride_argb,int width,int height)581 int NV21ToARGB(const uint8* src_y, int src_stride_y,
582                const uint8* src_uv, int src_stride_uv,
583                uint8* dst_argb, int dst_stride_argb,
584                int width, int height) {
585   if (!src_y || !src_uv || !dst_argb ||
586       width <= 0 || height == 0) {
587     return -1;
588   }
589   // Negative height means invert the image.
590   if (height < 0) {
591     height = -height;
592     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
593     dst_stride_argb = -dst_stride_argb;
594   }
595   void (*NV21ToARGBRow)(const uint8* y_buf,
596                         const uint8* uv_buf,
597                         uint8* rgb_buf,
598                         int width) = NV21ToARGBRow_C;
599 #if defined(HAS_NV21TOARGBROW_SSSE3)
600   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
601     NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
602     if (IS_ALIGNED(width, 8)) {
603       NV21ToARGBRow = NV21ToARGBRow_Unaligned_SSSE3;
604       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
605         NV21ToARGBRow = NV21ToARGBRow_SSSE3;
606       }
607     }
608   }
609 #endif
610 #if defined(HAS_NV21TOARGBROW_NEON)
611   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
612     NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
613     if (IS_ALIGNED(width, 8)) {
614       NV21ToARGBRow = NV21ToARGBRow_NEON;
615     }
616   }
617 #endif
618 
619   for (int y = 0; y < height; ++y) {
620     NV21ToARGBRow(src_y, src_uv, dst_argb, width);
621     dst_argb += dst_stride_argb;
622     src_y += src_stride_y;
623     if (y & 1) {
624       src_uv += src_stride_uv;
625     }
626   }
627   return 0;
628 }
629 
630 // Convert M420 to ARGB.
631 LIBYUV_API
M420ToARGB(const uint8 * src_m420,int src_stride_m420,uint8 * dst_argb,int dst_stride_argb,int width,int height)632 int M420ToARGB(const uint8* src_m420, int src_stride_m420,
633                uint8* dst_argb, int dst_stride_argb,
634                int width, int height) {
635   if (!src_m420 || !dst_argb ||
636       width <= 0 || height == 0) {
637     return -1;
638   }
639   // Negative height means invert the image.
640   if (height < 0) {
641     height = -height;
642     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
643     dst_stride_argb = -dst_stride_argb;
644   }
645   void (*NV12ToARGBRow)(const uint8* y_buf,
646                         const uint8* uv_buf,
647                         uint8* rgb_buf,
648                         int width) = NV12ToARGBRow_C;
649 #if defined(HAS_NV12TOARGBROW_SSSE3)
650   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
651     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
652     if (IS_ALIGNED(width, 8)) {
653       NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3;
654       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
655         NV12ToARGBRow = NV12ToARGBRow_SSSE3;
656       }
657     }
658   }
659 #endif
660 
661   for (int y = 0; y < height - 1; y += 2) {
662     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width);
663     NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
664                   dst_argb + dst_stride_argb, width);
665     dst_argb += dst_stride_argb * 2;
666     src_m420 += src_stride_m420 * 3;
667   }
668   if (height & 1) {
669     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width);
670   }
671   return 0;
672 }
673 
674 // Convert YUY2 to ARGB.
675 LIBYUV_API
YUY2ToARGB(const uint8 * src_yuy2,int src_stride_yuy2,uint8 * dst_argb,int dst_stride_argb,int width,int height)676 int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2,
677                uint8* dst_argb, int dst_stride_argb,
678                int width, int height) {
679   if (!src_yuy2 || !dst_argb ||
680       width <= 0 || height == 0) {
681     return -1;
682   }
683   // Negative height means invert the image.
684   if (height < 0) {
685     height = -height;
686     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
687     src_stride_yuy2 = -src_stride_yuy2;
688   }
689   void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
690       int pix) = YUY2ToUV422Row_C;
691   void (*YUY2ToYRow)(const uint8* src_yuy2,
692                      uint8* dst_y, int pix) = YUY2ToYRow_C;
693 #if defined(HAS_YUY2TOYROW_SSE2)
694   if (TestCpuFlag(kCpuHasSSE2)) {
695     if (width > 16) {
696       YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
697       YUY2ToYRow = YUY2ToYRow_Any_SSE2;
698     }
699     if (IS_ALIGNED(width, 16)) {
700       YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
701       YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
702       if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
703         YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
704         YUY2ToYRow = YUY2ToYRow_SSE2;
705       }
706     }
707   }
708 #elif defined(HAS_YUY2TOYROW_NEON)
709   if (TestCpuFlag(kCpuHasNEON)) {
710     if (width > 8) {
711       YUY2ToYRow = YUY2ToYRow_Any_NEON;
712       if (width > 16) {
713         YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
714       }
715     }
716     if (IS_ALIGNED(width, 8)) {
717       YUY2ToYRow = YUY2ToYRow_NEON;
718       if (IS_ALIGNED(width, 16)) {
719         YUY2ToUV422Row = YUY2ToUV422Row_NEON;
720       }
721     }
722   }
723 #endif
724 
725   void (*I422ToARGBRow)(const uint8* y_buf,
726                         const uint8* u_buf,
727                         const uint8* v_buf,
728                         uint8* argb_buf,
729                         int width) = I422ToARGBRow_C;
730 #if defined(HAS_I422TOARGBROW_NEON)
731   if (TestCpuFlag(kCpuHasNEON)) {
732     I422ToARGBRow = I422ToARGBRow_Any_NEON;
733     if (IS_ALIGNED(width, 16)) {
734       I422ToARGBRow = I422ToARGBRow_NEON;
735     }
736   }
737 #elif defined(HAS_I422TOARGBROW_SSSE3)
738   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
739     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
740     if (IS_ALIGNED(width, 8) &&
741         IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
742       I422ToARGBRow = I422ToARGBRow_SSSE3;
743     }
744   }
745 #endif
746 
747   SIMD_ALIGNED(uint8 rowy[kMaxStride]);
748   SIMD_ALIGNED(uint8 rowu[kMaxStride]);
749   SIMD_ALIGNED(uint8 rowv[kMaxStride]);
750 
751   for (int y = 0; y < height; ++y) {
752     YUY2ToUV422Row(src_yuy2, rowu, rowv, width);
753     YUY2ToYRow(src_yuy2, rowy, width);
754     I422ToARGBRow(rowy, rowu, rowv, dst_argb, width);
755     src_yuy2 += src_stride_yuy2;
756     dst_argb += dst_stride_argb;
757   }
758   return 0;
759 }
760 
761 // Convert UYVY to ARGB.
762 LIBYUV_API
UYVYToARGB(const uint8 * src_uyvy,int src_stride_uyvy,uint8 * dst_argb,int dst_stride_argb,int width,int height)763 int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy,
764                uint8* dst_argb, int dst_stride_argb,
765                int width, int height) {
766   if (!src_uyvy || !dst_argb ||
767       width <= 0 || height == 0) {
768     return -1;
769   }
770   // Negative height means invert the image.
771   if (height < 0) {
772     height = -height;
773     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
774     src_stride_uyvy = -src_stride_uyvy;
775   }
776   void (*UYVYToUV422Row)(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v,
777       int pix) = UYVYToUV422Row_C;
778   void (*UYVYToYRow)(const uint8* src_uyvy,
779                      uint8* dst_y, int pix) = UYVYToYRow_C;
780 #if defined(HAS_UYVYTOYROW_SSE2)
781   if (TestCpuFlag(kCpuHasSSE2)) {
782     if (width > 16) {
783       UYVYToUV422Row = UYVYToUV422Row_Any_SSE2;
784       UYVYToYRow = UYVYToYRow_Any_SSE2;
785     }
786     if (IS_ALIGNED(width, 16)) {
787       UYVYToUV422Row = UYVYToUV422Row_Unaligned_SSE2;
788       UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
789       if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
790         UYVYToUV422Row = UYVYToUV422Row_SSE2;
791         UYVYToYRow = UYVYToYRow_SSE2;
792       }
793     }
794   }
795 #endif
796   void (*I422ToARGBRow)(const uint8* y_buf,
797                         const uint8* u_buf,
798                         const uint8* v_buf,
799                         uint8* argb_buf,
800                         int width) = I422ToARGBRow_C;
801 #if defined(HAS_I422TOARGBROW_NEON)
802   if (TestCpuFlag(kCpuHasNEON)) {
803     I422ToARGBRow = I422ToARGBRow_Any_NEON;
804     if (IS_ALIGNED(width, 16)) {
805       I422ToARGBRow = I422ToARGBRow_NEON;
806     }
807   }
808 #elif defined(HAS_I422TOARGBROW_SSSE3)
809   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
810     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
811     if (IS_ALIGNED(width, 8) &&
812         IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
813       I422ToARGBRow = I422ToARGBRow_SSSE3;
814     }
815   }
816 #endif
817 
818   SIMD_ALIGNED(uint8 rowy[kMaxStride]);
819   SIMD_ALIGNED(uint8 rowu[kMaxStride]);
820   SIMD_ALIGNED(uint8 rowv[kMaxStride]);
821 
822   for (int y = 0; y < height; ++y) {
823     UYVYToUV422Row(src_uyvy, rowu, rowv, width);
824     UYVYToYRow(src_uyvy, rowy, width);
825     I422ToARGBRow(rowy, rowu, rowv, dst_argb, width);
826     src_uyvy += src_stride_uyvy;
827     dst_argb += dst_stride_argb;
828   }
829   return 0;
830 }
831 
832 #ifdef HAVE_JPEG
833 struct ARGBBuffers {
834   uint8* argb;
835   int argb_stride;
836   int w;
837   int h;
838 };
839 
JpegI420ToARGB(void * opaque,const uint8 * const * data,const int * strides,int rows)840 static void JpegI420ToARGB(void* opaque,
841                          const uint8* const* data,
842                          const int* strides,
843                          int rows) {
844   ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque);
845   I420ToARGB(data[0], strides[0],
846              data[1], strides[1],
847              data[2], strides[2],
848              dest->argb, dest->argb_stride,
849              dest->w, rows);
850   dest->argb += rows * dest->argb_stride;
851   dest->h -= rows;
852 }
853 
JpegI422ToARGB(void * opaque,const uint8 * const * data,const int * strides,int rows)854 static void JpegI422ToARGB(void* opaque,
855                            const uint8* const* data,
856                            const int* strides,
857                            int rows) {
858   ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque);
859   I422ToARGB(data[0], strides[0],
860              data[1], strides[1],
861              data[2], strides[2],
862              dest->argb, dest->argb_stride,
863              dest->w, rows);
864   dest->argb += rows * dest->argb_stride;
865   dest->h -= rows;
866 }
867 
JpegI444ToARGB(void * opaque,const uint8 * const * data,const int * strides,int rows)868 static void JpegI444ToARGB(void* opaque,
869                            const uint8* const* data,
870                            const int* strides,
871                            int rows) {
872   ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque);
873   I444ToARGB(data[0], strides[0],
874              data[1], strides[1],
875              data[2], strides[2],
876              dest->argb, dest->argb_stride,
877              dest->w, rows);
878   dest->argb += rows * dest->argb_stride;
879   dest->h -= rows;
880 }
881 
JpegI411ToARGB(void * opaque,const uint8 * const * data,const int * strides,int rows)882 static void JpegI411ToARGB(void* opaque,
883                            const uint8* const* data,
884                            const int* strides,
885                            int rows) {
886   ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque);
887   I411ToARGB(data[0], strides[0],
888              data[1], strides[1],
889              data[2], strides[2],
890              dest->argb, dest->argb_stride,
891              dest->w, rows);
892   dest->argb += rows * dest->argb_stride;
893   dest->h -= rows;
894 }
895 
JpegI400ToARGB(void * opaque,const uint8 * const * data,const int * strides,int rows)896 static void JpegI400ToARGB(void* opaque,
897                            const uint8* const* data,
898                            const int* strides,
899                            int rows) {
900   ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque);
901   I400ToARGB(data[0], strides[0],
902              dest->argb, dest->argb_stride,
903              dest->w, rows);
904   dest->argb += rows * dest->argb_stride;
905   dest->h -= rows;
906 }
907 
908 // MJPG (Motion JPeg) to ARGB
909 // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
910 LIBYUV_API
MJPGToARGB(const uint8 * sample,size_t sample_size,uint8 * argb,int argb_stride,int w,int h,int dw,int dh)911 int MJPGToARGB(const uint8* sample,
912                size_t sample_size,
913                uint8* argb, int argb_stride,
914                int w, int h,
915                int dw, int dh) {
916   if (sample_size == kUnknownDataSize) {
917     // ERROR: MJPEG frame size unknown
918     return -1;
919   }
920 
921   // TODO(fbarchard): Port to C
922   MJpegDecoder mjpeg_decoder;
923   bool ret = mjpeg_decoder.LoadFrame(sample, sample_size);
924   if (ret && (mjpeg_decoder.GetWidth() != w ||
925               mjpeg_decoder.GetHeight() != h)) {
926     // ERROR: MJPEG frame has unexpected dimensions
927     mjpeg_decoder.UnloadFrame();
928     return 1;  // runtime failure
929   }
930   if (ret) {
931     ARGBBuffers bufs = { argb, argb_stride, dw, dh };
932     // YUV420
933     if (mjpeg_decoder.GetColorSpace() ==
934             MJpegDecoder::kColorSpaceYCbCr &&
935         mjpeg_decoder.GetNumComponents() == 3 &&
936         mjpeg_decoder.GetVertSampFactor(0) == 2 &&
937         mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
938         mjpeg_decoder.GetVertSampFactor(1) == 1 &&
939         mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
940         mjpeg_decoder.GetVertSampFactor(2) == 1 &&
941         mjpeg_decoder.GetHorizSampFactor(2) == 1) {
942       ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh);
943     // YUV422
944     } else if (mjpeg_decoder.GetColorSpace() ==
945                    MJpegDecoder::kColorSpaceYCbCr &&
946                mjpeg_decoder.GetNumComponents() == 3 &&
947                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
948                mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
949                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
950                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
951                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
952                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
953       ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh);
954     // YUV444
955     } else if (mjpeg_decoder.GetColorSpace() ==
956                    MJpegDecoder::kColorSpaceYCbCr &&
957                mjpeg_decoder.GetNumComponents() == 3 &&
958                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
959                mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
960                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
961                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
962                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
963                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
964       ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh);
965     // YUV411
966     } else if (mjpeg_decoder.GetColorSpace() ==
967                    MJpegDecoder::kColorSpaceYCbCr &&
968                mjpeg_decoder.GetNumComponents() == 3 &&
969                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
970                mjpeg_decoder.GetHorizSampFactor(0) == 4 &&
971                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
972                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
973                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
974                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
975       ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToARGB, &bufs, dw, dh);
976     // YUV400
977     } else if (mjpeg_decoder.GetColorSpace() ==
978                    MJpegDecoder::kColorSpaceGrayscale &&
979                mjpeg_decoder.GetNumComponents() == 1 &&
980                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
981                mjpeg_decoder.GetHorizSampFactor(0) == 1) {
982       ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh);
983     } else {
984       // TODO(fbarchard): Implement conversion for any other colorspace/sample
985       // factors that occur in practice. 411 is supported by libjpeg
986       // ERROR: Unable to convert MJPEG frame because format is not supported
987       mjpeg_decoder.UnloadFrame();
988       return 1;
989     }
990   }
991   return 0;
992 }
993 #endif
994 
995 // Convert camera sample to I420 with cropping, rotation and vertical flip.
996 // src_width is used for source stride computation
997 // src_height is used to compute location of planes, and indicate inversion
998 // sample_size is measured in bytes and is the size of the frame.
999 //   With MJPEG it is the compressed size of the frame.
1000 LIBYUV_API
ConvertToARGB(const uint8 * sample,size_t sample_size,uint8 * dst_argb,int argb_stride,int crop_x,int crop_y,int src_width,int src_height,int dst_width,int dst_height,RotationMode rotation,uint32 format)1001 int ConvertToARGB(const uint8* sample, size_t sample_size,
1002                   uint8* dst_argb, int argb_stride,
1003                   int crop_x, int crop_y,
1004                   int src_width, int src_height,
1005                   int dst_width, int dst_height,
1006                   RotationMode rotation,
1007                   uint32 format) {
1008   if (dst_argb == NULL || sample == NULL ||
1009       src_width <= 0 || dst_width <= 0 ||
1010       src_height == 0 || dst_height == 0) {
1011     return -1;
1012   }
1013   int aligned_src_width = (src_width + 1) & ~1;
1014   const uint8* src;
1015   const uint8* src_uv;
1016   int abs_src_height = (src_height < 0) ? -src_height : src_height;
1017   int inv_dst_height = (dst_height < 0) ? -dst_height : dst_height;
1018   if (src_height < 0) {
1019     inv_dst_height = -inv_dst_height;
1020   }
1021   int r = 0;
1022 
1023   // One pass rotation is available for some formats. For the rest, convert
1024   // to I420 (with optional vertical flipping) into a temporary I420 buffer,
1025   // and then rotate the I420 to the final destination buffer.
1026   // For in-place conversion, if destination dst_argb is same as source sample,
1027   // also enable temporary buffer.
1028   bool need_buf = (rotation && format != FOURCC_ARGB) || dst_argb == sample;
1029   uint8* tmp_argb = dst_argb;
1030   int tmp_argb_stride = argb_stride;
1031   uint8* buf = NULL;
1032   int abs_dst_height = (dst_height < 0) ? -dst_height : dst_height;
1033   if (need_buf) {
1034     int argb_size = dst_width * abs_dst_height * 4;
1035     buf = new uint8[argb_size];
1036     if (!buf) {
1037       return 1;  // Out of memory runtime error.
1038     }
1039     dst_argb = buf;
1040     argb_stride = dst_width;
1041   }
1042 
1043   switch (format) {
1044     // Single plane formats
1045     case FOURCC_YUY2:
1046       src = sample + (aligned_src_width * crop_y + crop_x) * 2;
1047       r = YUY2ToARGB(src, aligned_src_width * 2,
1048                      dst_argb, argb_stride,
1049                      dst_width, inv_dst_height);
1050       break;
1051     case FOURCC_UYVY:
1052       src = sample + (aligned_src_width * crop_y + crop_x) * 2;
1053       r = UYVYToARGB(src, aligned_src_width * 2,
1054                      dst_argb, argb_stride,
1055                      dst_width, inv_dst_height);
1056       break;
1057 //    case FOURCC_V210:
1058       // stride is multiple of 48 pixels (128 bytes).
1059       // pixels come in groups of 6 = 16 bytes
1060 //      src = sample + (aligned_src_width + 47) / 48 * 128 * crop_y +
1061 //            crop_x / 6 * 16;
1062 //      r = V210ToARGB(src, (aligned_src_width + 47) / 48 * 128,
1063 //                     dst_argb, argb_stride,
1064 //                     dst_width, inv_dst_height);
1065 //      break;
1066     case FOURCC_24BG:
1067       src = sample + (src_width * crop_y + crop_x) * 3;
1068       r = RGB24ToARGB(src, src_width * 3,
1069                       dst_argb, argb_stride,
1070                       dst_width, inv_dst_height);
1071       break;
1072     case FOURCC_RAW:
1073       src = sample + (src_width * crop_y + crop_x) * 3;
1074       r = RAWToARGB(src, src_width * 3,
1075                     dst_argb, argb_stride,
1076                     dst_width, inv_dst_height);
1077       break;
1078     case FOURCC_ARGB:
1079       src = sample + (src_width * crop_y + crop_x) * 4;
1080       r = ARGBToARGB(src, src_width * 4,
1081                      dst_argb, argb_stride,
1082                      dst_width, inv_dst_height);
1083       break;
1084     case FOURCC_BGRA:
1085       src = sample + (src_width * crop_y + crop_x) * 4;
1086       r = BGRAToARGB(src, src_width * 4,
1087                      dst_argb, argb_stride,
1088                      dst_width, inv_dst_height);
1089       break;
1090     case FOURCC_ABGR:
1091       src = sample + (src_width * crop_y + crop_x) * 4;
1092       r = ABGRToARGB(src, src_width * 4,
1093                      dst_argb, argb_stride,
1094                      dst_width, inv_dst_height);
1095       break;
1096     case FOURCC_RGBA:
1097       src = sample + (src_width * crop_y + crop_x) * 4;
1098       r = RGBAToARGB(src, src_width * 4,
1099                      dst_argb, argb_stride,
1100                      dst_width, inv_dst_height);
1101       break;
1102     case FOURCC_RGBP:
1103       src = sample + (src_width * crop_y + crop_x) * 2;
1104       r = RGB565ToARGB(src, src_width * 2,
1105                        dst_argb, argb_stride,
1106                        dst_width, inv_dst_height);
1107       break;
1108     case FOURCC_RGBO:
1109       src = sample + (src_width * crop_y + crop_x) * 2;
1110       r = ARGB1555ToARGB(src, src_width * 2,
1111                          dst_argb, argb_stride,
1112                          dst_width, inv_dst_height);
1113       break;
1114     case FOURCC_R444:
1115       src = sample + (src_width * crop_y + crop_x) * 2;
1116       r = ARGB4444ToARGB(src, src_width * 2,
1117                          dst_argb, argb_stride,
1118                          dst_width, inv_dst_height);
1119       break;
1120     // TODO(fbarchard): Support cropping Bayer by odd numbers
1121     // by adjusting fourcc.
1122     case FOURCC_BGGR:
1123       src = sample + (src_width * crop_y + crop_x);
1124       r = BayerBGGRToARGB(src, src_width,
1125                           dst_argb, argb_stride,
1126                           dst_width, inv_dst_height);
1127       break;
1128 
1129     case FOURCC_GBRG:
1130       src = sample + (src_width * crop_y + crop_x);
1131       r = BayerGBRGToARGB(src, src_width,
1132                           dst_argb, argb_stride,
1133                           dst_width, inv_dst_height);
1134       break;
1135 
1136     case FOURCC_GRBG:
1137       src = sample + (src_width * crop_y + crop_x);
1138       r = BayerGRBGToARGB(src, src_width,
1139                           dst_argb, argb_stride,
1140                           dst_width, inv_dst_height);
1141       break;
1142 
1143     case FOURCC_RGGB:
1144       src = sample + (src_width * crop_y + crop_x);
1145       r = BayerRGGBToARGB(src, src_width,
1146                           dst_argb, argb_stride,
1147                           dst_width, inv_dst_height);
1148       break;
1149 
1150     case FOURCC_I400:
1151       src = sample + src_width * crop_y + crop_x;
1152       r = I400ToARGB(src, src_width,
1153                      dst_argb, argb_stride,
1154                      dst_width, inv_dst_height);
1155       break;
1156 
1157     // Biplanar formats
1158     case FOURCC_NV12:
1159       src = sample + (src_width * crop_y + crop_x);
1160       src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
1161       r = NV12ToARGB(src, src_width,
1162                      src_uv, aligned_src_width,
1163                      dst_argb, argb_stride,
1164                      dst_width, inv_dst_height);
1165       break;
1166     case FOURCC_NV21:
1167       src = sample + (src_width * crop_y + crop_x);
1168       src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
1169       // Call NV12 but with u and v parameters swapped.
1170       r = NV21ToARGB(src, src_width,
1171                      src_uv, aligned_src_width,
1172                      dst_argb, argb_stride,
1173                      dst_width, inv_dst_height);
1174       break;
1175     case FOURCC_M420:
1176       src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
1177       r = M420ToARGB(src, src_width,
1178                      dst_argb, argb_stride,
1179                      dst_width, inv_dst_height);
1180       break;
1181 //    case FOURCC_Q420:
1182 //      src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x;
1183 //      src_uv = sample + (src_width + aligned_src_width * 2) * crop_y +
1184 //               src_width + crop_x * 2;
1185 //      r = Q420ToARGB(src, src_width * 3,
1186 //                    src_uv, src_width * 3,
1187 //                    dst_argb, argb_stride,
1188 //                    dst_width, inv_dst_height);
1189 //      break;
1190     // Triplanar formats
1191     case FOURCC_I420:
1192     case FOURCC_YU12:
1193     case FOURCC_YV12: {
1194       const uint8* src_y = sample + (src_width * crop_y + crop_x);
1195       const uint8* src_u;
1196       const uint8* src_v;
1197       int halfwidth = (src_width + 1) / 2;
1198       int halfheight = (abs_src_height + 1) / 2;
1199       if (format == FOURCC_YV12) {
1200         src_v = sample + src_width * abs_src_height +
1201             (halfwidth * crop_y + crop_x) / 2;
1202         src_u = sample + src_width * abs_src_height +
1203             halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
1204       } else {
1205         src_u = sample + src_width * abs_src_height +
1206             (halfwidth * crop_y + crop_x) / 2;
1207         src_v = sample + src_width * abs_src_height +
1208             halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
1209       }
1210       r = I420ToARGB(src_y, src_width,
1211                      src_u, halfwidth,
1212                      src_v, halfwidth,
1213                      dst_argb, argb_stride,
1214                      dst_width, inv_dst_height);
1215       break;
1216     }
1217     case FOURCC_I422:
1218     case FOURCC_YV16: {
1219       const uint8* src_y = sample + src_width * crop_y + crop_x;
1220       const uint8* src_u;
1221       const uint8* src_v;
1222       int halfwidth = (src_width + 1) / 2;
1223       if (format == FOURCC_YV16) {
1224         src_v = sample + src_width * abs_src_height +
1225             halfwidth * crop_y + crop_x / 2;
1226         src_u = sample + src_width * abs_src_height +
1227             halfwidth * (abs_src_height + crop_y) + crop_x / 2;
1228       } else {
1229         src_u = sample + src_width * abs_src_height +
1230             halfwidth * crop_y + crop_x / 2;
1231         src_v = sample + src_width * abs_src_height +
1232             halfwidth * (abs_src_height + crop_y) + crop_x / 2;
1233       }
1234       r = I422ToARGB(src_y, src_width,
1235                      src_u, halfwidth,
1236                      src_v, halfwidth,
1237                      dst_argb, argb_stride,
1238                      dst_width, inv_dst_height);
1239       break;
1240     }
1241     case FOURCC_I444:
1242     case FOURCC_YV24: {
1243       const uint8* src_y = sample + src_width * crop_y + crop_x;
1244       const uint8* src_u;
1245       const uint8* src_v;
1246       if (format == FOURCC_YV24) {
1247         src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
1248         src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
1249       } else {
1250         src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
1251         src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
1252       }
1253       r = I444ToARGB(src_y, src_width,
1254                      src_u, src_width,
1255                      src_v, src_width,
1256                      dst_argb, argb_stride,
1257                      dst_width, inv_dst_height);
1258       break;
1259     }
1260     case FOURCC_I411: {
1261       int quarterwidth = (src_width + 3) / 4;
1262       const uint8* src_y = sample + src_width * crop_y + crop_x;
1263       const uint8* src_u = sample + src_width * abs_src_height +
1264           quarterwidth * crop_y + crop_x / 4;
1265       const uint8* src_v = sample + src_width * abs_src_height +
1266           quarterwidth * (abs_src_height + crop_y) + crop_x / 4;
1267       r = I411ToARGB(src_y, src_width,
1268                      src_u, quarterwidth,
1269                      src_v, quarterwidth,
1270                      dst_argb, argb_stride,
1271                      dst_width, inv_dst_height);
1272       break;
1273     }
1274 #ifdef HAVE_JPEG
1275     case FOURCC_MJPG:
1276       r = MJPGToARGB(sample, sample_size,
1277                      dst_argb, argb_stride,
1278                      src_width, abs_src_height, dst_width, inv_dst_height);
1279       break;
1280 #endif
1281     default:
1282       r = -1;  // unknown fourcc - return failure code.
1283   }
1284 
1285   if (need_buf) {
1286     if (!r) {
1287       r = ARGBRotate(dst_argb, argb_stride,
1288                      tmp_argb, tmp_argb_stride,
1289                      dst_width, abs_dst_height, rotation);
1290     }
1291     delete buf;
1292   }
1293 
1294   return r;
1295 }
1296 
1297 #ifdef __cplusplus
1298 }  // extern "C"
1299 }  // namespace libyuv
1300 #endif
1301