Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/media/libyuv/libyuv/source/convert.cc
Line
Count
Source (jump to first uncovered line)
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/planar_functions.h"
16
#include "libyuv/rotate.h"
17
#include "libyuv/row.h"
18
#include "libyuv/scale.h"  // For ScalePlane()
19
20
#ifdef __cplusplus
21
namespace libyuv {
22
extern "C" {
23
#endif
24
25
0
#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
26
0
static __inline int Abs(int v) {
27
0
  return v >= 0 ? v : -v;
28
0
}
29
30
// Any I4xx To I420 format with mirroring.
31
static int I4xxToI420(const uint8_t* src_y,
32
                      int src_stride_y,
33
                      const uint8_t* src_u,
34
                      int src_stride_u,
35
                      const uint8_t* src_v,
36
                      int src_stride_v,
37
                      uint8_t* dst_y,
38
                      int dst_stride_y,
39
                      uint8_t* dst_u,
40
                      int dst_stride_u,
41
                      uint8_t* dst_v,
42
                      int dst_stride_v,
43
                      int src_y_width,
44
                      int src_y_height,
45
                      int src_uv_width,
46
0
                      int src_uv_height) {
47
0
  const int dst_y_width = Abs(src_y_width);
48
0
  const int dst_y_height = Abs(src_y_height);
49
0
  const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
50
0
  const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
51
0
  if (src_uv_width == 0 || src_uv_height == 0) {
52
0
    return -1;
53
0
  }
54
0
  if (dst_y) {
55
0
    ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
56
0
               dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
57
0
  }
58
0
  ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
59
0
             dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
60
0
  ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
61
0
             dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
62
0
  return 0;
63
0
}
64
65
// Copy I420 with optional flipping.
66
// TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
67
// is does row coalescing.
68
LIBYUV_API
69
int I420Copy(const uint8_t* src_y,
70
             int src_stride_y,
71
             const uint8_t* src_u,
72
             int src_stride_u,
73
             const uint8_t* src_v,
74
             int src_stride_v,
75
             uint8_t* dst_y,
76
             int dst_stride_y,
77
             uint8_t* dst_u,
78
             int dst_stride_u,
79
             uint8_t* dst_v,
80
             int dst_stride_v,
81
             int width,
82
0
             int height) {
83
0
  int halfwidth = (width + 1) >> 1;
84
0
  int halfheight = (height + 1) >> 1;
85
0
  if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
86
0
    return -1;
87
0
  }
88
0
  // Negative height means invert the image.
89
0
  if (height < 0) {
90
0
    height = -height;
91
0
    halfheight = (height + 1) >> 1;
92
0
    src_y = src_y + (height - 1) * src_stride_y;
93
0
    src_u = src_u + (halfheight - 1) * src_stride_u;
94
0
    src_v = src_v + (halfheight - 1) * src_stride_v;
95
0
    src_stride_y = -src_stride_y;
96
0
    src_stride_u = -src_stride_u;
97
0
    src_stride_v = -src_stride_v;
98
0
  }
99
0
100
0
  if (dst_y) {
101
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
102
0
  }
103
0
  // Copy UV planes.
104
0
  CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
105
0
  CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
106
0
  return 0;
107
0
}
108
109
// Copy I010 with optional flipping.
110
LIBYUV_API
111
int I010Copy(const uint16_t* src_y,
112
             int src_stride_y,
113
             const uint16_t* src_u,
114
             int src_stride_u,
115
             const uint16_t* src_v,
116
             int src_stride_v,
117
             uint16_t* dst_y,
118
             int dst_stride_y,
119
             uint16_t* dst_u,
120
             int dst_stride_u,
121
             uint16_t* dst_v,
122
             int dst_stride_v,
123
             int width,
124
0
             int height) {
125
0
  int halfwidth = (width + 1) >> 1;
126
0
  int halfheight = (height + 1) >> 1;
127
0
  if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
128
0
    return -1;
129
0
  }
130
0
  // Negative height means invert the image.
131
0
  if (height < 0) {
132
0
    height = -height;
133
0
    halfheight = (height + 1) >> 1;
134
0
    src_y = src_y + (height - 1) * src_stride_y;
135
0
    src_u = src_u + (halfheight - 1) * src_stride_u;
136
0
    src_v = src_v + (halfheight - 1) * src_stride_v;
137
0
    src_stride_y = -src_stride_y;
138
0
    src_stride_u = -src_stride_u;
139
0
    src_stride_v = -src_stride_v;
140
0
  }
141
0
142
0
  if (dst_y) {
143
0
    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
144
0
  }
145
0
  // Copy UV planes.
146
0
  CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
147
0
  CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
148
0
  return 0;
149
0
}
150
151
// Convert 10 bit YUV to 8 bit.
152
LIBYUV_API
153
int I010ToI420(const uint16_t* src_y,
154
               int src_stride_y,
155
               const uint16_t* src_u,
156
               int src_stride_u,
157
               const uint16_t* src_v,
158
               int src_stride_v,
159
               uint8_t* dst_y,
160
               int dst_stride_y,
161
               uint8_t* dst_u,
162
               int dst_stride_u,
163
               uint8_t* dst_v,
164
               int dst_stride_v,
165
               int width,
166
0
               int height) {
167
0
  int halfwidth = (width + 1) >> 1;
168
0
  int halfheight = (height + 1) >> 1;
169
0
  if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
170
0
    return -1;
171
0
  }
172
0
  // Negative height means invert the image.
173
0
  if (height < 0) {
174
0
    height = -height;
175
0
    halfheight = (height + 1) >> 1;
176
0
    src_y = src_y + (height - 1) * src_stride_y;
177
0
    src_u = src_u + (halfheight - 1) * src_stride_u;
178
0
    src_v = src_v + (halfheight - 1) * src_stride_v;
179
0
    src_stride_y = -src_stride_y;
180
0
    src_stride_u = -src_stride_u;
181
0
    src_stride_v = -src_stride_v;
182
0
  }
183
0
184
0
  // Convert Y plane.
185
0
  Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, 16384, width,
186
0
                    height);
187
0
  // Convert UV planes.
188
0
  Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, 16384, halfwidth,
189
0
                    halfheight);
190
0
  Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, 16384, halfwidth,
191
0
                    halfheight);
192
0
  return 0;
193
0
}
194
195
// 422 chroma is 1/2 width, 1x height
196
// 420 chroma is 1/2 width, 1/2 height
197
LIBYUV_API
198
int I422ToI420(const uint8_t* src_y,
199
               int src_stride_y,
200
               const uint8_t* src_u,
201
               int src_stride_u,
202
               const uint8_t* src_v,
203
               int src_stride_v,
204
               uint8_t* dst_y,
205
               int dst_stride_y,
206
               uint8_t* dst_u,
207
               int dst_stride_u,
208
               uint8_t* dst_v,
209
               int dst_stride_v,
210
               int width,
211
0
               int height) {
212
0
  const int src_uv_width = SUBSAMPLE(width, 1, 1);
213
0
  return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
214
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
215
0
                    dst_v, dst_stride_v, width, height, src_uv_width, height);
216
0
}
217
218
// 444 chroma is 1x width, 1x height
219
// 420 chroma is 1/2 width, 1/2 height
220
LIBYUV_API
221
int I444ToI420(const uint8_t* src_y,
222
               int src_stride_y,
223
               const uint8_t* src_u,
224
               int src_stride_u,
225
               const uint8_t* src_v,
226
               int src_stride_v,
227
               uint8_t* dst_y,
228
               int dst_stride_y,
229
               uint8_t* dst_u,
230
               int dst_stride_u,
231
               uint8_t* dst_v,
232
               int dst_stride_v,
233
               int width,
234
0
               int height) {
235
0
  return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
236
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
237
0
                    dst_v, dst_stride_v, width, height, width, height);
238
0
}
239
240
// I400 is greyscale typically used in MJPG
241
LIBYUV_API
242
int I400ToI420(const uint8_t* src_y,
243
               int src_stride_y,
244
               uint8_t* dst_y,
245
               int dst_stride_y,
246
               uint8_t* dst_u,
247
               int dst_stride_u,
248
               uint8_t* dst_v,
249
               int dst_stride_v,
250
               int width,
251
0
               int height) {
252
0
  int halfwidth = (width + 1) >> 1;
253
0
  int halfheight = (height + 1) >> 1;
254
0
  if (!dst_u || !dst_v || width <= 0 || height == 0) {
255
0
    return -1;
256
0
  }
257
0
  // Negative height means invert the image.
258
0
  if (height < 0) {
259
0
    height = -height;
260
0
    halfheight = (height + 1) >> 1;
261
0
    src_y = src_y + (height - 1) * src_stride_y;
262
0
    src_stride_y = -src_stride_y;
263
0
  }
264
0
  if (dst_y) {
265
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
266
0
  }
267
0
  SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
268
0
  SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
269
0
  return 0;
270
0
}
271
272
static void CopyPlane2(const uint8_t* src,
273
                       int src_stride_0,
274
                       int src_stride_1,
275
                       uint8_t* dst,
276
                       int dst_stride,
277
                       int width,
278
0
                       int height) {
279
0
  int y;
280
0
  void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C;
281
0
#if defined(HAS_COPYROW_SSE2)
282
0
  if (TestCpuFlag(kCpuHasSSE2)) {
283
0
    CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
284
0
  }
285
0
#endif
286
0
#if defined(HAS_COPYROW_AVX)
287
0
  if (TestCpuFlag(kCpuHasAVX)) {
288
0
    CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
289
0
  }
290
0
#endif
291
0
#if defined(HAS_COPYROW_ERMS)
292
0
  if (TestCpuFlag(kCpuHasERMS)) {
293
0
    CopyRow = CopyRow_ERMS;
294
0
  }
295
0
#endif
296
#if defined(HAS_COPYROW_NEON)
297
  if (TestCpuFlag(kCpuHasNEON)) {
298
    CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
299
  }
300
#endif
301
302
0
  // Copy plane
303
0
  for (y = 0; y < height - 1; y += 2) {
304
0
    CopyRow(src, dst, width);
305
0
    CopyRow(src + src_stride_0, dst + dst_stride, width);
306
0
    src += src_stride_0 + src_stride_1;
307
0
    dst += dst_stride * 2;
308
0
  }
309
0
  if (height & 1) {
310
0
    CopyRow(src, dst, width);
311
0
  }
312
0
}
313
314
// Support converting from FOURCC_M420
315
// Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
316
// easy conversion to I420.
317
// M420 format description:
318
// M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
319
// Chroma is half width / half height. (420)
320
// src_stride_m420 is row planar. Normally this will be the width in pixels.
321
//   The UV plane is half width, but 2 values, so src_stride_m420 applies to
322
//   this as well as the two Y planes.
323
static int X420ToI420(const uint8_t* src_y,
324
                      int src_stride_y0,
325
                      int src_stride_y1,
326
                      const uint8_t* src_uv,
327
                      int src_stride_uv,
328
                      uint8_t* dst_y,
329
                      int dst_stride_y,
330
                      uint8_t* dst_u,
331
                      int dst_stride_u,
332
                      uint8_t* dst_v,
333
                      int dst_stride_v,
334
                      int width,
335
0
                      int height) {
336
0
  int halfwidth = (width + 1) >> 1;
337
0
  int halfheight = (height + 1) >> 1;
338
0
  if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) {
339
0
    return -1;
340
0
  }
341
0
  // Negative height means invert the image.
342
0
  if (height < 0) {
343
0
    height = -height;
344
0
    halfheight = (height + 1) >> 1;
345
0
    if (dst_y) {
346
0
      dst_y = dst_y + (height - 1) * dst_stride_y;
347
0
    }
348
0
    dst_u = dst_u + (halfheight - 1) * dst_stride_u;
349
0
    dst_v = dst_v + (halfheight - 1) * dst_stride_v;
350
0
    dst_stride_y = -dst_stride_y;
351
0
    dst_stride_u = -dst_stride_u;
352
0
    dst_stride_v = -dst_stride_v;
353
0
  }
354
0
  // Coalesce rows.
355
0
  if (src_stride_y0 == width && src_stride_y1 == width &&
356
0
      dst_stride_y == width) {
357
0
    width *= height;
358
0
    height = 1;
359
0
    src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
360
0
  }
361
0
  // Coalesce rows.
362
0
  if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
363
0
      dst_stride_v == halfwidth) {
364
0
    halfwidth *= halfheight;
365
0
    halfheight = 1;
366
0
    src_stride_uv = dst_stride_u = dst_stride_v = 0;
367
0
  }
368
0
369
0
  if (dst_y) {
370
0
    if (src_stride_y0 == src_stride_y1) {
371
0
      CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
372
0
    } else {
373
0
      CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
374
0
                 width, height);
375
0
    }
376
0
  }
377
0
378
0
  // Split UV plane - NV12 / NV21
379
0
  SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v,
380
0
               halfwidth, halfheight);
381
0
382
0
  return 0;
383
0
}
384
385
// Convert NV12 to I420.
386
LIBYUV_API
387
int NV12ToI420(const uint8_t* src_y,
388
               int src_stride_y,
389
               const uint8_t* src_uv,
390
               int src_stride_uv,
391
               uint8_t* dst_y,
392
               int dst_stride_y,
393
               uint8_t* dst_u,
394
               int dst_stride_u,
395
               uint8_t* dst_v,
396
               int dst_stride_v,
397
               int width,
398
0
               int height) {
399
0
  return X420ToI420(src_y, src_stride_y, src_stride_y, src_uv, src_stride_uv,
400
0
                    dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v,
401
0
                    dst_stride_v, width, height);
402
0
}
403
404
// Convert NV21 to I420.  Same as NV12 but u and v pointers swapped.
405
LIBYUV_API
406
int NV21ToI420(const uint8_t* src_y,
407
               int src_stride_y,
408
               const uint8_t* src_vu,
409
               int src_stride_vu,
410
               uint8_t* dst_y,
411
               int dst_stride_y,
412
               uint8_t* dst_u,
413
               int dst_stride_u,
414
               uint8_t* dst_v,
415
               int dst_stride_v,
416
               int width,
417
0
               int height) {
418
0
  return X420ToI420(src_y, src_stride_y, src_stride_y, src_vu, src_stride_vu,
419
0
                    dst_y, dst_stride_y, dst_v, dst_stride_v, dst_u,
420
0
                    dst_stride_u, width, height);
421
0
}
422
423
// Convert M420 to I420.
424
LIBYUV_API
425
int M420ToI420(const uint8_t* src_m420,
426
               int src_stride_m420,
427
               uint8_t* dst_y,
428
               int dst_stride_y,
429
               uint8_t* dst_u,
430
               int dst_stride_u,
431
               uint8_t* dst_v,
432
               int dst_stride_v,
433
               int width,
434
0
               int height) {
435
0
  return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
436
0
                    src_m420 + src_stride_m420 * 2, src_stride_m420 * 3, dst_y,
437
0
                    dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
438
0
                    width, height);
439
0
}
440
441
// Convert YUY2 to I420.
442
LIBYUV_API
443
int YUY2ToI420(const uint8_t* src_yuy2,
444
               int src_stride_yuy2,
445
               uint8_t* dst_y,
446
               int dst_stride_y,
447
               uint8_t* dst_u,
448
               int dst_stride_u,
449
               uint8_t* dst_v,
450
               int dst_stride_v,
451
               int width,
452
0
               int height) {
453
0
  int y;
454
0
  void (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2,
455
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
456
0
      YUY2ToUVRow_C;
457
0
  void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) =
458
0
      YUY2ToYRow_C;
459
0
  // Negative height means invert the image.
460
0
  if (height < 0) {
461
0
    height = -height;
462
0
    src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
463
0
    src_stride_yuy2 = -src_stride_yuy2;
464
0
  }
465
0
#if defined(HAS_YUY2TOYROW_SSE2)
466
0
  if (TestCpuFlag(kCpuHasSSE2)) {
467
0
    YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
468
0
    YUY2ToYRow = YUY2ToYRow_Any_SSE2;
469
0
    if (IS_ALIGNED(width, 16)) {
470
0
      YUY2ToUVRow = YUY2ToUVRow_SSE2;
471
0
      YUY2ToYRow = YUY2ToYRow_SSE2;
472
0
    }
473
0
  }
474
0
#endif
475
0
#if defined(HAS_YUY2TOYROW_AVX2)
476
0
  if (TestCpuFlag(kCpuHasAVX2)) {
477
0
    YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
478
0
    YUY2ToYRow = YUY2ToYRow_Any_AVX2;
479
0
    if (IS_ALIGNED(width, 32)) {
480
0
      YUY2ToUVRow = YUY2ToUVRow_AVX2;
481
0
      YUY2ToYRow = YUY2ToYRow_AVX2;
482
0
    }
483
0
  }
484
0
#endif
485
#if defined(HAS_YUY2TOYROW_NEON)
486
  if (TestCpuFlag(kCpuHasNEON)) {
487
    YUY2ToYRow = YUY2ToYRow_Any_NEON;
488
    YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
489
    if (IS_ALIGNED(width, 16)) {
490
      YUY2ToYRow = YUY2ToYRow_NEON;
491
      YUY2ToUVRow = YUY2ToUVRow_NEON;
492
    }
493
  }
494
#endif
495
#if defined(HAS_YUY2TOYROW_MSA)
496
  if (TestCpuFlag(kCpuHasMSA)) {
497
    YUY2ToYRow = YUY2ToYRow_Any_MSA;
498
    YUY2ToUVRow = YUY2ToUVRow_Any_MSA;
499
    if (IS_ALIGNED(width, 32)) {
500
      YUY2ToYRow = YUY2ToYRow_MSA;
501
      YUY2ToUVRow = YUY2ToUVRow_MSA;
502
    }
503
  }
504
#endif
505
506
0
  for (y = 0; y < height - 1; y += 2) {
507
0
    YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
508
0
    YUY2ToYRow(src_yuy2, dst_y, width);
509
0
    YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
510
0
    src_yuy2 += src_stride_yuy2 * 2;
511
0
    dst_y += dst_stride_y * 2;
512
0
    dst_u += dst_stride_u;
513
0
    dst_v += dst_stride_v;
514
0
  }
515
0
  if (height & 1) {
516
0
    YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
517
0
    YUY2ToYRow(src_yuy2, dst_y, width);
518
0
  }
519
0
  return 0;
520
0
}
521
522
// Convert UYVY to I420.
523
LIBYUV_API
524
int UYVYToI420(const uint8_t* src_uyvy,
525
               int src_stride_uyvy,
526
               uint8_t* dst_y,
527
               int dst_stride_y,
528
               uint8_t* dst_u,
529
               int dst_stride_u,
530
               uint8_t* dst_v,
531
               int dst_stride_v,
532
               int width,
533
0
               int height) {
534
0
  int y;
535
0
  void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy,
536
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
537
0
      UYVYToUVRow_C;
538
0
  void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) =
539
0
      UYVYToYRow_C;
540
0
  // Negative height means invert the image.
541
0
  if (height < 0) {
542
0
    height = -height;
543
0
    src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
544
0
    src_stride_uyvy = -src_stride_uyvy;
545
0
  }
546
0
#if defined(HAS_UYVYTOYROW_SSE2)
547
0
  if (TestCpuFlag(kCpuHasSSE2)) {
548
0
    UYVYToUVRow = UYVYToUVRow_Any_SSE2;
549
0
    UYVYToYRow = UYVYToYRow_Any_SSE2;
550
0
    if (IS_ALIGNED(width, 16)) {
551
0
      UYVYToUVRow = UYVYToUVRow_SSE2;
552
0
      UYVYToYRow = UYVYToYRow_SSE2;
553
0
    }
554
0
  }
555
0
#endif
556
0
#if defined(HAS_UYVYTOYROW_AVX2)
557
0
  if (TestCpuFlag(kCpuHasAVX2)) {
558
0
    UYVYToUVRow = UYVYToUVRow_Any_AVX2;
559
0
    UYVYToYRow = UYVYToYRow_Any_AVX2;
560
0
    if (IS_ALIGNED(width, 32)) {
561
0
      UYVYToUVRow = UYVYToUVRow_AVX2;
562
0
      UYVYToYRow = UYVYToYRow_AVX2;
563
0
    }
564
0
  }
565
0
#endif
566
#if defined(HAS_UYVYTOYROW_NEON)
567
  if (TestCpuFlag(kCpuHasNEON)) {
568
    UYVYToYRow = UYVYToYRow_Any_NEON;
569
    UYVYToUVRow = UYVYToUVRow_Any_NEON;
570
    if (IS_ALIGNED(width, 16)) {
571
      UYVYToYRow = UYVYToYRow_NEON;
572
      UYVYToUVRow = UYVYToUVRow_NEON;
573
    }
574
  }
575
#endif
576
#if defined(HAS_UYVYTOYROW_MSA)
577
  if (TestCpuFlag(kCpuHasMSA)) {
578
    UYVYToYRow = UYVYToYRow_Any_MSA;
579
    UYVYToUVRow = UYVYToUVRow_Any_MSA;
580
    if (IS_ALIGNED(width, 32)) {
581
      UYVYToYRow = UYVYToYRow_MSA;
582
      UYVYToUVRow = UYVYToUVRow_MSA;
583
    }
584
  }
585
#endif
586
587
0
  for (y = 0; y < height - 1; y += 2) {
588
0
    UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
589
0
    UYVYToYRow(src_uyvy, dst_y, width);
590
0
    UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
591
0
    src_uyvy += src_stride_uyvy * 2;
592
0
    dst_y += dst_stride_y * 2;
593
0
    dst_u += dst_stride_u;
594
0
    dst_v += dst_stride_v;
595
0
  }
596
0
  if (height & 1) {
597
0
    UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
598
0
    UYVYToYRow(src_uyvy, dst_y, width);
599
0
  }
600
0
  return 0;
601
0
}
602
603
// Convert ARGB to I420.
604
LIBYUV_API
605
int ARGBToI420(const uint8_t* src_argb,
606
               int src_stride_argb,
607
               uint8_t* dst_y,
608
               int dst_stride_y,
609
               uint8_t* dst_u,
610
               int dst_stride_u,
611
               uint8_t* dst_v,
612
               int dst_stride_v,
613
               int width,
614
0
               int height) {
615
0
  int y;
616
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
617
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
618
0
      ARGBToUVRow_C;
619
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
620
0
      ARGBToYRow_C;
621
0
  if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
622
0
    return -1;
623
0
  }
624
0
  // Negative height means invert the image.
625
0
  if (height < 0) {
626
0
    height = -height;
627
0
    src_argb = src_argb + (height - 1) * src_stride_argb;
628
0
    src_stride_argb = -src_stride_argb;
629
0
  }
630
0
#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
631
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
632
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
633
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
634
0
    if (IS_ALIGNED(width, 16)) {
635
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
636
0
      ARGBToYRow = ARGBToYRow_SSSE3;
637
0
    }
638
0
  }
639
0
#endif
640
0
#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
641
0
  if (TestCpuFlag(kCpuHasAVX2)) {
642
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
643
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
644
0
    if (IS_ALIGNED(width, 32)) {
645
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
646
0
      ARGBToYRow = ARGBToYRow_AVX2;
647
0
    }
648
0
  }
649
0
#endif
650
#if defined(HAS_ARGBTOYROW_NEON)
651
  if (TestCpuFlag(kCpuHasNEON)) {
652
    ARGBToYRow = ARGBToYRow_Any_NEON;
653
    if (IS_ALIGNED(width, 8)) {
654
      ARGBToYRow = ARGBToYRow_NEON;
655
    }
656
  }
657
#endif
658
#if defined(HAS_ARGBTOUVROW_NEON)
659
  if (TestCpuFlag(kCpuHasNEON)) {
660
    ARGBToUVRow = ARGBToUVRow_Any_NEON;
661
    if (IS_ALIGNED(width, 16)) {
662
      ARGBToUVRow = ARGBToUVRow_NEON;
663
    }
664
  }
665
#endif
666
#if defined(HAS_ARGBTOYROW_MSA)
667
  if (TestCpuFlag(kCpuHasMSA)) {
668
    ARGBToYRow = ARGBToYRow_Any_MSA;
669
    if (IS_ALIGNED(width, 16)) {
670
      ARGBToYRow = ARGBToYRow_MSA;
671
    }
672
  }
673
#endif
674
#if defined(HAS_ARGBTOUVROW_MSA)
675
  if (TestCpuFlag(kCpuHasMSA)) {
676
    ARGBToUVRow = ARGBToUVRow_Any_MSA;
677
    if (IS_ALIGNED(width, 32)) {
678
      ARGBToUVRow = ARGBToUVRow_MSA;
679
    }
680
  }
681
#endif
682
683
0
  for (y = 0; y < height - 1; y += 2) {
684
0
    ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
685
0
    ARGBToYRow(src_argb, dst_y, width);
686
0
    ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
687
0
    src_argb += src_stride_argb * 2;
688
0
    dst_y += dst_stride_y * 2;
689
0
    dst_u += dst_stride_u;
690
0
    dst_v += dst_stride_v;
691
0
  }
692
0
  if (height & 1) {
693
0
    ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
694
0
    ARGBToYRow(src_argb, dst_y, width);
695
0
  }
696
0
  return 0;
697
0
}
698
699
// Convert BGRA to I420.
700
LIBYUV_API
701
int BGRAToI420(const uint8_t* src_bgra,
702
               int src_stride_bgra,
703
               uint8_t* dst_y,
704
               int dst_stride_y,
705
               uint8_t* dst_u,
706
               int dst_stride_u,
707
               uint8_t* dst_v,
708
               int dst_stride_v,
709
               int width,
710
0
               int height) {
711
0
  int y;
712
0
  void (*BGRAToUVRow)(const uint8_t* src_bgra0, int src_stride_bgra,
713
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
714
0
      BGRAToUVRow_C;
715
0
  void (*BGRAToYRow)(const uint8_t* src_bgra, uint8_t* dst_y, int width) =
716
0
      BGRAToYRow_C;
717
0
  if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
718
0
    return -1;
719
0
  }
720
0
  // Negative height means invert the image.
721
0
  if (height < 0) {
722
0
    height = -height;
723
0
    src_bgra = src_bgra + (height - 1) * src_stride_bgra;
724
0
    src_stride_bgra = -src_stride_bgra;
725
0
  }
726
0
#if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3)
727
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
728
0
    BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
729
0
    BGRAToYRow = BGRAToYRow_Any_SSSE3;
730
0
    if (IS_ALIGNED(width, 16)) {
731
0
      BGRAToUVRow = BGRAToUVRow_SSSE3;
732
0
      BGRAToYRow = BGRAToYRow_SSSE3;
733
0
    }
734
0
  }
735
0
#endif
736
#if defined(HAS_BGRATOYROW_NEON)
737
  if (TestCpuFlag(kCpuHasNEON)) {
738
    BGRAToYRow = BGRAToYRow_Any_NEON;
739
    if (IS_ALIGNED(width, 8)) {
740
      BGRAToYRow = BGRAToYRow_NEON;
741
    }
742
  }
743
#endif
744
#if defined(HAS_BGRATOUVROW_NEON)
745
  if (TestCpuFlag(kCpuHasNEON)) {
746
    BGRAToUVRow = BGRAToUVRow_Any_NEON;
747
    if (IS_ALIGNED(width, 16)) {
748
      BGRAToUVRow = BGRAToUVRow_NEON;
749
    }
750
  }
751
#endif
752
#if defined(HAS_BGRATOYROW_MSA)
753
  if (TestCpuFlag(kCpuHasMSA)) {
754
    BGRAToYRow = BGRAToYRow_Any_MSA;
755
    if (IS_ALIGNED(width, 16)) {
756
      BGRAToYRow = BGRAToYRow_MSA;
757
    }
758
  }
759
#endif
760
#if defined(HAS_BGRATOUVROW_MSA)
761
  if (TestCpuFlag(kCpuHasMSA)) {
762
    BGRAToUVRow = BGRAToUVRow_Any_MSA;
763
    if (IS_ALIGNED(width, 16)) {
764
      BGRAToUVRow = BGRAToUVRow_MSA;
765
    }
766
  }
767
#endif
768
769
0
  for (y = 0; y < height - 1; y += 2) {
770
0
    BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
771
0
    BGRAToYRow(src_bgra, dst_y, width);
772
0
    BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
773
0
    src_bgra += src_stride_bgra * 2;
774
0
    dst_y += dst_stride_y * 2;
775
0
    dst_u += dst_stride_u;
776
0
    dst_v += dst_stride_v;
777
0
  }
778
0
  if (height & 1) {
779
0
    BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
780
0
    BGRAToYRow(src_bgra, dst_y, width);
781
0
  }
782
0
  return 0;
783
0
}
784
785
// Convert ABGR to I420.
786
LIBYUV_API
787
int ABGRToI420(const uint8_t* src_abgr,
788
               int src_stride_abgr,
789
               uint8_t* dst_y,
790
               int dst_stride_y,
791
               uint8_t* dst_u,
792
               int dst_stride_u,
793
               uint8_t* dst_v,
794
               int dst_stride_v,
795
               int width,
796
0
               int height) {
797
0
  int y;
798
0
  void (*ABGRToUVRow)(const uint8_t* src_abgr0, int src_stride_abgr,
799
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
800
0
      ABGRToUVRow_C;
801
0
  void (*ABGRToYRow)(const uint8_t* src_abgr, uint8_t* dst_y, int width) =
802
0
      ABGRToYRow_C;
803
0
  if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
804
0
    return -1;
805
0
  }
806
0
  // Negative height means invert the image.
807
0
  if (height < 0) {
808
0
    height = -height;
809
0
    src_abgr = src_abgr + (height - 1) * src_stride_abgr;
810
0
    src_stride_abgr = -src_stride_abgr;
811
0
  }
812
0
#if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3)
813
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
814
0
    ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
815
0
    ABGRToYRow = ABGRToYRow_Any_SSSE3;
816
0
    if (IS_ALIGNED(width, 16)) {
817
0
      ABGRToUVRow = ABGRToUVRow_SSSE3;
818
0
      ABGRToYRow = ABGRToYRow_SSSE3;
819
0
    }
820
0
  }
821
0
#endif
822
#if defined(HAS_ABGRTOYROW_NEON)
823
  if (TestCpuFlag(kCpuHasNEON)) {
824
    ABGRToYRow = ABGRToYRow_Any_NEON;
825
    if (IS_ALIGNED(width, 8)) {
826
      ABGRToYRow = ABGRToYRow_NEON;
827
    }
828
  }
829
#endif
830
#if defined(HAS_ABGRTOUVROW_NEON)
831
  if (TestCpuFlag(kCpuHasNEON)) {
832
    ABGRToUVRow = ABGRToUVRow_Any_NEON;
833
    if (IS_ALIGNED(width, 16)) {
834
      ABGRToUVRow = ABGRToUVRow_NEON;
835
    }
836
  }
837
#endif
838
#if defined(HAS_ABGRTOYROW_MSA)
839
  if (TestCpuFlag(kCpuHasMSA)) {
840
    ABGRToYRow = ABGRToYRow_Any_MSA;
841
    if (IS_ALIGNED(width, 16)) {
842
      ABGRToYRow = ABGRToYRow_MSA;
843
    }
844
  }
845
#endif
846
#if defined(HAS_ABGRTOUVROW_MSA)
847
  if (TestCpuFlag(kCpuHasMSA)) {
848
    ABGRToUVRow = ABGRToUVRow_Any_MSA;
849
    if (IS_ALIGNED(width, 16)) {
850
      ABGRToUVRow = ABGRToUVRow_MSA;
851
    }
852
  }
853
#endif
854
855
0
  for (y = 0; y < height - 1; y += 2) {
856
0
    ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
857
0
    ABGRToYRow(src_abgr, dst_y, width);
858
0
    ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
859
0
    src_abgr += src_stride_abgr * 2;
860
0
    dst_y += dst_stride_y * 2;
861
0
    dst_u += dst_stride_u;
862
0
    dst_v += dst_stride_v;
863
0
  }
864
0
  if (height & 1) {
865
0
    ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
866
0
    ABGRToYRow(src_abgr, dst_y, width);
867
0
  }
868
0
  return 0;
869
0
}
870
871
// Convert RGBA to I420.
872
LIBYUV_API
873
int RGBAToI420(const uint8_t* src_rgba,
874
               int src_stride_rgba,
875
               uint8_t* dst_y,
876
               int dst_stride_y,
877
               uint8_t* dst_u,
878
               int dst_stride_u,
879
               uint8_t* dst_v,
880
               int dst_stride_v,
881
               int width,
882
0
               int height) {
883
0
  int y;
884
0
  void (*RGBAToUVRow)(const uint8_t* src_rgba0, int src_stride_rgba,
885
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
886
0
      RGBAToUVRow_C;
887
0
  void (*RGBAToYRow)(const uint8_t* src_rgba, uint8_t* dst_y, int width) =
888
0
      RGBAToYRow_C;
889
0
  if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
890
0
    return -1;
891
0
  }
892
0
  // Negative height means invert the image.
893
0
  if (height < 0) {
894
0
    height = -height;
895
0
    src_rgba = src_rgba + (height - 1) * src_stride_rgba;
896
0
    src_stride_rgba = -src_stride_rgba;
897
0
  }
898
0
#if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3)
899
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
900
0
    RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
901
0
    RGBAToYRow = RGBAToYRow_Any_SSSE3;
902
0
    if (IS_ALIGNED(width, 16)) {
903
0
      RGBAToUVRow = RGBAToUVRow_SSSE3;
904
0
      RGBAToYRow = RGBAToYRow_SSSE3;
905
0
    }
906
0
  }
907
0
#endif
908
#if defined(HAS_RGBATOYROW_NEON)
909
  if (TestCpuFlag(kCpuHasNEON)) {
910
    RGBAToYRow = RGBAToYRow_Any_NEON;
911
    if (IS_ALIGNED(width, 8)) {
912
      RGBAToYRow = RGBAToYRow_NEON;
913
    }
914
  }
915
#endif
916
#if defined(HAS_RGBATOUVROW_NEON)
917
  if (TestCpuFlag(kCpuHasNEON)) {
918
    RGBAToUVRow = RGBAToUVRow_Any_NEON;
919
    if (IS_ALIGNED(width, 16)) {
920
      RGBAToUVRow = RGBAToUVRow_NEON;
921
    }
922
  }
923
#endif
924
#if defined(HAS_RGBATOYROW_MSA)
925
  if (TestCpuFlag(kCpuHasMSA)) {
926
    RGBAToYRow = RGBAToYRow_Any_MSA;
927
    if (IS_ALIGNED(width, 16)) {
928
      RGBAToYRow = RGBAToYRow_MSA;
929
    }
930
  }
931
#endif
932
#if defined(HAS_RGBATOUVROW_MSA)
933
  if (TestCpuFlag(kCpuHasMSA)) {
934
    RGBAToUVRow = RGBAToUVRow_Any_MSA;
935
    if (IS_ALIGNED(width, 16)) {
936
      RGBAToUVRow = RGBAToUVRow_MSA;
937
    }
938
  }
939
#endif
940
941
0
  for (y = 0; y < height - 1; y += 2) {
942
0
    RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
943
0
    RGBAToYRow(src_rgba, dst_y, width);
944
0
    RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
945
0
    src_rgba += src_stride_rgba * 2;
946
0
    dst_y += dst_stride_y * 2;
947
0
    dst_u += dst_stride_u;
948
0
    dst_v += dst_stride_v;
949
0
  }
950
0
  if (height & 1) {
951
0
    RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
952
0
    RGBAToYRow(src_rgba, dst_y, width);
953
0
  }
954
0
  return 0;
955
0
}
956
957
// Convert RGB24 to I420.
958
LIBYUV_API
959
int RGB24ToI420(const uint8_t* src_rgb24,
960
                int src_stride_rgb24,
961
                uint8_t* dst_y,
962
                int dst_stride_y,
963
                uint8_t* dst_u,
964
                int dst_stride_u,
965
                uint8_t* dst_v,
966
                int dst_stride_v,
967
                int width,
968
0
                int height) {
969
0
  int y;
970
#if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
971
  void (*RGB24ToUVRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
972
                       uint8_t* dst_u, uint8_t* dst_v, int width) =
973
      RGB24ToUVRow_C;
974
  void (*RGB24ToYRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
975
      RGB24ToYRow_C;
976
#else
977
  void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
978
0
      RGB24ToARGBRow_C;
979
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
980
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
981
0
      ARGBToUVRow_C;
982
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
983
0
      ARGBToYRow_C;
984
0
#endif
985
0
  if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
986
0
    return -1;
987
0
  }
988
0
  // Negative height means invert the image.
989
0
  if (height < 0) {
990
0
    height = -height;
991
0
    src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
992
0
    src_stride_rgb24 = -src_stride_rgb24;
993
0
  }
994
0
995
0
// Neon version does direct RGB24 to YUV.
996
#if defined(HAS_RGB24TOYROW_NEON)
997
  if (TestCpuFlag(kCpuHasNEON)) {
998
    RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
999
    RGB24ToYRow = RGB24ToYRow_Any_NEON;
1000
    if (IS_ALIGNED(width, 8)) {
1001
      RGB24ToYRow = RGB24ToYRow_NEON;
1002
      if (IS_ALIGNED(width, 16)) {
1003
        RGB24ToUVRow = RGB24ToUVRow_NEON;
1004
      }
1005
    }
1006
  }
1007
#elif defined(HAS_RGB24TOYROW_MSA)
1008
  if (TestCpuFlag(kCpuHasMSA)) {
1009
    RGB24ToUVRow = RGB24ToUVRow_Any_MSA;
1010
    RGB24ToYRow = RGB24ToYRow_Any_MSA;
1011
    if (IS_ALIGNED(width, 16)) {
1012
      RGB24ToYRow = RGB24ToYRow_MSA;
1013
      RGB24ToUVRow = RGB24ToUVRow_MSA;
1014
    }
1015
  }
1016
// Other platforms do intermediate conversion from RGB24 to ARGB.
1017
#else
1018
#if defined(HAS_RGB24TOARGBROW_SSSE3)
1019
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
1020
0
    RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
1021
0
    if (IS_ALIGNED(width, 16)) {
1022
0
      RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1023
0
    }
1024
0
  }
1025
0
#endif
1026
0
#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1027
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
1028
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1029
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
1030
0
    if (IS_ALIGNED(width, 16)) {
1031
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
1032
0
      ARGBToYRow = ARGBToYRow_SSSE3;
1033
0
    }
1034
0
  }
1035
0
#endif
1036
0
#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1037
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1038
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1039
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
1040
0
    if (IS_ALIGNED(width, 32)) {
1041
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
1042
0
      ARGBToYRow = ARGBToYRow_AVX2;
1043
0
    }
1044
0
  }
1045
0
#endif
1046
0
#endif
1047
0
1048
0
  {
1049
0
#if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1050
0
    // Allocate 2 rows of ARGB.
1051
0
    const int kRowSize = (width * 4 + 31) & ~31;
1052
0
    align_buffer_64(row, kRowSize * 2);
1053
0
#endif
1054
0
1055
0
    for (y = 0; y < height - 1; y += 2) {
1056
#if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1057
      RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
1058
      RGB24ToYRow(src_rgb24, dst_y, width);
1059
      RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
1060
#else
1061
      RGB24ToARGBRow(src_rgb24, row, width);
1062
0
      RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1063
0
      ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1064
0
      ARGBToYRow(row, dst_y, width);
1065
0
      ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1066
0
#endif
1067
0
      src_rgb24 += src_stride_rgb24 * 2;
1068
0
      dst_y += dst_stride_y * 2;
1069
0
      dst_u += dst_stride_u;
1070
0
      dst_v += dst_stride_v;
1071
0
    }
1072
0
    if (height & 1) {
1073
#if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1074
      RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
1075
      RGB24ToYRow(src_rgb24, dst_y, width);
1076
#else
1077
      RGB24ToARGBRow(src_rgb24, row, width);
1078
0
      ARGBToUVRow(row, 0, dst_u, dst_v, width);
1079
0
      ARGBToYRow(row, dst_y, width);
1080
0
#endif
1081
0
    }
1082
0
#if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1083
0
    free_aligned_buffer_64(row);
1084
0
#endif
1085
0
  }
1086
0
  return 0;
1087
0
}
1088
1089
// Convert RAW to I420.
1090
LIBYUV_API
1091
int RAWToI420(const uint8_t* src_raw,
1092
              int src_stride_raw,
1093
              uint8_t* dst_y,
1094
              int dst_stride_y,
1095
              uint8_t* dst_u,
1096
              int dst_stride_u,
1097
              uint8_t* dst_v,
1098
              int dst_stride_v,
1099
              int width,
1100
0
              int height) {
1101
0
  int y;
1102
#if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1103
  void (*RAWToUVRow)(const uint8_t* src_raw, int src_stride_raw, uint8_t* dst_u,
1104
                     uint8_t* dst_v, int width) = RAWToUVRow_C;
1105
  void (*RAWToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
1106
      RAWToYRow_C;
1107
#else
1108
  void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1109
0
      RAWToARGBRow_C;
1110
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1111
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
1112
0
      ARGBToUVRow_C;
1113
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1114
0
      ARGBToYRow_C;
1115
0
#endif
1116
0
  if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1117
0
    return -1;
1118
0
  }
1119
0
  // Negative height means invert the image.
1120
0
  if (height < 0) {
1121
0
    height = -height;
1122
0
    src_raw = src_raw + (height - 1) * src_stride_raw;
1123
0
    src_stride_raw = -src_stride_raw;
1124
0
  }
1125
0
1126
0
// Neon version does direct RAW to YUV.
1127
#if defined(HAS_RAWTOYROW_NEON)
1128
  if (TestCpuFlag(kCpuHasNEON)) {
1129
    RAWToUVRow = RAWToUVRow_Any_NEON;
1130
    RAWToYRow = RAWToYRow_Any_NEON;
1131
    if (IS_ALIGNED(width, 8)) {
1132
      RAWToYRow = RAWToYRow_NEON;
1133
      if (IS_ALIGNED(width, 16)) {
1134
        RAWToUVRow = RAWToUVRow_NEON;
1135
      }
1136
    }
1137
  }
1138
#elif defined(HAS_RAWTOYROW_MSA)
1139
  if (TestCpuFlag(kCpuHasMSA)) {
1140
    RAWToUVRow = RAWToUVRow_Any_MSA;
1141
    RAWToYRow = RAWToYRow_Any_MSA;
1142
    if (IS_ALIGNED(width, 16)) {
1143
      RAWToYRow = RAWToYRow_MSA;
1144
      RAWToUVRow = RAWToUVRow_MSA;
1145
    }
1146
  }
1147
// Other platforms do intermediate conversion from RAW to ARGB.
1148
#else
1149
#if defined(HAS_RAWTOARGBROW_SSSE3)
1150
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
1151
0
    RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1152
0
    if (IS_ALIGNED(width, 16)) {
1153
0
      RAWToARGBRow = RAWToARGBRow_SSSE3;
1154
0
    }
1155
0
  }
1156
0
#endif
1157
0
#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1158
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
1159
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1160
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
1161
0
    if (IS_ALIGNED(width, 16)) {
1162
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
1163
0
      ARGBToYRow = ARGBToYRow_SSSE3;
1164
0
    }
1165
0
  }
1166
0
#endif
1167
0
#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1168
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1169
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1170
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
1171
0
    if (IS_ALIGNED(width, 32)) {
1172
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
1173
0
      ARGBToYRow = ARGBToYRow_AVX2;
1174
0
    }
1175
0
  }
1176
0
#endif
1177
0
#endif
1178
0
1179
0
  {
1180
0
#if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1181
0
    // Allocate 2 rows of ARGB.
1182
0
    const int kRowSize = (width * 4 + 31) & ~31;
1183
0
    align_buffer_64(row, kRowSize * 2);
1184
0
#endif
1185
0
1186
0
    for (y = 0; y < height - 1; y += 2) {
1187
#if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1188
      RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
1189
      RAWToYRow(src_raw, dst_y, width);
1190
      RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
1191
#else
1192
      RAWToARGBRow(src_raw, row, width);
1193
0
      RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
1194
0
      ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1195
0
      ARGBToYRow(row, dst_y, width);
1196
0
      ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1197
0
#endif
1198
0
      src_raw += src_stride_raw * 2;
1199
0
      dst_y += dst_stride_y * 2;
1200
0
      dst_u += dst_stride_u;
1201
0
      dst_v += dst_stride_v;
1202
0
    }
1203
0
    if (height & 1) {
1204
#if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1205
      RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
1206
      RAWToYRow(src_raw, dst_y, width);
1207
#else
1208
      RAWToARGBRow(src_raw, row, width);
1209
0
      ARGBToUVRow(row, 0, dst_u, dst_v, width);
1210
0
      ARGBToYRow(row, dst_y, width);
1211
0
#endif
1212
0
    }
1213
0
#if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1214
0
    free_aligned_buffer_64(row);
1215
0
#endif
1216
0
  }
1217
0
  return 0;
1218
0
}
1219
1220
// Convert RGB565 to I420.
1221
LIBYUV_API
1222
int RGB565ToI420(const uint8_t* src_rgb565,
1223
                 int src_stride_rgb565,
1224
                 uint8_t* dst_y,
1225
                 int dst_stride_y,
1226
                 uint8_t* dst_u,
1227
                 int dst_stride_u,
1228
                 uint8_t* dst_v,
1229
                 int dst_stride_v,
1230
                 int width,
1231
0
                 int height) {
1232
0
  int y;
1233
#if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1234
  void (*RGB565ToUVRow)(const uint8_t* src_rgb565, int src_stride_rgb565,
1235
                        uint8_t* dst_u, uint8_t* dst_v, int width) =
1236
      RGB565ToUVRow_C;
1237
  void (*RGB565ToYRow)(const uint8_t* src_rgb565, uint8_t* dst_y, int width) =
1238
      RGB565ToYRow_C;
1239
#else
1240
  void (*RGB565ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
1241
0
                          int width) = RGB565ToARGBRow_C;
1242
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1243
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
1244
0
      ARGBToUVRow_C;
1245
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1246
0
      ARGBToYRow_C;
1247
0
#endif
1248
0
  if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1249
0
    return -1;
1250
0
  }
1251
0
  // Negative height means invert the image.
1252
0
  if (height < 0) {
1253
0
    height = -height;
1254
0
    src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1255
0
    src_stride_rgb565 = -src_stride_rgb565;
1256
0
  }
1257
0
1258
0
// Neon version does direct RGB565 to YUV.
1259
#if defined(HAS_RGB565TOYROW_NEON)
1260
  if (TestCpuFlag(kCpuHasNEON)) {
1261
    RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
1262
    RGB565ToYRow = RGB565ToYRow_Any_NEON;
1263
    if (IS_ALIGNED(width, 8)) {
1264
      RGB565ToYRow = RGB565ToYRow_NEON;
1265
      if (IS_ALIGNED(width, 16)) {
1266
        RGB565ToUVRow = RGB565ToUVRow_NEON;
1267
      }
1268
    }
1269
  }
1270
#elif defined(HAS_RGB565TOYROW_MSA)
1271
  if (TestCpuFlag(kCpuHasMSA)) {
1272
    RGB565ToUVRow = RGB565ToUVRow_Any_MSA;
1273
    RGB565ToYRow = RGB565ToYRow_Any_MSA;
1274
    if (IS_ALIGNED(width, 16)) {
1275
      RGB565ToYRow = RGB565ToYRow_MSA;
1276
      RGB565ToUVRow = RGB565ToUVRow_MSA;
1277
    }
1278
  }
1279
// Other platforms do intermediate conversion from RGB565 to ARGB.
1280
#else
1281
#if defined(HAS_RGB565TOARGBROW_SSE2)
1282
0
  if (TestCpuFlag(kCpuHasSSE2)) {
1283
0
    RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1284
0
    if (IS_ALIGNED(width, 8)) {
1285
0
      RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1286
0
    }
1287
0
  }
1288
0
#endif
1289
#if defined(HAS_RGB565TOARGBROW_AVX2)
1290
  if (TestCpuFlag(kCpuHasAVX2)) {
1291
    RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
1292
    if (IS_ALIGNED(width, 16)) {
1293
      RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
1294
    }
1295
  }
1296
#endif
1297
#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1298
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
1299
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1300
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
1301
0
    if (IS_ALIGNED(width, 16)) {
1302
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
1303
0
      ARGBToYRow = ARGBToYRow_SSSE3;
1304
0
    }
1305
0
  }
1306
0
#endif
1307
0
#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1308
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1309
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1310
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
1311
0
    if (IS_ALIGNED(width, 32)) {
1312
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
1313
0
      ARGBToYRow = ARGBToYRow_AVX2;
1314
0
    }
1315
0
  }
1316
0
#endif
1317
0
#endif
1318
0
  {
1319
0
#if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1320
0
    // Allocate 2 rows of ARGB.
1321
0
    const int kRowSize = (width * 4 + 31) & ~31;
1322
0
    align_buffer_64(row, kRowSize * 2);
1323
0
#endif
1324
0
    for (y = 0; y < height - 1; y += 2) {
1325
#if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1326
      RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
1327
      RGB565ToYRow(src_rgb565, dst_y, width);
1328
      RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
1329
#else
1330
      RGB565ToARGBRow(src_rgb565, row, width);
1331
0
      RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
1332
0
      ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1333
0
      ARGBToYRow(row, dst_y, width);
1334
0
      ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1335
0
#endif
1336
0
      src_rgb565 += src_stride_rgb565 * 2;
1337
0
      dst_y += dst_stride_y * 2;
1338
0
      dst_u += dst_stride_u;
1339
0
      dst_v += dst_stride_v;
1340
0
    }
1341
0
    if (height & 1) {
1342
#if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1343
      RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
1344
      RGB565ToYRow(src_rgb565, dst_y, width);
1345
#else
1346
      RGB565ToARGBRow(src_rgb565, row, width);
1347
0
      ARGBToUVRow(row, 0, dst_u, dst_v, width);
1348
0
      ARGBToYRow(row, dst_y, width);
1349
0
#endif
1350
0
    }
1351
0
#if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1352
0
    free_aligned_buffer_64(row);
1353
0
#endif
1354
0
  }
1355
0
  return 0;
1356
0
}
1357
1358
// Convert ARGB1555 to I420.
1359
LIBYUV_API
1360
int ARGB1555ToI420(const uint8_t* src_argb1555,
1361
                   int src_stride_argb1555,
1362
                   uint8_t* dst_y,
1363
                   int dst_stride_y,
1364
                   uint8_t* dst_u,
1365
                   int dst_stride_u,
1366
                   uint8_t* dst_v,
1367
                   int dst_stride_v,
1368
                   int width,
1369
0
                   int height) {
1370
0
  int y;
1371
#if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1372
  void (*ARGB1555ToUVRow)(const uint8_t* src_argb1555, int src_stride_argb1555,
1373
                          uint8_t* dst_u, uint8_t* dst_v, int width) =
1374
      ARGB1555ToUVRow_C;
1375
  void (*ARGB1555ToYRow)(const uint8_t* src_argb1555, uint8_t* dst_y,
1376
                         int width) = ARGB1555ToYRow_C;
1377
#else
1378
  void (*ARGB1555ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
1379
0
                            int width) = ARGB1555ToARGBRow_C;
1380
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1381
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
1382
0
      ARGBToUVRow_C;
1383
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1384
0
      ARGBToYRow_C;
1385
0
#endif
1386
0
  if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
1387
0
      height == 0) {
1388
0
    return -1;
1389
0
  }
1390
0
  // Negative height means invert the image.
1391
0
  if (height < 0) {
1392
0
    height = -height;
1393
0
    src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1394
0
    src_stride_argb1555 = -src_stride_argb1555;
1395
0
  }
1396
0
1397
0
// Neon version does direct ARGB1555 to YUV.
1398
#if defined(HAS_ARGB1555TOYROW_NEON)
1399
  if (TestCpuFlag(kCpuHasNEON)) {
1400
    ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
1401
    ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
1402
    if (IS_ALIGNED(width, 8)) {
1403
      ARGB1555ToYRow = ARGB1555ToYRow_NEON;
1404
      if (IS_ALIGNED(width, 16)) {
1405
        ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
1406
      }
1407
    }
1408
  }
1409
#elif defined(HAS_ARGB1555TOYROW_MSA)
1410
  if (TestCpuFlag(kCpuHasMSA)) {
1411
    ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA;
1412
    ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA;
1413
    if (IS_ALIGNED(width, 16)) {
1414
      ARGB1555ToYRow = ARGB1555ToYRow_MSA;
1415
      ARGB1555ToUVRow = ARGB1555ToUVRow_MSA;
1416
    }
1417
  }
1418
// Other platforms do intermediate conversion from ARGB1555 to ARGB.
1419
#else
1420
#if defined(HAS_ARGB1555TOARGBROW_SSE2)
1421
0
  if (TestCpuFlag(kCpuHasSSE2)) {
1422
0
    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1423
0
    if (IS_ALIGNED(width, 8)) {
1424
0
      ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1425
0
    }
1426
0
  }
1427
0
#endif
1428
#if defined(HAS_ARGB1555TOARGBROW_AVX2)
1429
  if (TestCpuFlag(kCpuHasAVX2)) {
1430
    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
1431
    if (IS_ALIGNED(width, 16)) {
1432
      ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
1433
    }
1434
  }
1435
#endif
1436
#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1437
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
1438
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1439
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
1440
0
    if (IS_ALIGNED(width, 16)) {
1441
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
1442
0
      ARGBToYRow = ARGBToYRow_SSSE3;
1443
0
    }
1444
0
  }
1445
0
#endif
1446
0
#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1447
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1448
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1449
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
1450
0
    if (IS_ALIGNED(width, 32)) {
1451
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
1452
0
      ARGBToYRow = ARGBToYRow_AVX2;
1453
0
    }
1454
0
  }
1455
0
#endif
1456
0
#endif
1457
0
  {
1458
0
#if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1459
0
    // Allocate 2 rows of ARGB.
1460
0
    const int kRowSize = (width * 4 + 31) & ~31;
1461
0
    align_buffer_64(row, kRowSize * 2);
1462
0
#endif
1463
0
1464
0
    for (y = 0; y < height - 1; y += 2) {
1465
#if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1466
      ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
1467
      ARGB1555ToYRow(src_argb1555, dst_y, width);
1468
      ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
1469
                     width);
1470
#else
1471
      ARGB1555ToARGBRow(src_argb1555, row, width);
1472
0
      ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
1473
0
                        width);
1474
0
      ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1475
0
      ARGBToYRow(row, dst_y, width);
1476
0
      ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1477
0
#endif
1478
0
      src_argb1555 += src_stride_argb1555 * 2;
1479
0
      dst_y += dst_stride_y * 2;
1480
0
      dst_u += dst_stride_u;
1481
0
      dst_v += dst_stride_v;
1482
0
    }
1483
0
    if (height & 1) {
1484
#if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1485
      ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
1486
      ARGB1555ToYRow(src_argb1555, dst_y, width);
1487
#else
1488
      ARGB1555ToARGBRow(src_argb1555, row, width);
1489
0
      ARGBToUVRow(row, 0, dst_u, dst_v, width);
1490
0
      ARGBToYRow(row, dst_y, width);
1491
0
#endif
1492
0
    }
1493
0
#if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1494
0
    free_aligned_buffer_64(row);
1495
0
#endif
1496
0
  }
1497
0
  return 0;
1498
0
}
1499
1500
// Convert ARGB4444 to I420.
1501
LIBYUV_API
1502
int ARGB4444ToI420(const uint8_t* src_argb4444,
1503
                   int src_stride_argb4444,
1504
                   uint8_t* dst_y,
1505
                   int dst_stride_y,
1506
                   uint8_t* dst_u,
1507
                   int dst_stride_u,
1508
                   uint8_t* dst_v,
1509
                   int dst_stride_v,
1510
                   int width,
1511
0
                   int height) {
1512
0
  int y;
1513
#if defined(HAS_ARGB4444TOYROW_NEON)
1514
  void (*ARGB4444ToUVRow)(const uint8_t* src_argb4444, int src_stride_argb4444,
1515
                          uint8_t* dst_u, uint8_t* dst_v, int width) =
1516
      ARGB4444ToUVRow_C;
1517
  void (*ARGB4444ToYRow)(const uint8_t* src_argb4444, uint8_t* dst_y,
1518
                         int width) = ARGB4444ToYRow_C;
1519
#else
1520
  void (*ARGB4444ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
1521
0
                            int width) = ARGB4444ToARGBRow_C;
1522
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1523
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
1524
0
      ARGBToUVRow_C;
1525
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1526
0
      ARGBToYRow_C;
1527
0
#endif
1528
0
  if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
1529
0
      height == 0) {
1530
0
    return -1;
1531
0
  }
1532
0
  // Negative height means invert the image.
1533
0
  if (height < 0) {
1534
0
    height = -height;
1535
0
    src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1536
0
    src_stride_argb4444 = -src_stride_argb4444;
1537
0
  }
1538
0
1539
0
// Neon version does direct ARGB4444 to YUV.
1540
#if defined(HAS_ARGB4444TOYROW_NEON)
1541
  if (TestCpuFlag(kCpuHasNEON)) {
1542
    ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
1543
    ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
1544
    if (IS_ALIGNED(width, 8)) {
1545
      ARGB4444ToYRow = ARGB4444ToYRow_NEON;
1546
      if (IS_ALIGNED(width, 16)) {
1547
        ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
1548
      }
1549
    }
1550
  }
1551
// Other platforms do intermediate conversion from ARGB4444 to ARGB.
1552
#else
1553
#if defined(HAS_ARGB4444TOARGBROW_SSE2)
1554
0
  if (TestCpuFlag(kCpuHasSSE2)) {
1555
0
    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1556
0
    if (IS_ALIGNED(width, 8)) {
1557
0
      ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1558
0
    }
1559
0
  }
1560
0
#endif
1561
#if defined(HAS_ARGB4444TOARGBROW_AVX2)
1562
  if (TestCpuFlag(kCpuHasAVX2)) {
1563
    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
1564
    if (IS_ALIGNED(width, 16)) {
1565
      ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
1566
    }
1567
  }
1568
#endif
1569
#if defined(HAS_ARGB4444TOARGBROW_MSA)
1570
  if (TestCpuFlag(kCpuHasMSA)) {
1571
    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
1572
    if (IS_ALIGNED(width, 16)) {
1573
      ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
1574
    }
1575
  }
1576
#endif
1577
#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1578
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
1579
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1580
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
1581
0
    if (IS_ALIGNED(width, 16)) {
1582
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
1583
0
      ARGBToYRow = ARGBToYRow_SSSE3;
1584
0
    }
1585
0
  }
1586
0
#endif
1587
0
#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1588
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1589
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1590
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
1591
0
    if (IS_ALIGNED(width, 32)) {
1592
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
1593
0
      ARGBToYRow = ARGBToYRow_AVX2;
1594
0
    }
1595
0
  }
1596
0
#endif
1597
#if defined(HAS_ARGBTOYROW_MSA)
1598
  if (TestCpuFlag(kCpuHasMSA)) {
1599
    ARGBToUVRow = ARGBToUVRow_Any_MSA;
1600
    ARGBToYRow = ARGBToYRow_Any_MSA;
1601
    if (IS_ALIGNED(width, 16)) {
1602
      ARGBToYRow = ARGBToYRow_MSA;
1603
      if (IS_ALIGNED(width, 32)) {
1604
        ARGBToUVRow = ARGBToUVRow_MSA;
1605
      }
1606
    }
1607
  }
1608
#endif
1609
#endif
1610
0
1611
0
  {
1612
0
#if !defined(HAS_ARGB4444TOYROW_NEON)
1613
0
    // Allocate 2 rows of ARGB.
1614
0
    const int kRowSize = (width * 4 + 31) & ~31;
1615
0
    align_buffer_64(row, kRowSize * 2);
1616
0
#endif
1617
0
1618
0
    for (y = 0; y < height - 1; y += 2) {
1619
#if defined(HAS_ARGB4444TOYROW_NEON)
1620
      ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
1621
      ARGB4444ToYRow(src_argb4444, dst_y, width);
1622
      ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
1623
                     width);
1624
#else
1625
      ARGB4444ToARGBRow(src_argb4444, row, width);
1626
0
      ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
1627
0
                        width);
1628
0
      ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1629
0
      ARGBToYRow(row, dst_y, width);
1630
0
      ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1631
0
#endif
1632
0
      src_argb4444 += src_stride_argb4444 * 2;
1633
0
      dst_y += dst_stride_y * 2;
1634
0
      dst_u += dst_stride_u;
1635
0
      dst_v += dst_stride_v;
1636
0
    }
1637
0
    if (height & 1) {
1638
#if defined(HAS_ARGB4444TOYROW_NEON)
1639
      ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
1640
      ARGB4444ToYRow(src_argb4444, dst_y, width);
1641
#else
1642
      ARGB4444ToARGBRow(src_argb4444, row, width);
1643
0
      ARGBToUVRow(row, 0, dst_u, dst_v, width);
1644
0
      ARGBToYRow(row, dst_y, width);
1645
0
#endif
1646
0
    }
1647
0
#if !defined(HAS_ARGB4444TOYROW_NEON)
1648
0
    free_aligned_buffer_64(row);
1649
0
#endif
1650
0
  }
1651
0
  return 0;
1652
0
}
1653
1654
static void SplitPixels(const uint8_t* src_u,
1655
                        int src_pixel_stride_uv,
1656
                        uint8_t* dst_u,
1657
0
                        int width) {
1658
0
  int i;
1659
0
  for (i = 0; i < width; ++i) {
1660
0
    *dst_u = *src_u;
1661
0
    ++dst_u;
1662
0
    src_u += src_pixel_stride_uv;
1663
0
  }
1664
0
}
1665
1666
// Convert Android420 to I420.
1667
LIBYUV_API
1668
int Android420ToI420(const uint8_t* src_y,
1669
                     int src_stride_y,
1670
                     const uint8_t* src_u,
1671
                     int src_stride_u,
1672
                     const uint8_t* src_v,
1673
                     int src_stride_v,
1674
                     int src_pixel_stride_uv,
1675
                     uint8_t* dst_y,
1676
                     int dst_stride_y,
1677
                     uint8_t* dst_u,
1678
                     int dst_stride_u,
1679
                     uint8_t* dst_v,
1680
                     int dst_stride_v,
1681
                     int width,
1682
0
                     int height) {
1683
0
  int y;
1684
0
  const ptrdiff_t vu_off = src_v - src_u;
1685
0
  int halfwidth = (width + 1) >> 1;
1686
0
  int halfheight = (height + 1) >> 1;
1687
0
  if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
1688
0
    return -1;
1689
0
  }
1690
0
  // Negative height means invert the image.
1691
0
  if (height < 0) {
1692
0
    height = -height;
1693
0
    halfheight = (height + 1) >> 1;
1694
0
    src_y = src_y + (height - 1) * src_stride_y;
1695
0
    src_u = src_u + (halfheight - 1) * src_stride_u;
1696
0
    src_v = src_v + (halfheight - 1) * src_stride_v;
1697
0
    src_stride_y = -src_stride_y;
1698
0
    src_stride_u = -src_stride_u;
1699
0
    src_stride_v = -src_stride_v;
1700
0
  }
1701
0
1702
0
  if (dst_y) {
1703
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1704
0
  }
1705
0
1706
0
  // Copy UV planes as is - I420
1707
0
  if (src_pixel_stride_uv == 1) {
1708
0
    CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
1709
0
    CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
1710
0
    return 0;
1711
0
    // Split UV planes - NV21
1712
0
  }
1713
0
  if (src_pixel_stride_uv == 2 && vu_off == -1 &&
1714
0
      src_stride_u == src_stride_v) {
1715
0
    SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u,
1716
0
                 halfwidth, halfheight);
1717
0
    return 0;
1718
0
    // Split UV planes - NV12
1719
0
  }
1720
0
  if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
1721
0
    SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v,
1722
0
                 halfwidth, halfheight);
1723
0
    return 0;
1724
0
  }
1725
0
1726
0
  for (y = 0; y < halfheight; ++y) {
1727
0
    SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth);
1728
0
    SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth);
1729
0
    src_u += src_stride_u;
1730
0
    src_v += src_stride_v;
1731
0
    dst_u += dst_stride_u;
1732
0
    dst_v += dst_stride_v;
1733
0
  }
1734
0
  return 0;
1735
0
}
1736
1737
#ifdef __cplusplus
1738
}  // extern "C"
1739
}  // namespace libyuv
1740
#endif