Coverage Report

Created: 2025-07-11 06:43

/src/libavif/ext/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
#include "libyuv/scale_row.h"  // For FixedDiv
20
#include "libyuv/scale_uv.h"   // For UVScale()
21
22
#ifdef __cplusplus
23
namespace libyuv {
24
extern "C" {
25
#endif
26
27
// Subsample amount uses a shift.
28
//   v is value
29
//   a is amount to add to round up
30
//   s is shift to subsample down
31
0
#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
32
0
static __inline int Abs(int v) {
33
0
  return v >= 0 ? v : -v;
34
0
}
35
36
// Any I4xx To I420 format
37
static int I4xxToI420(const uint8_t* src_y,
38
                      int src_stride_y,
39
                      const uint8_t* src_u,
40
                      int src_stride_u,
41
                      const uint8_t* src_v,
42
                      int src_stride_v,
43
                      uint8_t* dst_y,
44
                      int dst_stride_y,
45
                      uint8_t* dst_u,
46
                      int dst_stride_u,
47
                      uint8_t* dst_v,
48
                      int dst_stride_v,
49
                      int src_y_width,
50
                      int src_y_height,
51
                      int src_uv_width,
52
0
                      int src_uv_height) {
53
0
  const int dst_y_width = src_y_width;
54
0
  const int dst_y_height = Abs(src_y_height);
55
0
  const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
56
0
  const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
57
0
  int r;
58
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v ||
59
0
      src_y_width <= 0 || src_y_height == 0 || src_uv_width <= 0 ||
60
0
      src_uv_height == 0) {
61
0
    return -1;
62
0
  }
63
0
  if (dst_y) {
64
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, src_y_width,
65
0
              src_y_height);
66
0
  }
67
0
  r = ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
68
0
                 dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
69
0
  if (r != 0) {
70
0
    return r;
71
0
  }
72
0
  r = ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
73
0
                 dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
74
0
  return r;
75
0
}
76
77
// Copy I420 with optional vertical flipping using negative height.
78
LIBYUV_API
79
int I420Copy(const uint8_t* src_y,
80
             int src_stride_y,
81
             const uint8_t* src_u,
82
             int src_stride_u,
83
             const uint8_t* src_v,
84
             int src_stride_v,
85
             uint8_t* dst_y,
86
             int dst_stride_y,
87
             uint8_t* dst_u,
88
             int dst_stride_u,
89
             uint8_t* dst_v,
90
             int dst_stride_v,
91
             int width,
92
0
             int height) {
93
0
  int halfwidth = (width + 1) >> 1;
94
0
  int halfheight = (height + 1) >> 1;
95
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
96
0
      height == 0) {
97
0
    return -1;
98
0
  }
99
  // Negative height means invert the image.
100
0
  if (height < 0) {
101
0
    height = -height;
102
0
    halfheight = (height + 1) >> 1;
103
0
    src_y = src_y + (height - 1) * src_stride_y;
104
0
    src_u = src_u + (halfheight - 1) * src_stride_u;
105
0
    src_v = src_v + (halfheight - 1) * src_stride_v;
106
0
    src_stride_y = -src_stride_y;
107
0
    src_stride_u = -src_stride_u;
108
0
    src_stride_v = -src_stride_v;
109
0
  }
110
111
0
  if (dst_y) {
112
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
113
0
  }
114
  // Copy UV planes.
115
0
  CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
116
0
  CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
117
0
  return 0;
118
0
}
119
120
// Copy I010 with optional flipping.
121
LIBYUV_API
122
int I010Copy(const uint16_t* src_y,
123
             int src_stride_y,
124
             const uint16_t* src_u,
125
             int src_stride_u,
126
             const uint16_t* src_v,
127
             int src_stride_v,
128
             uint16_t* dst_y,
129
             int dst_stride_y,
130
             uint16_t* dst_u,
131
             int dst_stride_u,
132
             uint16_t* dst_v,
133
             int dst_stride_v,
134
             int width,
135
0
             int height) {
136
0
  int halfwidth = (width + 1) >> 1;
137
0
  int halfheight = (height + 1) >> 1;
138
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
139
0
      height == 0) {
140
0
    return -1;
141
0
  }
142
  // Negative height means invert the image.
143
0
  if (height < 0) {
144
0
    height = -height;
145
0
    halfheight = (height + 1) >> 1;
146
0
    src_y = src_y + (height - 1) * src_stride_y;
147
0
    src_u = src_u + (halfheight - 1) * src_stride_u;
148
0
    src_v = src_v + (halfheight - 1) * src_stride_v;
149
0
    src_stride_y = -src_stride_y;
150
0
    src_stride_u = -src_stride_u;
151
0
    src_stride_v = -src_stride_v;
152
0
  }
153
154
0
  if (dst_y) {
155
0
    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
156
0
  }
157
  // Copy UV planes.
158
0
  CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
159
0
  CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
160
0
  return 0;
161
0
}
162
163
static int Planar16bitTo8bit(const uint16_t* src_y,
164
                             int src_stride_y,
165
                             const uint16_t* src_u,
166
                             int src_stride_u,
167
                             const uint16_t* src_v,
168
                             int src_stride_v,
169
                             uint8_t* dst_y,
170
                             int dst_stride_y,
171
                             uint8_t* dst_u,
172
                             int dst_stride_u,
173
                             uint8_t* dst_v,
174
                             int dst_stride_v,
175
                             int width,
176
                             int height,
177
                             int subsample_x,
178
                             int subsample_y,
179
0
                             int depth) {
180
0
  int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
181
0
  int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
182
0
  int scale = 1 << (24 - depth);
183
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
184
0
      height == 0) {
185
0
    return -1;
186
0
  }
187
  // Negative height means invert the image.
188
0
  if (height < 0) {
189
0
    height = -height;
190
0
    uv_height = -uv_height;
191
0
    src_y = src_y + (height - 1) * src_stride_y;
192
0
    src_u = src_u + (uv_height - 1) * src_stride_u;
193
0
    src_v = src_v + (uv_height - 1) * src_stride_v;
194
0
    src_stride_y = -src_stride_y;
195
0
    src_stride_u = -src_stride_u;
196
0
    src_stride_v = -src_stride_v;
197
0
  }
198
199
  // Convert Y plane.
200
0
  if (dst_y) {
201
0
    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
202
0
                      height);
203
0
  }
204
  // Convert UV planes.
205
0
  Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, scale, uv_width,
206
0
                    uv_height);
207
0
  Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, scale, uv_width,
208
0
                    uv_height);
209
0
  return 0;
210
0
}
211
212
static int I41xToI420(const uint16_t* src_y,
213
                      int src_stride_y,
214
                      const uint16_t* src_u,
215
                      int src_stride_u,
216
                      const uint16_t* src_v,
217
                      int src_stride_v,
218
                      uint8_t* dst_y,
219
                      int dst_stride_y,
220
                      uint8_t* dst_u,
221
                      int dst_stride_u,
222
                      uint8_t* dst_v,
223
                      int dst_stride_v,
224
                      int width,
225
                      int height,
226
0
                      int depth) {
227
0
  const int scale = 1 << (24 - depth);
228
229
0
  if (width <= 0 || height == 0) {
230
0
    return -1;
231
0
  }
232
  // Negative height means invert the image.
233
0
  if (height < 0) {
234
0
    height = -height;
235
0
    src_y = src_y + (height - 1) * src_stride_y;
236
0
    src_u = src_u + (height - 1) * src_stride_u;
237
0
    src_v = src_v + (height - 1) * src_stride_v;
238
0
    src_stride_y = -src_stride_y;
239
0
    src_stride_u = -src_stride_u;
240
0
    src_stride_v = -src_stride_v;
241
0
  }
242
243
0
  {
244
0
    const int uv_width = SUBSAMPLE(width, 1, 1);
245
0
    const int uv_height = SUBSAMPLE(height, 1, 1);
246
247
0
    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
248
0
                      height);
249
0
    ScalePlaneDown2_16To8(width, height, uv_width, uv_height, src_stride_u,
250
0
                          dst_stride_u, src_u, dst_u, scale, kFilterBilinear);
251
0
    ScalePlaneDown2_16To8(width, height, uv_width, uv_height, src_stride_v,
252
0
                          dst_stride_v, src_v, dst_v, scale, kFilterBilinear);
253
0
  }
254
0
  return 0;
255
0
}
256
257
static int I21xToI420(const uint16_t* src_y,
258
                      int src_stride_y,
259
                      const uint16_t* src_u,
260
                      int src_stride_u,
261
                      const uint16_t* src_v,
262
                      int src_stride_v,
263
                      uint8_t* dst_y,
264
                      int dst_stride_y,
265
                      uint8_t* dst_u,
266
                      int dst_stride_u,
267
                      uint8_t* dst_v,
268
                      int dst_stride_v,
269
                      int width,
270
                      int height,
271
0
                      int depth) {
272
0
  const int scale = 1 << (24 - depth);
273
274
0
  if (width <= 0 || height == 0) {
275
0
    return -1;
276
0
  }
277
  // Negative height means invert the image.
278
0
  if (height < 0) {
279
0
    height = -height;
280
0
    src_y = src_y + (height - 1) * src_stride_y;
281
0
    src_u = src_u + (height - 1) * src_stride_u;
282
0
    src_v = src_v + (height - 1) * src_stride_v;
283
0
    src_stride_y = -src_stride_y;
284
0
    src_stride_u = -src_stride_u;
285
0
    src_stride_v = -src_stride_v;
286
0
  }
287
288
0
  {
289
0
    const int uv_width = SUBSAMPLE(width, 1, 1);
290
0
    const int uv_height = SUBSAMPLE(height, 1, 1);
291
0
    const int dy = FixedDiv(height, uv_height);
292
293
0
    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
294
0
                      height);
295
0
    ScalePlaneVertical_16To8(height, uv_width, uv_height, src_stride_u,
296
0
                             dst_stride_u, src_u, dst_u, 0, 32768, dy,
297
0
                             /*bpp=*/1, scale, kFilterBilinear);
298
0
    ScalePlaneVertical_16To8(height, uv_width, uv_height, src_stride_v,
299
0
                             dst_stride_v, src_v, dst_v, 0, 32768, dy,
300
0
                             /*bpp=*/1, scale, kFilterBilinear);
301
0
  }
302
0
  return 0;
303
0
}
304
305
// Convert 10 bit YUV to 8 bit.
306
LIBYUV_API
307
int I010ToI420(const uint16_t* src_y,
308
               int src_stride_y,
309
               const uint16_t* src_u,
310
               int src_stride_u,
311
               const uint16_t* src_v,
312
               int src_stride_v,
313
               uint8_t* dst_y,
314
               int dst_stride_y,
315
               uint8_t* dst_u,
316
               int dst_stride_u,
317
               uint8_t* dst_v,
318
               int dst_stride_v,
319
               int width,
320
0
               int height) {
321
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
322
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
323
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 1,
324
0
                           1, 10);
325
0
}
326
327
LIBYUV_API
328
int I210ToI420(const uint16_t* src_y,
329
               int src_stride_y,
330
               const uint16_t* src_u,
331
               int src_stride_u,
332
               const uint16_t* src_v,
333
               int src_stride_v,
334
               uint8_t* dst_y,
335
               int dst_stride_y,
336
               uint8_t* dst_u,
337
               int dst_stride_u,
338
               uint8_t* dst_v,
339
               int dst_stride_v,
340
               int width,
341
0
               int height) {
342
0
  return I21xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
343
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
344
0
                    dst_v, dst_stride_v, width, height, 10);
345
0
}
346
347
LIBYUV_API
348
int I210ToI422(const uint16_t* src_y,
349
               int src_stride_y,
350
               const uint16_t* src_u,
351
               int src_stride_u,
352
               const uint16_t* src_v,
353
               int src_stride_v,
354
               uint8_t* dst_y,
355
               int dst_stride_y,
356
               uint8_t* dst_u,
357
               int dst_stride_u,
358
               uint8_t* dst_v,
359
               int dst_stride_v,
360
               int width,
361
0
               int height) {
362
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
363
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
364
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 1,
365
0
                           0, 10);
366
0
}
367
368
LIBYUV_API
369
int I410ToI420(const uint16_t* src_y,
370
               int src_stride_y,
371
               const uint16_t* src_u,
372
               int src_stride_u,
373
               const uint16_t* src_v,
374
               int src_stride_v,
375
               uint8_t* dst_y,
376
               int dst_stride_y,
377
               uint8_t* dst_u,
378
               int dst_stride_u,
379
               uint8_t* dst_v,
380
               int dst_stride_v,
381
               int width,
382
0
               int height) {
383
0
  return I41xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
384
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
385
0
                    dst_v, dst_stride_v, width, height, 10);
386
0
}
387
388
LIBYUV_API
389
int I410ToI444(const uint16_t* src_y,
390
               int src_stride_y,
391
               const uint16_t* src_u,
392
               int src_stride_u,
393
               const uint16_t* src_v,
394
               int src_stride_v,
395
               uint8_t* dst_y,
396
               int dst_stride_y,
397
               uint8_t* dst_u,
398
               int dst_stride_u,
399
               uint8_t* dst_v,
400
               int dst_stride_v,
401
               int width,
402
0
               int height) {
403
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
404
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
405
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 0,
406
0
                           0, 10);
407
0
}
408
409
LIBYUV_API
410
int I012ToI420(const uint16_t* src_y,
411
               int src_stride_y,
412
               const uint16_t* src_u,
413
               int src_stride_u,
414
               const uint16_t* src_v,
415
               int src_stride_v,
416
               uint8_t* dst_y,
417
               int dst_stride_y,
418
               uint8_t* dst_u,
419
               int dst_stride_u,
420
               uint8_t* dst_v,
421
               int dst_stride_v,
422
               int width,
423
0
               int height) {
424
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
425
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
426
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 1,
427
0
                           1, 12);
428
0
}
429
430
LIBYUV_API
431
int I212ToI422(const uint16_t* src_y,
432
               int src_stride_y,
433
               const uint16_t* src_u,
434
               int src_stride_u,
435
               const uint16_t* src_v,
436
               int src_stride_v,
437
               uint8_t* dst_y,
438
               int dst_stride_y,
439
               uint8_t* dst_u,
440
               int dst_stride_u,
441
               uint8_t* dst_v,
442
               int dst_stride_v,
443
               int width,
444
0
               int height) {
445
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
446
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
447
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 1,
448
0
                           0, 12);
449
0
}
450
451
LIBYUV_API
452
int I212ToI420(const uint16_t* src_y,
453
               int src_stride_y,
454
               const uint16_t* src_u,
455
               int src_stride_u,
456
               const uint16_t* src_v,
457
               int src_stride_v,
458
               uint8_t* dst_y,
459
               int dst_stride_y,
460
               uint8_t* dst_u,
461
               int dst_stride_u,
462
               uint8_t* dst_v,
463
               int dst_stride_v,
464
               int width,
465
0
               int height) {
466
0
  return I21xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
467
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
468
0
                    dst_v, dst_stride_v, width, height, 12);
469
0
}
470
471
LIBYUV_API
472
int I412ToI444(const uint16_t* src_y,
473
               int src_stride_y,
474
               const uint16_t* src_u,
475
               int src_stride_u,
476
               const uint16_t* src_v,
477
               int src_stride_v,
478
               uint8_t* dst_y,
479
               int dst_stride_y,
480
               uint8_t* dst_u,
481
               int dst_stride_u,
482
               uint8_t* dst_v,
483
               int dst_stride_v,
484
               int width,
485
0
               int height) {
486
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
487
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
488
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 0,
489
0
                           0, 12);
490
0
}
491
492
LIBYUV_API
493
int I412ToI420(const uint16_t* src_y,
494
               int src_stride_y,
495
               const uint16_t* src_u,
496
               int src_stride_u,
497
               const uint16_t* src_v,
498
               int src_stride_v,
499
               uint8_t* dst_y,
500
               int dst_stride_y,
501
               uint8_t* dst_u,
502
               int dst_stride_u,
503
               uint8_t* dst_v,
504
               int dst_stride_v,
505
               int width,
506
0
               int height) {
507
0
  return I41xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
508
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
509
0
                    dst_v, dst_stride_v, width, height, 12);
510
0
}
511
512
// Any Ix10 To I010 format
513
static int Ix10ToI010(const uint16_t* src_y,
514
                      int src_stride_y,
515
                      const uint16_t* src_u,
516
                      int src_stride_u,
517
                      const uint16_t* src_v,
518
                      int src_stride_v,
519
                      uint16_t* dst_y,
520
                      int dst_stride_y,
521
                      uint16_t* dst_u,
522
                      int dst_stride_u,
523
                      uint16_t* dst_v,
524
                      int dst_stride_v,
525
                      int width,
526
                      int height,
527
                      int subsample_x,
528
0
                      int subsample_y) {
529
0
  const int dst_y_width = width;
530
0
  const int dst_y_height = Abs(height);
531
0
  const int src_uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
532
0
  const int src_uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
533
0
  const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
534
0
  const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
535
0
  int r;
536
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
537
0
      height == 0) {
538
0
    return -1;
539
0
  }
540
0
  if (dst_y) {
541
0
    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
542
0
  }
543
0
  r = ScalePlane_12(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
544
0
                    dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
545
0
  if (r != 0) {
546
0
    return r;
547
0
  }
548
0
  r = ScalePlane_12(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
549
0
                    dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
550
0
  return r;
551
0
}
552
553
LIBYUV_API
554
int I410ToI010(const uint16_t* src_y,
555
               int src_stride_y,
556
               const uint16_t* src_u,
557
               int src_stride_u,
558
               const uint16_t* src_v,
559
               int src_stride_v,
560
               uint16_t* dst_y,
561
               int dst_stride_y,
562
               uint16_t* dst_u,
563
               int dst_stride_u,
564
               uint16_t* dst_v,
565
               int dst_stride_v,
566
               int width,
567
0
               int height) {
568
0
  return Ix10ToI010(src_y, src_stride_y, src_u, src_stride_u, src_v,
569
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
570
0
                    dst_v, dst_stride_v, width, height, 0, 0);
571
0
}
572
573
LIBYUV_API
574
int I210ToI010(const uint16_t* src_y,
575
               int src_stride_y,
576
               const uint16_t* src_u,
577
               int src_stride_u,
578
               const uint16_t* src_v,
579
               int src_stride_v,
580
               uint16_t* dst_y,
581
               int dst_stride_y,
582
               uint16_t* dst_u,
583
               int dst_stride_u,
584
               uint16_t* dst_v,
585
               int dst_stride_v,
586
               int width,
587
0
               int height) {
588
0
  return Ix10ToI010(src_y, src_stride_y, src_u, src_stride_u, src_v,
589
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
590
0
                    dst_v, dst_stride_v, width, height, 1, 0);
591
0
}
592
593
// Any I[420]1[02] to P[420]1[02] format
594
static int IxxxToPxxx(const uint16_t* src_y,
595
                      int src_stride_y,
596
                      const uint16_t* src_u,
597
                      int src_stride_u,
598
                      const uint16_t* src_v,
599
                      int src_stride_v,
600
                      uint16_t* dst_y,
601
                      int dst_stride_y,
602
                      uint16_t* dst_uv,
603
                      int dst_stride_uv,
604
                      int width,
605
                      int height,
606
                      int subsample_x,
607
                      int subsample_y,
608
0
                      int depth) {
609
0
  const int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
610
0
  const int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
611
0
  if (width <= 0 || height == 0) {
612
0
    return -1;
613
0
  }
614
615
0
  ConvertToMSBPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
616
0
                       depth);
617
0
  MergeUVPlane_16(src_u, src_stride_u, src_v, src_stride_v, dst_uv,
618
0
                  dst_stride_uv, uv_width, uv_height, depth);
619
0
  return 0;
620
0
}
621
622
LIBYUV_API
623
int I010ToP010(const uint16_t* src_y,
624
               int src_stride_y,
625
               const uint16_t* src_u,
626
               int src_stride_u,
627
               const uint16_t* src_v,
628
               int src_stride_v,
629
               uint16_t* dst_y,
630
               int dst_stride_y,
631
               uint16_t* dst_uv,
632
               int dst_stride_uv,
633
               int width,
634
0
               int height) {
635
0
  return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
636
0
                    src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
637
0
                    width, height, 1, 1, 10);
638
0
}
639
640
LIBYUV_API
641
int I010ToNV12(const uint16_t* src_y,
642
               int src_stride_y,
643
               const uint16_t* src_u,
644
               int src_stride_u,
645
               const uint16_t* src_v,
646
               int src_stride_v,
647
               uint8_t* dst_y,
648
               int dst_stride_y,
649
               uint8_t* dst_uv,
650
               int dst_stride_uv,
651
               int width,
652
0
               int height) {
653
0
  int y;
654
0
  int halfwidth = (width + 1) >> 1;
655
0
  int halfheight = (height + 1) >> 1;
656
0
  const int scale = 16385;  // 16384 for 10 bits
657
0
  void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale,
658
0
                          int width) = Convert16To8Row_C;
659
0
  void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
660
0
                     uint8_t* dst_uv, int width) = MergeUVRow_C;
661
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_uv || width <= 0 ||
662
0
      height == 0) {
663
0
    return -1;
664
0
  }
665
  // Negative height means invert the image.
666
0
  if (height < 0) {
667
0
    height = -height;
668
0
    halfheight = (height + 1) >> 1;
669
0
    src_y = src_y + (height - 1) * src_stride_y;
670
0
    src_u = src_u + (halfheight - 1) * src_stride_u;
671
0
    src_v = src_v + (halfheight - 1) * src_stride_v;
672
0
    src_stride_y = -src_stride_y;
673
0
    src_stride_u = -src_stride_u;
674
0
    src_stride_v = -src_stride_v;
675
0
  }
676
#if defined(HAS_CONVERT16TO8ROW_NEON)
677
  if (TestCpuFlag(kCpuHasNEON)) {
678
    Convert16To8Row = Convert16To8Row_Any_NEON;
679
    if (IS_ALIGNED(width, 16)) {
680
      Convert16To8Row = Convert16To8Row_NEON;
681
    }
682
  }
683
#endif
684
#if defined(HAS_CONVERT16TO8ROW_SME)
685
  if (TestCpuFlag(kCpuHasSME)) {
686
    Convert16To8Row = Convert16To8Row_SME;
687
  }
688
#endif
689
0
#if defined(HAS_CONVERT16TO8ROW_SSSE3)
690
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
691
0
    Convert16To8Row = Convert16To8Row_Any_SSSE3;
692
0
    if (IS_ALIGNED(width, 16)) {
693
0
      Convert16To8Row = Convert16To8Row_SSSE3;
694
0
    }
695
0
  }
696
0
#endif
697
0
#if defined(HAS_CONVERT16TO8ROW_AVX2)
698
0
  if (TestCpuFlag(kCpuHasAVX2)) {
699
0
    Convert16To8Row = Convert16To8Row_Any_AVX2;
700
0
    if (IS_ALIGNED(width, 32)) {
701
0
      Convert16To8Row = Convert16To8Row_AVX2;
702
0
    }
703
0
  }
704
0
#endif
705
0
#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
706
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
707
0
    Convert16To8Row = Convert16To8Row_Any_AVX512BW;
708
0
    if (IS_ALIGNED(width, 64)) {
709
0
      Convert16To8Row = Convert16To8Row_AVX512BW;
710
0
    }
711
0
  }
712
0
#endif
713
714
0
#if defined(HAS_MERGEUVROW_SSE2)
715
0
  if (TestCpuFlag(kCpuHasSSE2)) {
716
0
    MergeUVRow = MergeUVRow_Any_SSE2;
717
0
    if (IS_ALIGNED(halfwidth, 16)) {
718
0
      MergeUVRow = MergeUVRow_SSE2;
719
0
    }
720
0
  }
721
0
#endif
722
0
#if defined(HAS_MERGEUVROW_AVX2)
723
0
  if (TestCpuFlag(kCpuHasAVX2)) {
724
0
    MergeUVRow = MergeUVRow_Any_AVX2;
725
0
    if (IS_ALIGNED(halfwidth, 16)) {
726
0
      MergeUVRow = MergeUVRow_AVX2;
727
0
    }
728
0
  }
729
0
#endif
730
0
#if defined(HAS_MERGEUVROW_AVX512BW)
731
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
732
0
    MergeUVRow = MergeUVRow_Any_AVX512BW;
733
0
    if (IS_ALIGNED(halfwidth, 32)) {
734
0
      MergeUVRow = MergeUVRow_AVX512BW;
735
0
    }
736
0
  }
737
0
#endif
738
#if defined(HAS_MERGEUVROW_NEON)
739
  if (TestCpuFlag(kCpuHasNEON)) {
740
    MergeUVRow = MergeUVRow_Any_NEON;
741
    if (IS_ALIGNED(halfwidth, 16)) {
742
      MergeUVRow = MergeUVRow_NEON;
743
    }
744
  }
745
#endif
746
#if defined(HAS_MERGEUVROW_SME)
747
  if (TestCpuFlag(kCpuHasSME)) {
748
    MergeUVRow = MergeUVRow_SME;
749
  }
750
#endif
751
#if defined(HAS_MERGEUVROW_MSA)
752
  if (TestCpuFlag(kCpuHasMSA)) {
753
    MergeUVRow = MergeUVRow_Any_MSA;
754
    if (IS_ALIGNED(halfwidth, 16)) {
755
      MergeUVRow = MergeUVRow_MSA;
756
    }
757
  }
758
#endif
759
#if defined(HAS_MERGEUVROW_LSX)
760
  if (TestCpuFlag(kCpuHasLSX)) {
761
    MergeUVRow = MergeUVRow_Any_LSX;
762
    if (IS_ALIGNED(halfwidth, 16)) {
763
      MergeUVRow = MergeUVRow_LSX;
764
    }
765
  }
766
#endif
767
#if defined(HAS_MERGEUVROW_RVV)
768
  if (TestCpuFlag(kCpuHasRVV)) {
769
    MergeUVRow = MergeUVRow_RVV;
770
  }
771
#endif
772
773
  // Convert Y plane.
774
0
  if (dst_y) {
775
0
    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
776
0
                      height);
777
0
  }
778
779
0
  {
780
    // Allocate a row of uv.
781
0
    align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2);
782
0
    uint8_t* row_v = row_u + ((halfwidth + 31) & ~31);
783
0
    if (!row_u)
784
0
      return 1;
785
786
0
    for (y = 0; y < halfheight; ++y) {
787
0
      Convert16To8Row(src_u, row_u, scale, halfwidth);
788
0
      Convert16To8Row(src_v, row_v, scale, halfwidth);
789
0
      MergeUVRow(row_u, row_v, dst_uv, halfwidth);
790
0
      src_u += src_stride_u;
791
0
      src_v += src_stride_v;
792
0
      dst_uv += dst_stride_uv;
793
0
    }
794
0
    free_aligned_buffer_64(row_u);
795
0
  }
796
0
  return 0;
797
0
}
798
799
LIBYUV_API
800
int I210ToP210(const uint16_t* src_y,
801
               int src_stride_y,
802
               const uint16_t* src_u,
803
               int src_stride_u,
804
               const uint16_t* src_v,
805
               int src_stride_v,
806
               uint16_t* dst_y,
807
               int dst_stride_y,
808
               uint16_t* dst_uv,
809
               int dst_stride_uv,
810
               int width,
811
0
               int height) {
812
0
  return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
813
0
                    src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
814
0
                    width, height, 1, 0, 10);
815
0
}
816
817
LIBYUV_API
818
int I012ToP012(const uint16_t* src_y,
819
               int src_stride_y,
820
               const uint16_t* src_u,
821
               int src_stride_u,
822
               const uint16_t* src_v,
823
               int src_stride_v,
824
               uint16_t* dst_y,
825
               int dst_stride_y,
826
               uint16_t* dst_uv,
827
               int dst_stride_uv,
828
               int width,
829
0
               int height) {
830
0
  return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
831
0
                    src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
832
0
                    width, height, 1, 1, 12);
833
0
}
834
835
LIBYUV_API
836
int I212ToP212(const uint16_t* src_y,
837
               int src_stride_y,
838
               const uint16_t* src_u,
839
               int src_stride_u,
840
               const uint16_t* src_v,
841
               int src_stride_v,
842
               uint16_t* dst_y,
843
               int dst_stride_y,
844
               uint16_t* dst_uv,
845
               int dst_stride_uv,
846
               int width,
847
0
               int height) {
848
0
  return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
849
0
                    src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
850
0
                    width, height, 1, 0, 12);
851
0
}
852
853
// 422 chroma is 1/2 width, 1x height
854
// 420 chroma is 1/2 width, 1/2 height
855
LIBYUV_API
856
int I422ToI420(const uint8_t* src_y,
857
               int src_stride_y,
858
               const uint8_t* src_u,
859
               int src_stride_u,
860
               const uint8_t* src_v,
861
               int src_stride_v,
862
               uint8_t* dst_y,
863
               int dst_stride_y,
864
               uint8_t* dst_u,
865
               int dst_stride_u,
866
               uint8_t* dst_v,
867
               int dst_stride_v,
868
               int width,
869
0
               int height) {
870
0
  const int src_uv_width = SUBSAMPLE(width, 1, 1);
871
0
  return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
872
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
873
0
                    dst_v, dst_stride_v, width, height, src_uv_width, height);
874
0
}
875
876
LIBYUV_API
877
int I422ToI210(const uint8_t* src_y,
878
               int src_stride_y,
879
               const uint8_t* src_u,
880
               int src_stride_u,
881
               const uint8_t* src_v,
882
               int src_stride_v,
883
               uint16_t* dst_y,
884
               int dst_stride_y,
885
               uint16_t* dst_u,
886
               int dst_stride_u,
887
               uint16_t* dst_v,
888
               int dst_stride_v,
889
               int width,
890
0
               int height) {
891
0
  int halfwidth = (width + 1) >> 1;
892
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
893
0
      height == 0) {
894
0
    return -1;
895
0
  }
896
  // Negative height means invert the image.
897
0
  if (height < 0) {
898
0
    height = -height;
899
0
    src_y = src_y + (height - 1) * src_stride_y;
900
0
    src_u = src_u + (height - 1) * src_stride_u;
901
0
    src_v = src_v + (height - 1) * src_stride_v;
902
0
    src_stride_y = -src_stride_y;
903
0
    src_stride_u = -src_stride_u;
904
0
    src_stride_v = -src_stride_v;
905
0
  }
906
907
  // Convert Y plane.
908
0
  Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width,
909
0
                    height);
910
  // Convert UV planes.
911
0
  Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth,
912
0
                    height);
913
0
  Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth,
914
0
                    height);
915
0
  return 0;
916
0
}
917
918
// TODO(fbarchard): Implement row conversion.
919
LIBYUV_API
920
int I422ToNV21(const uint8_t* src_y,
921
               int src_stride_y,
922
               const uint8_t* src_u,
923
               int src_stride_u,
924
               const uint8_t* src_v,
925
               int src_stride_v,
926
               uint8_t* dst_y,
927
               int dst_stride_y,
928
               uint8_t* dst_vu,
929
               int dst_stride_vu,
930
               int width,
931
0
               int height) {
932
0
  int halfwidth = (width + 1) >> 1;
933
0
  int halfheight = (height + 1) >> 1;
934
  // Negative height means invert the image.
935
0
  if (height < 0) {
936
0
    height = -height;
937
0
    halfheight = (height + 1) >> 1;
938
0
    src_y = src_y + (height - 1) * src_stride_y;
939
0
    src_u = src_u + (height - 1) * src_stride_u;
940
0
    src_v = src_v + (height - 1) * src_stride_v;
941
0
    src_stride_y = -src_stride_y;
942
0
    src_stride_u = -src_stride_u;
943
0
    src_stride_v = -src_stride_v;
944
0
  }
945
946
  // Allocate u and v buffers
947
0
  align_buffer_64(plane_u, halfwidth * halfheight * 2);
948
0
  uint8_t* plane_v = plane_u + halfwidth * halfheight;
949
0
  if (!plane_u)
950
0
    return 1;
951
952
0
  I422ToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
953
0
             dst_y, dst_stride_y, plane_u, halfwidth, plane_v, halfwidth, width,
954
0
             height);
955
0
  MergeUVPlane(plane_v, halfwidth, plane_u, halfwidth, dst_vu, dst_stride_vu,
956
0
               halfwidth, halfheight);
957
0
  free_aligned_buffer_64(plane_u);
958
0
  return 0;
959
0
}
960
961
LIBYUV_API
962
int MM21ToNV12(const uint8_t* src_y,
963
               int src_stride_y,
964
               const uint8_t* src_uv,
965
               int src_stride_uv,
966
               uint8_t* dst_y,
967
               int dst_stride_y,
968
               uint8_t* dst_uv,
969
               int dst_stride_uv,
970
               int width,
971
0
               int height) {
972
0
  if (!src_uv || !dst_uv || width <= 0) {
973
0
    return -1;
974
0
  }
975
976
0
  int sign = height < 0 ? -1 : 1;
977
978
0
  if (dst_y) {
979
0
    DetilePlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height, 32);
980
0
  }
981
0
  DetilePlane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, (width + 1) & ~1,
982
0
              (height + sign) / 2, 16);
983
984
0
  return 0;
985
0
}
986
987
LIBYUV_API
988
int MM21ToI420(const uint8_t* src_y,
989
               int src_stride_y,
990
               const uint8_t* src_uv,
991
               int src_stride_uv,
992
               uint8_t* dst_y,
993
               int dst_stride_y,
994
               uint8_t* dst_u,
995
               int dst_stride_u,
996
               uint8_t* dst_v,
997
               int dst_stride_v,
998
               int width,
999
0
               int height) {
1000
0
  int sign = height < 0 ? -1 : 1;
1001
1002
0
  if (!src_uv || !dst_u || !dst_v || width <= 0) {
1003
0
    return -1;
1004
0
  }
1005
1006
0
  if (dst_y) {
1007
0
    DetilePlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height, 32);
1008
0
  }
1009
0
  DetileSplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
1010
0
                     dst_stride_v, (width + 1) & ~1, (height + sign) / 2, 16);
1011
1012
0
  return 0;
1013
0
}
1014
1015
LIBYUV_API
1016
int MM21ToYUY2(const uint8_t* src_y,
1017
               int src_stride_y,
1018
               const uint8_t* src_uv,
1019
               int src_stride_uv,
1020
               uint8_t* dst_yuy2,
1021
               int dst_stride_yuy2,
1022
               int width,
1023
0
               int height) {
1024
0
  if (!src_y || !src_uv || !dst_yuy2 || width <= 0) {
1025
0
    return -1;
1026
0
  }
1027
1028
0
  DetileToYUY2(src_y, src_stride_y, src_uv, src_stride_uv, dst_yuy2,
1029
0
               dst_stride_yuy2, width, height, 32);
1030
1031
0
  return 0;
1032
0
}
1033
1034
// Convert MT2T into P010. See tinyurl.com/mtk-10bit-video-format for format
1035
// documentation.
1036
// TODO(greenjustin): Add an MT2T to I420 conversion.
1037
LIBYUV_API
1038
int MT2TToP010(const uint8_t* src_y,
1039
               int src_stride_y,
1040
               const uint8_t* src_uv,
1041
               int src_stride_uv,
1042
               uint16_t* dst_y,
1043
               int dst_stride_y,
1044
               uint16_t* dst_uv,
1045
               int dst_stride_uv,
1046
               int width,
1047
0
               int height) {
1048
0
  if (width <= 0 || !height || !src_uv || !dst_uv) {
1049
0
    return -1;
1050
0
  }
1051
1052
0
  {
1053
0
    int uv_width = (width + 1) & ~1;
1054
0
    int uv_height = (height + 1) / 2;
1055
0
    int y = 0;
1056
0
    const int tile_width = 16;
1057
0
    const int y_tile_height = 32;
1058
0
    const int uv_tile_height = 16;
1059
0
    int padded_width = (width + tile_width - 1) & ~(tile_width - 1);
1060
0
    int y_tile_row_size = padded_width * y_tile_height * 10 / 8;
1061
0
    int uv_tile_row_size = padded_width * uv_tile_height * 10 / 8;
1062
0
    size_t row_buf_size = padded_width * y_tile_height * sizeof(uint16_t);
1063
0
    void (*UnpackMT2T)(const uint8_t* src, uint16_t* dst, size_t size) =
1064
0
        UnpackMT2T_C;
1065
0
    align_buffer_64(row_buf, row_buf_size);
1066
0
    if (!row_buf)
1067
0
      return 1;
1068
1069
#if defined(HAS_UNPACKMT2T_NEON)
1070
    if (TestCpuFlag(kCpuHasNEON)) {
1071
      UnpackMT2T = UnpackMT2T_NEON;
1072
    }
1073
#endif
1074
    // Negative height means invert the image.
1075
0
    if (height < 0) {
1076
0
      height = -height;
1077
0
      uv_height = (height + 1) / 2;
1078
0
      if (dst_y) {
1079
0
        dst_y = dst_y + (height - 1) * dst_stride_y;
1080
0
        dst_stride_y = -dst_stride_y;
1081
0
      }
1082
0
      dst_uv = dst_uv + (uv_height - 1) * dst_stride_uv;
1083
0
      dst_stride_uv = -dst_stride_uv;
1084
0
    }
1085
1086
    // Unpack and detile Y in rows of tiles
1087
0
    if (src_y && dst_y) {
1088
0
      for (y = 0; y < (height & ~(y_tile_height - 1)); y += y_tile_height) {
1089
0
        UnpackMT2T(src_y, (uint16_t*)row_buf, y_tile_row_size);
1090
0
        DetilePlane_16((uint16_t*)row_buf, padded_width, dst_y, dst_stride_y,
1091
0
                       width, y_tile_height, y_tile_height);
1092
0
        src_y += src_stride_y * y_tile_height;
1093
0
        dst_y += dst_stride_y * y_tile_height;
1094
0
      }
1095
0
      if (height & (y_tile_height - 1)) {
1096
0
        UnpackMT2T(src_y, (uint16_t*)row_buf, y_tile_row_size);
1097
0
        DetilePlane_16((uint16_t*)row_buf, padded_width, dst_y, dst_stride_y,
1098
0
                       width, height & (y_tile_height - 1), y_tile_height);
1099
0
      }
1100
0
    }
1101
1102
    // Unpack and detile UV plane
1103
0
    for (y = 0; y < (uv_height & ~(uv_tile_height - 1)); y += uv_tile_height) {
1104
0
      UnpackMT2T(src_uv, (uint16_t*)row_buf, uv_tile_row_size);
1105
0
      DetilePlane_16((uint16_t*)row_buf, padded_width, dst_uv, dst_stride_uv,
1106
0
                     uv_width, uv_tile_height, uv_tile_height);
1107
0
      src_uv += src_stride_uv * uv_tile_height;
1108
0
      dst_uv += dst_stride_uv * uv_tile_height;
1109
0
    }
1110
0
    if (uv_height & (uv_tile_height - 1)) {
1111
0
      UnpackMT2T(src_uv, (uint16_t*)row_buf, uv_tile_row_size);
1112
0
      DetilePlane_16((uint16_t*)row_buf, padded_width, dst_uv, dst_stride_uv,
1113
0
                     uv_width, uv_height & (uv_tile_height - 1),
1114
0
                     uv_tile_height);
1115
0
    }
1116
0
    free_aligned_buffer_64(row_buf);
1117
0
  }
1118
0
  return 0;
1119
0
}
1120
1121
#ifdef I422TONV21_ROW_VERSION
1122
// Unittest fails for this version.
1123
// 422 chroma is 1/2 width, 1x height
1124
// 420 chroma is 1/2 width, 1/2 height
1125
// Swap src_u and src_v to implement I422ToNV12
1126
LIBYUV_API
1127
int I422ToNV21(const uint8_t* src_y,
1128
               int src_stride_y,
1129
               const uint8_t* src_u,
1130
               int src_stride_u,
1131
               const uint8_t* src_v,
1132
               int src_stride_v,
1133
               uint8_t* dst_y,
1134
               int dst_stride_y,
1135
               uint8_t* dst_vu,
1136
               int dst_stride_vu,
1137
               int width,
1138
               int height) {
1139
  int y;
1140
  void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
1141
                     uint8_t* dst_uv, int width) = MergeUVRow_C;
1142
  void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr,
1143
                         ptrdiff_t src_stride, int dst_width,
1144
                         int source_y_fraction) = InterpolateRow_C;
1145
  int halfwidth = (width + 1) >> 1;
1146
  int halfheight = (height + 1) >> 1;
1147
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_vu || width <= 0 ||
1148
      height == 0) {
1149
    return -1;
1150
  }
1151
  // Negative height means invert the image.
1152
  if (height < 0) {
1153
    height = -height;
1154
    halfheight = (height + 1) >> 1;
1155
    src_y = src_y + (height - 1) * src_stride_y;
1156
    src_u = src_u + (halfheight - 1) * src_stride_u;
1157
    src_v = src_v + (halfheight - 1) * src_stride_v;
1158
    src_stride_y = -src_stride_y;
1159
    src_stride_u = -src_stride_u;
1160
    src_stride_v = -src_stride_v;
1161
  }
1162
#if defined(HAS_MERGEUVROW_SSE2)
1163
  if (TestCpuFlag(kCpuHasSSE2)) {
1164
    MergeUVRow = MergeUVRow_Any_SSE2;
1165
    if (IS_ALIGNED(halfwidth, 16)) {
1166
      MergeUVRow = MergeUVRow_SSE2;
1167
    }
1168
  }
1169
#endif
1170
#if defined(HAS_MERGEUVROW_AVX2)
1171
  if (TestCpuFlag(kCpuHasAVX2)) {
1172
    MergeUVRow = MergeUVRow_Any_AVX2;
1173
    if (IS_ALIGNED(halfwidth, 16)) {
1174
      MergeUVRow = MergeUVRow_AVX2;
1175
    }
1176
  }
1177
#endif
1178
#if defined(HAS_MERGEUVROW_AVX512BW)
1179
  if (TestCpuFlag(kCpuHasAVX512BW)) {
1180
    MergeUVRow = MergeUVRow_Any_AVX512BW;
1181
    if (IS_ALIGNED(halfwidth, 32)) {
1182
      MergeUVRow = MergeUVRow_AVX512BW;
1183
    }
1184
  }
1185
#endif
1186
#if defined(HAS_MERGEUVROW_NEON)
1187
  if (TestCpuFlag(kCpuHasNEON)) {
1188
    MergeUVRow = MergeUVRow_Any_NEON;
1189
    if (IS_ALIGNED(halfwidth, 16)) {
1190
      MergeUVRow = MergeUVRow_NEON;
1191
    }
1192
  }
1193
#endif
1194
#if defined(HAS_MERGEUVROW_SME)
1195
  if (TestCpuFlag(kCpuHasSME)) {
1196
    MergeUVRow = MergeUVRow_SME;
1197
  }
1198
#endif
1199
#if defined(HAS_MERGEUVROW_MSA)
1200
  if (TestCpuFlag(kCpuHasMSA)) {
1201
    MergeUVRow = MergeUVRow_Any_MSA;
1202
    if (IS_ALIGNED(halfwidth, 16)) {
1203
      MergeUVRow = MergeUVRow_MSA;
1204
    }
1205
  }
1206
#endif
1207
#if defined(HAS_MERGEUVROW_LSX)
1208
  if (TestCpuFlag(kCpuHasLSX)) {
1209
    MergeUVRow = MergeUVRow_Any_LSX;
1210
    if (IS_ALIGNED(halfwidth, 16)) {
1211
      MergeUVRow = MergeUVRow_LSX;
1212
    }
1213
  }
1214
#endif
1215
#if defined(HAS_MERGEUVROW_RVV)
1216
  if (TestCpuFlag(kCpuHasRVV)) {
1217
    MergeUVRow = MergeUVRow_RVV;
1218
  }
1219
#endif
1220
#if defined(HAS_INTERPOLATEROW_SSSE3)
1221
  if (TestCpuFlag(kCpuHasSSSE3)) {
1222
    InterpolateRow = InterpolateRow_Any_SSSE3;
1223
    if (IS_ALIGNED(width, 16)) {
1224
      InterpolateRow = InterpolateRow_SSSE3;
1225
    }
1226
  }
1227
#endif
1228
#if defined(HAS_INTERPOLATEROW_AVX2)
1229
  if (TestCpuFlag(kCpuHasAVX2)) {
1230
    InterpolateRow = InterpolateRow_Any_AVX2;
1231
    if (IS_ALIGNED(width, 32)) {
1232
      InterpolateRow = InterpolateRow_AVX2;
1233
    }
1234
  }
1235
#endif
1236
#if defined(HAS_INTERPOLATEROW_NEON)
1237
  if (TestCpuFlag(kCpuHasNEON)) {
1238
    InterpolateRow = InterpolateRow_Any_NEON;
1239
    if (IS_ALIGNED(width, 16)) {
1240
      InterpolateRow = InterpolateRow_NEON;
1241
    }
1242
  }
1243
#endif
1244
#if defined(HAS_INTERPOLATEROW_SME)
1245
  if (TestCpuFlag(kCpuHasSME)) {
1246
    InterpolateRow = InterpolateRow_SME;
1247
  }
1248
#endif
1249
#if defined(HAS_INTERPOLATEROW_MSA)
1250
  if (TestCpuFlag(kCpuHasMSA)) {
1251
    InterpolateRow = InterpolateRow_Any_MSA;
1252
    if (IS_ALIGNED(width, 32)) {
1253
      InterpolateRow = InterpolateRow_MSA;
1254
    }
1255
  }
1256
#endif
1257
#if defined(HAS_INTERPOLATEROW_LSX)
1258
  if (TestCpuFlag(kCpuHasLSX)) {
1259
    InterpolateRow = InterpolateRow_Any_LSX;
1260
    if (IS_ALIGNED(width, 32)) {
1261
      InterpolateRow = InterpolateRow_LSX;
1262
    }
1263
  }
1264
#endif
1265
#if defined(HAS_INTERPOLATEROW_RVV)
1266
  if (TestCpuFlag(kCpuHasRVV)) {
1267
    InterpolateRow = InterpolateRow_RVV;
1268
  }
1269
#endif
1270
1271
  if (dst_y) {
1272
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, halfwidth, height);
1273
  }
1274
  {
1275
    // Allocate 2 rows of vu.
1276
    int awidth = halfwidth * 2;
1277
    align_buffer_64(row_vu_0, awidth * 2);
1278
    uint8_t* row_vu_1 = row_vu_0 + awidth;
1279
    if (!row_vu_0)
1280
      return 1;
1281
1282
    for (y = 0; y < height - 1; y += 2) {
1283
      MergeUVRow(src_v, src_u, row_vu_0, halfwidth);
1284
      MergeUVRow(src_v + src_stride_v, src_u + src_stride_u, row_vu_1,
1285
                 halfwidth);
1286
      InterpolateRow(dst_vu, row_vu_0, awidth, awidth, 128);
1287
      src_u += src_stride_u * 2;
1288
      src_v += src_stride_v * 2;
1289
      dst_vu += dst_stride_vu;
1290
    }
1291
    if (height & 1) {
1292
      MergeUVRow(src_v, src_u, dst_vu, halfwidth);
1293
    }
1294
    free_aligned_buffer_64(row_vu_0);
1295
  }
1296
  return 0;
1297
}
1298
#endif  // I422TONV21_ROW_VERSION
1299
1300
// 444 chroma is 1x width, 1x height
1301
// 420 chroma is 1/2 width, 1/2 height
1302
LIBYUV_API
1303
int I444ToI420(const uint8_t* src_y,
1304
               int src_stride_y,
1305
               const uint8_t* src_u,
1306
               int src_stride_u,
1307
               const uint8_t* src_v,
1308
               int src_stride_v,
1309
               uint8_t* dst_y,
1310
               int dst_stride_y,
1311
               uint8_t* dst_u,
1312
               int dst_stride_u,
1313
               uint8_t* dst_v,
1314
               int dst_stride_v,
1315
               int width,
1316
0
               int height) {
1317
0
  return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
1318
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
1319
0
                    dst_v, dst_stride_v, width, height, width, height);
1320
0
}
1321
1322
LIBYUV_API
1323
int I444ToNV12(const uint8_t* src_y,
1324
               int src_stride_y,
1325
               const uint8_t* src_u,
1326
               int src_stride_u,
1327
               const uint8_t* src_v,
1328
               int src_stride_v,
1329
               uint8_t* dst_y,
1330
               int dst_stride_y,
1331
               uint8_t* dst_uv,
1332
               int dst_stride_uv,
1333
               int width,
1334
0
               int height) {
1335
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_uv || width <= 0 ||
1336
0
      height == 0) {
1337
0
    return -1;
1338
0
  }
1339
  // Negative height means invert the image.
1340
0
  if (height < 0) {
1341
0
    height = -height;
1342
0
    src_y = src_y + (height - 1) * src_stride_y;
1343
0
    src_u = src_u + (height - 1) * src_stride_u;
1344
0
    src_v = src_v + (height - 1) * src_stride_v;
1345
0
    src_stride_y = -src_stride_y;
1346
0
    src_stride_u = -src_stride_u;
1347
0
    src_stride_v = -src_stride_v;
1348
0
  }
1349
0
  if (dst_y) {
1350
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1351
0
  }
1352
0
  HalfMergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv,
1353
0
                   dst_stride_uv, width, height);
1354
0
  return 0;
1355
0
}
1356
1357
LIBYUV_API
1358
int I444ToNV21(const uint8_t* src_y,
1359
               int src_stride_y,
1360
               const uint8_t* src_u,
1361
               int src_stride_u,
1362
               const uint8_t* src_v,
1363
               int src_stride_v,
1364
               uint8_t* dst_y,
1365
               int dst_stride_y,
1366
               uint8_t* dst_vu,
1367
               int dst_stride_vu,
1368
               int width,
1369
0
               int height) {
1370
0
  return I444ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
1371
0
                    src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
1372
0
                    width, height);
1373
0
}
1374
1375
// I400 is greyscale typically used in MJPG
1376
LIBYUV_API
1377
int I400ToI420(const uint8_t* src_y,
1378
               int src_stride_y,
1379
               uint8_t* dst_y,
1380
               int dst_stride_y,
1381
               uint8_t* dst_u,
1382
               int dst_stride_u,
1383
               uint8_t* dst_v,
1384
               int dst_stride_v,
1385
               int width,
1386
0
               int height) {
1387
0
  int halfwidth = (width + 1) >> 1;
1388
0
  int halfheight = (height + 1) >> 1;
1389
0
  if ((!src_y && dst_y) || !dst_u || !dst_v || width <= 0 || height == 0) {
1390
0
    return -1;
1391
0
  }
1392
  // Negative height means invert the image.
1393
0
  if (height < 0) {
1394
0
    height = -height;
1395
0
    halfheight = (height + 1) >> 1;
1396
0
    src_y = src_y + (height - 1) * src_stride_y;
1397
0
    src_stride_y = -src_stride_y;
1398
0
  }
1399
0
  if (dst_y) {
1400
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1401
0
  }
1402
0
  SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
1403
0
  SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
1404
0
  return 0;
1405
0
}
1406
1407
// I400 is greyscale typically used in MJPG
1408
LIBYUV_API
1409
int I400ToNV21(const uint8_t* src_y,
1410
               int src_stride_y,
1411
               uint8_t* dst_y,
1412
               int dst_stride_y,
1413
               uint8_t* dst_vu,
1414
               int dst_stride_vu,
1415
               int width,
1416
0
               int height) {
1417
0
  int halfwidth = (width + 1) >> 1;
1418
0
  int halfheight = (height + 1) >> 1;
1419
0
  if ((!src_y && dst_y) || !dst_vu || width <= 0 || height == 0) {
1420
0
    return -1;
1421
0
  }
1422
  // Negative height means invert the image.
1423
0
  if (height < 0) {
1424
0
    height = -height;
1425
0
    halfheight = (height + 1) >> 1;
1426
0
    src_y = src_y + (height - 1) * src_stride_y;
1427
0
    src_stride_y = -src_stride_y;
1428
0
  }
1429
0
  if (dst_y) {
1430
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1431
0
  }
1432
0
  SetPlane(dst_vu, dst_stride_vu, halfwidth * 2, halfheight, 128);
1433
0
  return 0;
1434
0
}
1435
1436
// Convert NV12 to I420.
1437
// TODO(fbarchard): Consider inverting destination. Faster on ARM with prfm.
1438
LIBYUV_API
1439
int NV12ToI420(const uint8_t* src_y,
1440
               int src_stride_y,
1441
               const uint8_t* src_uv,
1442
               int src_stride_uv,
1443
               uint8_t* dst_y,
1444
               int dst_stride_y,
1445
               uint8_t* dst_u,
1446
               int dst_stride_u,
1447
               uint8_t* dst_v,
1448
               int dst_stride_v,
1449
               int width,
1450
0
               int height) {
1451
0
  int halfwidth = (width + 1) >> 1;
1452
0
  int halfheight = (height + 1) >> 1;
1453
0
  if ((!src_y && dst_y) || !src_uv || !dst_u || !dst_v || width <= 0 ||
1454
0
      height == 0) {
1455
0
    return -1;
1456
0
  }
1457
  // Negative height means invert the image.
1458
0
  if (height < 0) {
1459
0
    height = -height;
1460
0
    halfheight = (height + 1) >> 1;
1461
0
    src_y = src_y + (height - 1) * src_stride_y;
1462
0
    src_uv = src_uv + (halfheight - 1) * src_stride_uv;
1463
0
    src_stride_y = -src_stride_y;
1464
0
    src_stride_uv = -src_stride_uv;
1465
0
  }
1466
  // Coalesce rows.
1467
0
  if (src_stride_y == width && dst_stride_y == width) {
1468
0
    width *= height;
1469
0
    height = 1;
1470
0
    src_stride_y = dst_stride_y = 0;
1471
0
  }
1472
  // Coalesce rows.
1473
0
  if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
1474
0
      dst_stride_v == halfwidth) {
1475
0
    halfwidth *= halfheight;
1476
0
    halfheight = 1;
1477
0
    src_stride_uv = dst_stride_u = dst_stride_v = 0;
1478
0
  }
1479
1480
0
  if (dst_y) {
1481
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1482
0
  }
1483
1484
  // Split UV plane - NV12 / NV21
1485
0
  SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v,
1486
0
               halfwidth, halfheight);
1487
1488
0
  return 0;
1489
0
}
1490
1491
// Convert NV21 to I420.  Same as NV12 but u and v pointers swapped.
1492
LIBYUV_API
1493
int NV21ToI420(const uint8_t* src_y,
1494
               int src_stride_y,
1495
               const uint8_t* src_vu,
1496
               int src_stride_vu,
1497
               uint8_t* dst_y,
1498
               int dst_stride_y,
1499
               uint8_t* dst_u,
1500
               int dst_stride_u,
1501
               uint8_t* dst_v,
1502
               int dst_stride_v,
1503
               int width,
1504
0
               int height) {
1505
0
  return NV12ToI420(src_y, src_stride_y, src_vu, src_stride_vu, dst_y,
1506
0
                    dst_stride_y, dst_v, dst_stride_v, dst_u, dst_stride_u,
1507
0
                    width, height);
1508
0
}
1509
1510
LIBYUV_API
1511
int NV12ToNV24(const uint8_t* src_y,
1512
               int src_stride_y,
1513
               const uint8_t* src_uv,
1514
               int src_stride_uv,
1515
               uint8_t* dst_y,
1516
               int dst_stride_y,
1517
               uint8_t* dst_uv,
1518
               int dst_stride_uv,
1519
               int width,
1520
0
               int height) {
1521
0
  int r;
1522
0
  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
1523
0
    return -1;
1524
0
  }
1525
1526
0
  if (dst_y) {
1527
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1528
0
  }
1529
0
  r = UVScale(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1),
1530
0
              SUBSAMPLE(height, 1, 1), dst_uv, dst_stride_uv, Abs(width),
1531
0
              Abs(height), kFilterBilinear);
1532
0
  return r;
1533
0
}
1534
1535
LIBYUV_API
1536
int NV16ToNV24(const uint8_t* src_y,
1537
               int src_stride_y,
1538
               const uint8_t* src_uv,
1539
               int src_stride_uv,
1540
               uint8_t* dst_y,
1541
               int dst_stride_y,
1542
               uint8_t* dst_uv,
1543
               int dst_stride_uv,
1544
               int width,
1545
0
               int height) {
1546
0
  int r;
1547
0
  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
1548
0
    return -1;
1549
0
  }
1550
1551
0
  if (dst_y) {
1552
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1553
0
  }
1554
0
  r = UVScale(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1), height, dst_uv,
1555
0
              dst_stride_uv, Abs(width), Abs(height), kFilterBilinear);
1556
0
  return r;
1557
0
}
1558
1559
// Any P[420]1[02] to I[420]1[02] format
1560
static int PxxxToIxxx(const uint16_t* src_y,
1561
                      int src_stride_y,
1562
                      const uint16_t* src_uv,
1563
                      int src_stride_uv,
1564
                      uint16_t* dst_y,
1565
                      int dst_stride_y,
1566
                      uint16_t* dst_u,
1567
                      int dst_stride_u,
1568
                      uint16_t* dst_v,
1569
                      int dst_stride_v,
1570
                      int width,
1571
                      int height,
1572
                      int subsample_x,
1573
                      int subsample_y,
1574
0
                      int depth) {
1575
0
  const int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
1576
0
  const int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
1577
0
  if (!src_y || !dst_y || !src_uv || !dst_u || !dst_v || width <= 0 ||
1578
0
      height == 0) {
1579
0
    return -1;
1580
0
  }
1581
0
  ConvertToLSBPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
1582
0
                       depth);
1583
0
  SplitUVPlane_16(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
1584
0
                  dst_stride_v, uv_width, uv_height, depth);
1585
0
  return 0;
1586
0
}
1587
1588
LIBYUV_API
1589
int P010ToI010(const uint16_t* src_y,
1590
               int src_stride_y,
1591
               const uint16_t* src_uv,
1592
               int src_stride_uv,
1593
               uint16_t* dst_y,
1594
               int dst_stride_y,
1595
               uint16_t* dst_u,
1596
               int dst_stride_u,
1597
               uint16_t* dst_v,
1598
               int dst_stride_v,
1599
               int width,
1600
0
               int height) {
1601
0
  return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
1602
0
                    dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
1603
0
                    width, height, 1, 1, 10);
1604
0
}
1605
1606
LIBYUV_API
1607
int P012ToI012(const uint16_t* src_y,
1608
               int src_stride_y,
1609
               const uint16_t* src_uv,
1610
               int src_stride_uv,
1611
               uint16_t* dst_y,
1612
               int dst_stride_y,
1613
               uint16_t* dst_u,
1614
               int dst_stride_u,
1615
               uint16_t* dst_v,
1616
               int dst_stride_v,
1617
               int width,
1618
0
               int height) {
1619
0
  return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
1620
0
                    dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
1621
0
                    width, height, 1, 1, 12);
1622
0
}
1623
1624
LIBYUV_API
1625
int P010ToP410(const uint16_t* src_y,
1626
               int src_stride_y,
1627
               const uint16_t* src_uv,
1628
               int src_stride_uv,
1629
               uint16_t* dst_y,
1630
               int dst_stride_y,
1631
               uint16_t* dst_uv,
1632
               int dst_stride_uv,
1633
               int width,
1634
0
               int height) {
1635
0
  int r;
1636
0
  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
1637
0
    return -1;
1638
0
  }
1639
1640
0
  if (dst_y) {
1641
0
    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1642
0
  }
1643
0
  r = UVScale_16(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1),
1644
0
                 SUBSAMPLE(height, 1, 1), dst_uv, dst_stride_uv, Abs(width),
1645
0
                 Abs(height), kFilterBilinear);
1646
0
  return r;
1647
0
}
1648
1649
LIBYUV_API
1650
int P210ToP410(const uint16_t* src_y,
1651
               int src_stride_y,
1652
               const uint16_t* src_uv,
1653
               int src_stride_uv,
1654
               uint16_t* dst_y,
1655
               int dst_stride_y,
1656
               uint16_t* dst_uv,
1657
               int dst_stride_uv,
1658
               int width,
1659
0
               int height) {
1660
0
  int r;
1661
0
  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
1662
0
    return -1;
1663
0
  }
1664
1665
0
  if (dst_y) {
1666
0
    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1667
0
  }
1668
0
  r = UVScale_16(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1), height, dst_uv,
1669
0
                 dst_stride_uv, Abs(width), Abs(height), kFilterBilinear);
1670
0
  return r;
1671
0
}
1672
1673
// Convert YUY2 to I420.
1674
LIBYUV_API
1675
int YUY2ToI420(const uint8_t* src_yuy2,
1676
               int src_stride_yuy2,
1677
               uint8_t* dst_y,
1678
               int dst_stride_y,
1679
               uint8_t* dst_u,
1680
               int dst_stride_u,
1681
               uint8_t* dst_v,
1682
               int dst_stride_v,
1683
               int width,
1684
0
               int height) {
1685
0
  int y;
1686
0
  void (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2,
1687
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
1688
0
      YUY2ToUVRow_C;
1689
0
  void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) =
1690
0
      YUY2ToYRow_C;
1691
  // Negative height means invert the image.
1692
0
  if (height < 0) {
1693
0
    height = -height;
1694
0
    src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
1695
0
    src_stride_yuy2 = -src_stride_yuy2;
1696
0
  }
1697
0
#if defined(HAS_YUY2TOYROW_SSE2)
1698
0
  if (TestCpuFlag(kCpuHasSSE2)) {
1699
0
    YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
1700
0
    YUY2ToYRow = YUY2ToYRow_Any_SSE2;
1701
0
    if (IS_ALIGNED(width, 16)) {
1702
0
      YUY2ToUVRow = YUY2ToUVRow_SSE2;
1703
0
      YUY2ToYRow = YUY2ToYRow_SSE2;
1704
0
    }
1705
0
  }
1706
0
#endif
1707
0
#if defined(HAS_YUY2TOYROW_AVX2)
1708
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1709
0
    YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
1710
0
    YUY2ToYRow = YUY2ToYRow_Any_AVX2;
1711
0
    if (IS_ALIGNED(width, 32)) {
1712
0
      YUY2ToUVRow = YUY2ToUVRow_AVX2;
1713
0
      YUY2ToYRow = YUY2ToYRow_AVX2;
1714
0
    }
1715
0
  }
1716
0
#endif
1717
#if defined(HAS_YUY2TOYROW_NEON)
1718
  if (TestCpuFlag(kCpuHasNEON)) {
1719
    YUY2ToYRow = YUY2ToYRow_Any_NEON;
1720
    YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
1721
    if (IS_ALIGNED(width, 16)) {
1722
      YUY2ToYRow = YUY2ToYRow_NEON;
1723
      YUY2ToUVRow = YUY2ToUVRow_NEON;
1724
    }
1725
  }
1726
#endif
1727
#if defined(HAS_YUY2TOYROW_MSA) && defined(HAS_YUY2TOUVROW_MSA)
1728
  if (TestCpuFlag(kCpuHasMSA)) {
1729
    YUY2ToYRow = YUY2ToYRow_Any_MSA;
1730
    YUY2ToUVRow = YUY2ToUVRow_Any_MSA;
1731
    if (IS_ALIGNED(width, 32)) {
1732
      YUY2ToYRow = YUY2ToYRow_MSA;
1733
      YUY2ToUVRow = YUY2ToUVRow_MSA;
1734
    }
1735
  }
1736
#endif
1737
#if defined(HAS_YUY2TOYROW_LSX) && defined(HAS_YUY2TOUVROW_LSX)
1738
  if (TestCpuFlag(kCpuHasLSX)) {
1739
    YUY2ToYRow = YUY2ToYRow_Any_LSX;
1740
    YUY2ToUVRow = YUY2ToUVRow_Any_LSX;
1741
    if (IS_ALIGNED(width, 16)) {
1742
      YUY2ToYRow = YUY2ToYRow_LSX;
1743
      YUY2ToUVRow = YUY2ToUVRow_LSX;
1744
    }
1745
  }
1746
#endif
1747
#if defined(HAS_YUY2TOYROW_LASX) && defined(HAS_YUY2TOUVROW_LASX)
1748
  if (TestCpuFlag(kCpuHasLASX)) {
1749
    YUY2ToYRow = YUY2ToYRow_Any_LASX;
1750
    YUY2ToUVRow = YUY2ToUVRow_Any_LASX;
1751
    if (IS_ALIGNED(width, 32)) {
1752
      YUY2ToYRow = YUY2ToYRow_LASX;
1753
      YUY2ToUVRow = YUY2ToUVRow_LASX;
1754
    }
1755
  }
1756
#endif
1757
1758
0
  for (y = 0; y < height - 1; y += 2) {
1759
0
    YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
1760
0
    YUY2ToYRow(src_yuy2, dst_y, width);
1761
0
    YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
1762
0
    src_yuy2 += src_stride_yuy2 * 2;
1763
0
    dst_y += dst_stride_y * 2;
1764
0
    dst_u += dst_stride_u;
1765
0
    dst_v += dst_stride_v;
1766
0
  }
1767
0
  if (height & 1) {
1768
0
    YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
1769
0
    YUY2ToYRow(src_yuy2, dst_y, width);
1770
0
  }
1771
0
  return 0;
1772
0
}
1773
1774
// Convert UYVY to I420.
1775
LIBYUV_API
1776
int UYVYToI420(const uint8_t* src_uyvy,
1777
               int src_stride_uyvy,
1778
               uint8_t* dst_y,
1779
               int dst_stride_y,
1780
               uint8_t* dst_u,
1781
               int dst_stride_u,
1782
               uint8_t* dst_v,
1783
               int dst_stride_v,
1784
               int width,
1785
0
               int height) {
1786
0
  int y;
1787
0
  void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy,
1788
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
1789
0
      UYVYToUVRow_C;
1790
0
  void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) =
1791
0
      UYVYToYRow_C;
1792
  // Negative height means invert the image.
1793
0
  if (height < 0) {
1794
0
    height = -height;
1795
0
    src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
1796
0
    src_stride_uyvy = -src_stride_uyvy;
1797
0
  }
1798
0
#if defined(HAS_UYVYTOYROW_SSE2)
1799
0
  if (TestCpuFlag(kCpuHasSSE2)) {
1800
0
    UYVYToUVRow = UYVYToUVRow_Any_SSE2;
1801
0
    UYVYToYRow = UYVYToYRow_Any_SSE2;
1802
0
    if (IS_ALIGNED(width, 16)) {
1803
0
      UYVYToUVRow = UYVYToUVRow_SSE2;
1804
0
      UYVYToYRow = UYVYToYRow_SSE2;
1805
0
    }
1806
0
  }
1807
0
#endif
1808
0
#if defined(HAS_UYVYTOYROW_AVX2)
1809
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1810
0
    UYVYToUVRow = UYVYToUVRow_Any_AVX2;
1811
0
    UYVYToYRow = UYVYToYRow_Any_AVX2;
1812
0
    if (IS_ALIGNED(width, 32)) {
1813
0
      UYVYToUVRow = UYVYToUVRow_AVX2;
1814
0
      UYVYToYRow = UYVYToYRow_AVX2;
1815
0
    }
1816
0
  }
1817
0
#endif
1818
#if defined(HAS_UYVYTOYROW_NEON)
1819
  if (TestCpuFlag(kCpuHasNEON)) {
1820
    UYVYToYRow = UYVYToYRow_Any_NEON;
1821
    UYVYToUVRow = UYVYToUVRow_Any_NEON;
1822
    if (IS_ALIGNED(width, 16)) {
1823
      UYVYToYRow = UYVYToYRow_NEON;
1824
      UYVYToUVRow = UYVYToUVRow_NEON;
1825
    }
1826
  }
1827
#endif
1828
#if defined(HAS_UYVYTOYROW_MSA)
1829
  if (TestCpuFlag(kCpuHasMSA)) {
1830
    UYVYToYRow = UYVYToYRow_Any_MSA;
1831
    UYVYToUVRow = UYVYToUVRow_Any_MSA;
1832
    if (IS_ALIGNED(width, 32)) {
1833
      UYVYToYRow = UYVYToYRow_MSA;
1834
      UYVYToUVRow = UYVYToUVRow_MSA;
1835
    }
1836
  }
1837
#endif
1838
#if defined(HAS_UYVYTOYROW_LSX)
1839
  if (TestCpuFlag(kCpuHasLSX)) {
1840
    UYVYToYRow = UYVYToYRow_Any_LSX;
1841
    UYVYToUVRow = UYVYToUVRow_Any_LSX;
1842
    if (IS_ALIGNED(width, 16)) {
1843
      UYVYToYRow = UYVYToYRow_LSX;
1844
      UYVYToUVRow = UYVYToUVRow_LSX;
1845
    }
1846
  }
1847
#endif
1848
#if defined(HAS_UYVYTOYROW_LSX)
1849
  if (TestCpuFlag(kCpuHasLSX)) {
1850
    UYVYToYRow = UYVYToYRow_Any_LSX;
1851
    UYVYToUVRow = UYVYToUVRow_Any_LSX;
1852
    if (IS_ALIGNED(width, 16)) {
1853
      UYVYToYRow = UYVYToYRow_LSX;
1854
      UYVYToUVRow = UYVYToUVRow_LSX;
1855
    }
1856
  }
1857
#endif
1858
#if defined(HAS_UYVYTOYROW_LASX)
1859
  if (TestCpuFlag(kCpuHasLASX)) {
1860
    UYVYToYRow = UYVYToYRow_Any_LASX;
1861
    UYVYToUVRow = UYVYToUVRow_Any_LASX;
1862
    if (IS_ALIGNED(width, 32)) {
1863
      UYVYToYRow = UYVYToYRow_LASX;
1864
      UYVYToUVRow = UYVYToUVRow_LASX;
1865
    }
1866
  }
1867
#endif
1868
1869
0
  for (y = 0; y < height - 1; y += 2) {
1870
0
    UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
1871
0
    UYVYToYRow(src_uyvy, dst_y, width);
1872
0
    UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
1873
0
    src_uyvy += src_stride_uyvy * 2;
1874
0
    dst_y += dst_stride_y * 2;
1875
0
    dst_u += dst_stride_u;
1876
0
    dst_v += dst_stride_v;
1877
0
  }
1878
0
  if (height & 1) {
1879
0
    UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
1880
0
    UYVYToYRow(src_uyvy, dst_y, width);
1881
0
  }
1882
0
  return 0;
1883
0
}
1884
1885
// Convert AYUV to NV12.
1886
LIBYUV_API
1887
int AYUVToNV12(const uint8_t* src_ayuv,
1888
               int src_stride_ayuv,
1889
               uint8_t* dst_y,
1890
               int dst_stride_y,
1891
               uint8_t* dst_uv,
1892
               int dst_stride_uv,
1893
               int width,
1894
0
               int height) {
1895
0
  int y;
1896
0
  void (*AYUVToUVRow)(const uint8_t* src_ayuv, int src_stride_ayuv,
1897
0
                      uint8_t* dst_uv, int width) = AYUVToUVRow_C;
1898
0
  void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
1899
0
      AYUVToYRow_C;
1900
  // Negative height means invert the image.
1901
0
  if (height < 0) {
1902
0
    height = -height;
1903
0
    src_ayuv = src_ayuv + (height - 1) * src_stride_ayuv;
1904
0
    src_stride_ayuv = -src_stride_ayuv;
1905
0
  }
1906
// place holders for future intel code
1907
#if defined(HAS_AYUVTOYROW_SSE2)
1908
  if (TestCpuFlag(kCpuHasSSE2)) {
1909
    AYUVToUVRow = AYUVToUVRow_Any_SSE2;
1910
    AYUVToYRow = AYUVToYRow_Any_SSE2;
1911
    if (IS_ALIGNED(width, 16)) {
1912
      AYUVToUVRow = AYUVToUVRow_SSE2;
1913
      AYUVToYRow = AYUVToYRow_SSE2;
1914
    }
1915
  }
1916
#endif
1917
#if defined(HAS_AYUVTOYROW_AVX2)
1918
  if (TestCpuFlag(kCpuHasAVX2)) {
1919
    AYUVToUVRow = AYUVToUVRow_Any_AVX2;
1920
    AYUVToYRow = AYUVToYRow_Any_AVX2;
1921
    if (IS_ALIGNED(width, 32)) {
1922
      AYUVToUVRow = AYUVToUVRow_AVX2;
1923
      AYUVToYRow = AYUVToYRow_AVX2;
1924
    }
1925
  }
1926
#endif
1927
1928
#if defined(HAS_AYUVTOYROW_NEON)
1929
  if (TestCpuFlag(kCpuHasNEON)) {
1930
    AYUVToYRow = AYUVToYRow_Any_NEON;
1931
    AYUVToUVRow = AYUVToUVRow_Any_NEON;
1932
    if (IS_ALIGNED(width, 16)) {
1933
      AYUVToYRow = AYUVToYRow_NEON;
1934
      AYUVToUVRow = AYUVToUVRow_NEON;
1935
    }
1936
  }
1937
#endif
1938
#if defined(HAS_AYUVTOUVROW_SVE2)
1939
  if (TestCpuFlag(kCpuHasSVE2)) {
1940
    AYUVToUVRow = AYUVToUVRow_Any_SVE2;
1941
    if (IS_ALIGNED(width, 2)) {
1942
      AYUVToUVRow = AYUVToUVRow_SVE2;
1943
    }
1944
  }
1945
#endif
1946
1947
0
  for (y = 0; y < height - 1; y += 2) {
1948
0
    AYUVToUVRow(src_ayuv, src_stride_ayuv, dst_uv, width);
1949
0
    AYUVToYRow(src_ayuv, dst_y, width);
1950
0
    AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
1951
0
    src_ayuv += src_stride_ayuv * 2;
1952
0
    dst_y += dst_stride_y * 2;
1953
0
    dst_uv += dst_stride_uv;
1954
0
  }
1955
0
  if (height & 1) {
1956
0
    AYUVToUVRow(src_ayuv, 0, dst_uv, width);
1957
0
    AYUVToYRow(src_ayuv, dst_y, width);
1958
0
  }
1959
0
  return 0;
1960
0
}
1961
1962
// Convert AYUV to NV21.
1963
LIBYUV_API
1964
int AYUVToNV21(const uint8_t* src_ayuv,
1965
               int src_stride_ayuv,
1966
               uint8_t* dst_y,
1967
               int dst_stride_y,
1968
               uint8_t* dst_vu,
1969
               int dst_stride_vu,
1970
               int width,
1971
0
               int height) {
1972
0
  int y;
1973
0
  void (*AYUVToVURow)(const uint8_t* src_ayuv, int src_stride_ayuv,
1974
0
                      uint8_t* dst_vu, int width) = AYUVToVURow_C;
1975
0
  void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
1976
0
      AYUVToYRow_C;
1977
  // Negative height means invert the image.
1978
0
  if (height < 0) {
1979
0
    height = -height;
1980
0
    src_ayuv = src_ayuv + (height - 1) * src_stride_ayuv;
1981
0
    src_stride_ayuv = -src_stride_ayuv;
1982
0
  }
1983
// place holders for future intel code
1984
#if defined(HAS_AYUVTOYROW_SSE2)
1985
  if (TestCpuFlag(kCpuHasSSE2)) {
1986
    AYUVToVURow = AYUVToVURow_Any_SSE2;
1987
    AYUVToYRow = AYUVToYRow_Any_SSE2;
1988
    if (IS_ALIGNED(width, 16)) {
1989
      AYUVToVURow = AYUVToVURow_SSE2;
1990
      AYUVToYRow = AYUVToYRow_SSE2;
1991
    }
1992
  }
1993
#endif
1994
#if defined(HAS_AYUVTOYROW_AVX2)
1995
  if (TestCpuFlag(kCpuHasAVX2)) {
1996
    AYUVToVURow = AYUVToVURow_Any_AVX2;
1997
    AYUVToYRow = AYUVToYRow_Any_AVX2;
1998
    if (IS_ALIGNED(width, 32)) {
1999
      AYUVToVURow = AYUVToVURow_AVX2;
2000
      AYUVToYRow = AYUVToYRow_AVX2;
2001
    }
2002
  }
2003
#endif
2004
2005
#if defined(HAS_AYUVTOYROW_NEON)
2006
  if (TestCpuFlag(kCpuHasNEON)) {
2007
    AYUVToYRow = AYUVToYRow_Any_NEON;
2008
    AYUVToVURow = AYUVToVURow_Any_NEON;
2009
    if (IS_ALIGNED(width, 16)) {
2010
      AYUVToYRow = AYUVToYRow_NEON;
2011
      AYUVToVURow = AYUVToVURow_NEON;
2012
    }
2013
  }
2014
#endif
2015
#if defined(HAS_AYUVTOVUROW_SVE2)
2016
  if (TestCpuFlag(kCpuHasSVE2)) {
2017
    AYUVToVURow = AYUVToVURow_Any_SVE2;
2018
    if (IS_ALIGNED(width, 2)) {
2019
      AYUVToVURow = AYUVToVURow_SVE2;
2020
    }
2021
  }
2022
#endif
2023
2024
0
  for (y = 0; y < height - 1; y += 2) {
2025
0
    AYUVToVURow(src_ayuv, src_stride_ayuv, dst_vu, width);
2026
0
    AYUVToYRow(src_ayuv, dst_y, width);
2027
0
    AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
2028
0
    src_ayuv += src_stride_ayuv * 2;
2029
0
    dst_y += dst_stride_y * 2;
2030
0
    dst_vu += dst_stride_vu;
2031
0
  }
2032
0
  if (height & 1) {
2033
0
    AYUVToVURow(src_ayuv, 0, dst_vu, width);
2034
0
    AYUVToYRow(src_ayuv, dst_y, width);
2035
0
  }
2036
0
  return 0;
2037
0
}
2038
2039
// Convert ARGB to I420.
2040
LIBYUV_API
2041
int ARGBToI420(const uint8_t* src_argb,
2042
               int src_stride_argb,
2043
               uint8_t* dst_y,
2044
               int dst_stride_y,
2045
               uint8_t* dst_u,
2046
               int dst_stride_u,
2047
               uint8_t* dst_v,
2048
               int dst_stride_v,
2049
               int width,
2050
0
               int height) {
2051
0
  int y;
2052
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
2053
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
2054
0
      ARGBToUVRow_C;
2055
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2056
0
      ARGBToYRow_C;
2057
0
  if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2058
0
    return -1;
2059
0
  }
2060
  // Negative height means invert the image.
2061
0
  if (height < 0) {
2062
0
    height = -height;
2063
0
    src_argb = src_argb + (height - 1) * src_stride_argb;
2064
0
    src_stride_argb = -src_stride_argb;
2065
0
  }
2066
#if defined(HAS_ARGBTOYROW_NEON)
2067
  if (TestCpuFlag(kCpuHasNEON)) {
2068
    ARGBToYRow = ARGBToYRow_Any_NEON;
2069
    if (IS_ALIGNED(width, 16)) {
2070
      ARGBToYRow = ARGBToYRow_NEON;
2071
    }
2072
  }
2073
#endif
2074
#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
2075
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
2076
    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
2077
    if (IS_ALIGNED(width, 16)) {
2078
      ARGBToYRow = ARGBToYRow_NEON_DotProd;
2079
    }
2080
  }
2081
#endif
2082
#if defined(HAS_ARGBTOUVROW_NEON)
2083
  if (TestCpuFlag(kCpuHasNEON)) {
2084
    ARGBToUVRow = ARGBToUVRow_Any_NEON;
2085
    if (IS_ALIGNED(width, 16)) {
2086
      ARGBToUVRow = ARGBToUVRow_NEON;
2087
    }
2088
  }
2089
#endif
2090
#if defined(HAS_ARGBTOUVROW_SVE2)
2091
  if (TestCpuFlag(kCpuHasSVE2)) {
2092
    ARGBToUVRow = ARGBToUVRow_Any_SVE2;
2093
    if (IS_ALIGNED(width, 2)) {
2094
      ARGBToUVRow = ARGBToUVRow_SVE2;
2095
    }
2096
  }
2097
#endif
2098
0
#if defined(HAS_ARGBTOYROW_SSSE3)
2099
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2100
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
2101
0
    if (IS_ALIGNED(width, 16)) {
2102
0
      ARGBToYRow = ARGBToYRow_SSSE3;
2103
0
    }
2104
0
  }
2105
0
#endif
2106
0
#if defined(HAS_ARGBTOUVROW_SSSE3)
2107
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2108
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
2109
0
    if (IS_ALIGNED(width, 16)) {
2110
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
2111
0
    }
2112
0
  }
2113
0
#endif
2114
0
#if defined(HAS_ARGBTOYROW_AVX2)
2115
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2116
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
2117
0
    if (IS_ALIGNED(width, 32)) {
2118
0
      ARGBToYRow = ARGBToYRow_AVX2;
2119
0
    }
2120
0
  }
2121
0
#endif
2122
0
#if defined(HAS_ARGBTOUVROW_AVX2)
2123
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2124
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
2125
0
    if (IS_ALIGNED(width, 32)) {
2126
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
2127
0
    }
2128
0
  }
2129
0
#endif
2130
#if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
2131
  if (TestCpuFlag(kCpuHasMSA)) {
2132
    ARGBToYRow = ARGBToYRow_Any_MSA;
2133
    ARGBToUVRow = ARGBToUVRow_Any_MSA;
2134
    if (IS_ALIGNED(width, 16)) {
2135
      ARGBToYRow = ARGBToYRow_MSA;
2136
    }
2137
    if (IS_ALIGNED(width, 32)) {
2138
      ARGBToUVRow = ARGBToUVRow_MSA;
2139
    }
2140
  }
2141
#endif
2142
#if defined(HAS_ARGBTOYROW_LSX)
2143
  if (TestCpuFlag(kCpuHasLSX)) {
2144
    ARGBToYRow = ARGBToYRow_Any_LSX;
2145
    if (IS_ALIGNED(width, 16)) {
2146
      ARGBToYRow = ARGBToYRow_LSX;
2147
    }
2148
  }
2149
#endif
2150
#if defined(HAS_ARGBTOYROW_LSX) && defined(HAS_ARGBTOUVROW_LSX)
2151
  if (TestCpuFlag(kCpuHasLSX)) {
2152
    ARGBToYRow = ARGBToYRow_Any_LSX;
2153
    ARGBToUVRow = ARGBToUVRow_Any_LSX;
2154
    if (IS_ALIGNED(width, 16)) {
2155
      ARGBToYRow = ARGBToYRow_LSX;
2156
      ARGBToUVRow = ARGBToUVRow_LSX;
2157
    }
2158
  }
2159
#endif
2160
#if defined(HAS_ARGBTOYROW_LASX) && defined(HAS_ARGBTOUVROW_LASX)
2161
  if (TestCpuFlag(kCpuHasLASX)) {
2162
    ARGBToYRow = ARGBToYRow_Any_LASX;
2163
    ARGBToUVRow = ARGBToUVRow_Any_LASX;
2164
    if (IS_ALIGNED(width, 32)) {
2165
      ARGBToYRow = ARGBToYRow_LASX;
2166
      ARGBToUVRow = ARGBToUVRow_LASX;
2167
    }
2168
  }
2169
#endif
2170
2171
0
  for (y = 0; y < height - 1; y += 2) {
2172
0
    ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
2173
0
    ARGBToYRow(src_argb, dst_y, width);
2174
0
    ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
2175
0
    src_argb += src_stride_argb * 2;
2176
0
    dst_y += dst_stride_y * 2;
2177
0
    dst_u += dst_stride_u;
2178
0
    dst_v += dst_stride_v;
2179
0
  }
2180
0
  if (height & 1) {
2181
0
    ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
2182
0
    ARGBToYRow(src_argb, dst_y, width);
2183
0
  }
2184
0
  return 0;
2185
0
}
2186
2187
#ifdef USE_EXTRACTALPHA
2188
// Convert ARGB to I420 with Alpha
2189
// The following version calls ARGBExtractAlpha on the full image.
2190
LIBYUV_API
2191
int ARGBToI420Alpha(const uint8_t* src_argb,
2192
                    int src_stride_argb,
2193
                    uint8_t* dst_y,
2194
                    int dst_stride_y,
2195
                    uint8_t* dst_u,
2196
                    int dst_stride_u,
2197
                    uint8_t* dst_v,
2198
                    int dst_stride_v,
2199
                    uint8_t* dst_a,
2200
                    int dst_stride_a,
2201
                    int width,
2202
                    int height) {
2203
  int r = ARGBToI420(src_argb, src_stride_argb, dst_y, dst_stride_y, dst_u,
2204
                     dst_stride_u, dst_v, dst_stride_v, width, height);
2205
  if (r == 0) {
2206
    r = ARGBExtractAlpha(src_argb, src_stride_argb, dst_a, dst_stride_a, width,
2207
                         height);
2208
  }
2209
  return r;
2210
}
2211
#else  // USE_EXTRACTALPHA
2212
// Convert ARGB to I420 with Alpha
2213
LIBYUV_API
2214
int ARGBToI420Alpha(const uint8_t* src_argb,
2215
                    int src_stride_argb,
2216
                    uint8_t* dst_y,
2217
                    int dst_stride_y,
2218
                    uint8_t* dst_u,
2219
                    int dst_stride_u,
2220
                    uint8_t* dst_v,
2221
                    int dst_stride_v,
2222
                    uint8_t* dst_a,
2223
                    int dst_stride_a,
2224
                    int width,
2225
0
                    int height) {
2226
0
  int y;
2227
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
2228
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
2229
0
      ARGBToUVRow_C;
2230
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2231
0
      ARGBToYRow_C;
2232
0
  void (*ARGBExtractAlphaRow)(const uint8_t* src_argb, uint8_t* dst_a,
2233
0
                              int width) = ARGBExtractAlphaRow_C;
2234
0
  if (!src_argb || !dst_y || !dst_u || !dst_v || !dst_a || width <= 0 ||
2235
0
      height == 0) {
2236
0
    return -1;
2237
0
  }
2238
  // Negative height means invert the image.
2239
0
  if (height < 0) {
2240
0
    height = -height;
2241
0
    src_argb = src_argb + (height - 1) * src_stride_argb;
2242
0
    src_stride_argb = -src_stride_argb;
2243
0
  }
2244
#if defined(HAS_ARGBTOYROW_NEON)
2245
  if (TestCpuFlag(kCpuHasNEON)) {
2246
    ARGBToYRow = ARGBToYRow_Any_NEON;
2247
    if (IS_ALIGNED(width, 16)) {
2248
      ARGBToYRow = ARGBToYRow_NEON;
2249
    }
2250
  }
2251
#endif
2252
#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
2253
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
2254
    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
2255
    if (IS_ALIGNED(width, 16)) {
2256
      ARGBToYRow = ARGBToYRow_NEON_DotProd;
2257
    }
2258
  }
2259
#endif
2260
#if defined(HAS_ARGBTOUVROW_NEON)
2261
  if (TestCpuFlag(kCpuHasNEON)) {
2262
    ARGBToUVRow = ARGBToUVRow_Any_NEON;
2263
    if (IS_ALIGNED(width, 16)) {
2264
      ARGBToUVRow = ARGBToUVRow_NEON;
2265
    }
2266
  }
2267
#endif
2268
#if defined(HAS_ARGBTOUVROW_SVE2)
2269
  if (TestCpuFlag(kCpuHasSVE2)) {
2270
    ARGBToUVRow = ARGBToUVRow_Any_SVE2;
2271
    if (IS_ALIGNED(width, 2)) {
2272
      ARGBToUVRow = ARGBToUVRow_SVE2;
2273
    }
2274
  }
2275
#endif
2276
0
#if defined(HAS_ARGBTOYROW_SSSE3)
2277
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2278
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
2279
0
    if (IS_ALIGNED(width, 16)) {
2280
0
      ARGBToYRow = ARGBToYRow_SSSE3;
2281
0
    }
2282
0
  }
2283
0
#endif
2284
0
#if defined(HAS_ARGBTOUVROW_SSSE3)
2285
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2286
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
2287
0
    if (IS_ALIGNED(width, 16)) {
2288
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
2289
0
    }
2290
0
  }
2291
0
#endif
2292
0
#if defined(HAS_ARGBTOYROW_AVX2)
2293
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2294
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
2295
0
    if (IS_ALIGNED(width, 32)) {
2296
0
      ARGBToYRow = ARGBToYRow_AVX2;
2297
0
    }
2298
0
  }
2299
0
#endif
2300
0
#if defined(HAS_ARGBTOUVROW_AVX2)
2301
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2302
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
2303
0
    if (IS_ALIGNED(width, 32)) {
2304
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
2305
0
    }
2306
0
  }
2307
0
#endif
2308
#if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
2309
  if (TestCpuFlag(kCpuHasMSA)) {
2310
    ARGBToYRow = ARGBToYRow_Any_MSA;
2311
    ARGBToUVRow = ARGBToUVRow_Any_MSA;
2312
    if (IS_ALIGNED(width, 16)) {
2313
      ARGBToYRow = ARGBToYRow_MSA;
2314
    }
2315
    if (IS_ALIGNED(width, 32)) {
2316
      ARGBToUVRow = ARGBToUVRow_MSA;
2317
    }
2318
  }
2319
#endif
2320
#if defined(HAS_ARGBTOYROW_LSX)
2321
  if (TestCpuFlag(kCpuHasLSX)) {
2322
    ARGBToYRow = ARGBToYRow_Any_LSX;
2323
    if (IS_ALIGNED(width, 16)) {
2324
      ARGBToYRow = ARGBToYRow_LSX;
2325
    }
2326
  }
2327
#endif
2328
#if defined(HAS_ARGBTOYROW_LASX) && defined(HAS_ARGBTOUVROW_LASX)
2329
  if (TestCpuFlag(kCpuHasLASX)) {
2330
    ARGBToYRow = ARGBToYRow_Any_LASX;
2331
    ARGBToUVRow = ARGBToUVRow_Any_LASX;
2332
    if (IS_ALIGNED(width, 32)) {
2333
      ARGBToYRow = ARGBToYRow_LASX;
2334
      ARGBToUVRow = ARGBToUVRow_LASX;
2335
    }
2336
  }
2337
#endif
2338
0
#if defined(HAS_ARGBEXTRACTALPHAROW_SSE2)
2339
0
  if (TestCpuFlag(kCpuHasSSE2)) {
2340
0
    ARGBExtractAlphaRow = IS_ALIGNED(width, 8) ? ARGBExtractAlphaRow_SSE2
2341
0
                                               : ARGBExtractAlphaRow_Any_SSE2;
2342
0
  }
2343
0
#endif
2344
0
#if defined(HAS_ARGBEXTRACTALPHAROW_AVX2)
2345
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2346
0
    ARGBExtractAlphaRow = IS_ALIGNED(width, 32) ? ARGBExtractAlphaRow_AVX2
2347
0
                                                : ARGBExtractAlphaRow_Any_AVX2;
2348
0
  }
2349
0
#endif
2350
#if defined(HAS_ARGBEXTRACTALPHAROW_NEON)
2351
  if (TestCpuFlag(kCpuHasNEON)) {
2352
    ARGBExtractAlphaRow = IS_ALIGNED(width, 16) ? ARGBExtractAlphaRow_NEON
2353
                                                : ARGBExtractAlphaRow_Any_NEON;
2354
  }
2355
#endif
2356
#if defined(HAS_ARGBEXTRACTALPHAROW_MSA)
2357
  if (TestCpuFlag(kCpuHasMSA)) {
2358
    ARGBExtractAlphaRow = IS_ALIGNED(width, 16) ? ARGBExtractAlphaRow_MSA
2359
                                                : ARGBExtractAlphaRow_Any_MSA;
2360
  }
2361
#endif
2362
#if defined(HAS_ARGBEXTRACTALPHAROW_LSX)
2363
  if (TestCpuFlag(kCpuHasLSX)) {
2364
    ARGBExtractAlphaRow = IS_ALIGNED(width, 16) ? ARGBExtractAlphaRow_LSX
2365
                                                : ARGBExtractAlphaRow_Any_LSX;
2366
  }
2367
#endif
2368
#if defined(HAS_ARGBEXTRACTALPHAROW_RVV)
2369
  if (TestCpuFlag(kCpuHasRVV)) {
2370
    ARGBExtractAlphaRow = ARGBExtractAlphaRow_RVV;
2371
  }
2372
#endif
2373
2374
0
  for (y = 0; y < height - 1; y += 2) {
2375
0
    ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
2376
0
    ARGBToYRow(src_argb, dst_y, width);
2377
0
    ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
2378
0
    ARGBExtractAlphaRow(src_argb, dst_a, width);
2379
0
    ARGBExtractAlphaRow(src_argb + src_stride_argb, dst_a + dst_stride_a,
2380
0
                        width);
2381
0
    src_argb += src_stride_argb * 2;
2382
0
    dst_y += dst_stride_y * 2;
2383
0
    dst_u += dst_stride_u;
2384
0
    dst_v += dst_stride_v;
2385
0
    dst_a += dst_stride_a * 2;
2386
0
  }
2387
0
  if (height & 1) {
2388
0
    ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
2389
0
    ARGBToYRow(src_argb, dst_y, width);
2390
0
    ARGBExtractAlphaRow(src_argb, dst_a, width);
2391
0
  }
2392
0
  return 0;
2393
0
}
2394
#endif  // USE_EXTRACTALPHA
2395
2396
// Convert BGRA to I420.
2397
LIBYUV_API
2398
int BGRAToI420(const uint8_t* src_bgra,
2399
               int src_stride_bgra,
2400
               uint8_t* dst_y,
2401
               int dst_stride_y,
2402
               uint8_t* dst_u,
2403
               int dst_stride_u,
2404
               uint8_t* dst_v,
2405
               int dst_stride_v,
2406
               int width,
2407
0
               int height) {
2408
0
  int y;
2409
0
  void (*BGRAToUVRow)(const uint8_t* src_bgra0, int src_stride_bgra,
2410
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
2411
0
      BGRAToUVRow_C;
2412
0
  void (*BGRAToYRow)(const uint8_t* src_bgra, uint8_t* dst_y, int width) =
2413
0
      BGRAToYRow_C;
2414
0
  if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2415
0
    return -1;
2416
0
  }
2417
  // Negative height means invert the image.
2418
0
  if (height < 0) {
2419
0
    height = -height;
2420
0
    src_bgra = src_bgra + (height - 1) * src_stride_bgra;
2421
0
    src_stride_bgra = -src_stride_bgra;
2422
0
  }
2423
#if defined(HAS_BGRATOYROW_NEON)
2424
  if (TestCpuFlag(kCpuHasNEON)) {
2425
    BGRAToYRow = BGRAToYRow_Any_NEON;
2426
    if (IS_ALIGNED(width, 16)) {
2427
      BGRAToYRow = BGRAToYRow_NEON;
2428
    }
2429
  }
2430
#endif
2431
#if defined(HAS_BGRATOYROW_NEON_DOTPROD)
2432
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
2433
    BGRAToYRow = BGRAToYRow_Any_NEON_DotProd;
2434
    if (IS_ALIGNED(width, 16)) {
2435
      BGRAToYRow = BGRAToYRow_NEON_DotProd;
2436
    }
2437
  }
2438
#endif
2439
#if defined(HAS_BGRATOUVROW_NEON)
2440
  if (TestCpuFlag(kCpuHasNEON)) {
2441
    BGRAToUVRow = BGRAToUVRow_Any_NEON;
2442
    if (IS_ALIGNED(width, 16)) {
2443
      BGRAToUVRow = BGRAToUVRow_NEON;
2444
    }
2445
  }
2446
#endif
2447
#if defined(HAS_BGRATOUVROW_SVE2)
2448
  if (TestCpuFlag(kCpuHasSVE2)) {
2449
    BGRAToUVRow = BGRAToUVRow_Any_SVE2;
2450
    if (IS_ALIGNED(width, 2)) {
2451
      BGRAToUVRow = BGRAToUVRow_SVE2;
2452
    }
2453
  }
2454
#endif
2455
0
#if defined(HAS_BGRATOYROW_SSSE3)
2456
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2457
0
    BGRAToYRow = BGRAToYRow_Any_SSSE3;
2458
0
    if (IS_ALIGNED(width, 16)) {
2459
0
      BGRAToYRow = BGRAToYRow_SSSE3;
2460
0
    }
2461
0
  }
2462
0
#endif
2463
0
#if defined(HAS_BGRATOUVROW_SSSE3)
2464
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2465
0
    BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
2466
0
    if (IS_ALIGNED(width, 16)) {
2467
0
      BGRAToUVRow = BGRAToUVRow_SSSE3;
2468
0
    }
2469
0
  }
2470
0
#endif
2471
#if defined(HAS_BGRATOYROW_AVX2)
2472
  if (TestCpuFlag(kCpuHasAVX2)) {
2473
    BGRAToYRow = BGRAToYRow_Any_AVX2;
2474
    if (IS_ALIGNED(width, 32)) {
2475
      BGRAToYRow = BGRAToYRow_AVX2;
2476
    }
2477
  }
2478
#endif
2479
#if defined(HAS_BGRATOUVROW_AVX2)
2480
  if (TestCpuFlag(kCpuHasAVX2)) {
2481
    BGRAToUVRow = BGRAToUVRow_Any_AVX2;
2482
    if (IS_ALIGNED(width, 32)) {
2483
      BGRAToUVRow = BGRAToUVRow_AVX2;
2484
    }
2485
  }
2486
#endif
2487
#if defined(HAS_BGRATOYROW_MSA) && defined(HAS_BGRATOUVROW_MSA)
2488
  if (TestCpuFlag(kCpuHasMSA)) {
2489
    BGRAToYRow = BGRAToYRow_Any_MSA;
2490
    BGRAToUVRow = BGRAToUVRow_Any_MSA;
2491
    if (IS_ALIGNED(width, 16)) {
2492
      BGRAToYRow = BGRAToYRow_MSA;
2493
    }
2494
    if (IS_ALIGNED(width, 32)) {
2495
      BGRAToUVRow = BGRAToUVRow_MSA;
2496
    }
2497
  }
2498
#endif
2499
#if defined(HAS_BGRATOYROW_LSX) && defined(HAS_BGRATOUVROW_LSX)
2500
  if (TestCpuFlag(kCpuHasLSX)) {
2501
    BGRAToYRow = BGRAToYRow_Any_LSX;
2502
    BGRAToUVRow = BGRAToUVRow_Any_LSX;
2503
    if (IS_ALIGNED(width, 16)) {
2504
      BGRAToYRow = BGRAToYRow_LSX;
2505
      BGRAToUVRow = BGRAToUVRow_LSX;
2506
    }
2507
  }
2508
#endif
2509
#if defined(HAS_BGRATOYROW_LASX)
2510
  if (TestCpuFlag(kCpuHasLASX)) {
2511
    BGRAToYRow = BGRAToYRow_Any_LASX;
2512
    if (IS_ALIGNED(width, 32)) {
2513
      BGRAToYRow = BGRAToYRow_LASX;
2514
    }
2515
  }
2516
#endif
2517
#if defined(HAS_BGRATOYROW_RVV)
2518
  if (TestCpuFlag(kCpuHasRVV)) {
2519
    BGRAToYRow = BGRAToYRow_RVV;
2520
  }
2521
#endif
2522
2523
0
  for (y = 0; y < height - 1; y += 2) {
2524
0
    BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
2525
0
    BGRAToYRow(src_bgra, dst_y, width);
2526
0
    BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
2527
0
    src_bgra += src_stride_bgra * 2;
2528
0
    dst_y += dst_stride_y * 2;
2529
0
    dst_u += dst_stride_u;
2530
0
    dst_v += dst_stride_v;
2531
0
  }
2532
0
  if (height & 1) {
2533
0
    BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
2534
0
    BGRAToYRow(src_bgra, dst_y, width);
2535
0
  }
2536
0
  return 0;
2537
0
}
2538
2539
// Convert ABGR to I420.
2540
LIBYUV_API
2541
int ABGRToI420(const uint8_t* src_abgr,
2542
               int src_stride_abgr,
2543
               uint8_t* dst_y,
2544
               int dst_stride_y,
2545
               uint8_t* dst_u,
2546
               int dst_stride_u,
2547
               uint8_t* dst_v,
2548
               int dst_stride_v,
2549
               int width,
2550
0
               int height) {
2551
0
  int y;
2552
0
  void (*ABGRToUVRow)(const uint8_t* src_abgr0, int src_stride_abgr,
2553
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
2554
0
      ABGRToUVRow_C;
2555
0
  void (*ABGRToYRow)(const uint8_t* src_abgr, uint8_t* dst_y, int width) =
2556
0
      ABGRToYRow_C;
2557
0
  if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2558
0
    return -1;
2559
0
  }
2560
  // Negative height means invert the image.
2561
0
  if (height < 0) {
2562
0
    height = -height;
2563
0
    src_abgr = src_abgr + (height - 1) * src_stride_abgr;
2564
0
    src_stride_abgr = -src_stride_abgr;
2565
0
  }
2566
0
#if defined(HAS_ABGRTOYROW_SSSE3)
2567
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2568
0
    ABGRToYRow = ABGRToYRow_Any_SSSE3;
2569
0
    if (IS_ALIGNED(width, 16)) {
2570
0
      ABGRToYRow = ABGRToYRow_SSSE3;
2571
0
    }
2572
0
  }
2573
0
#endif
2574
0
#if defined(HAS_ABGRTOUVROW_SSSE3)
2575
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2576
0
    ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
2577
0
    if (IS_ALIGNED(width, 16)) {
2578
0
      ABGRToUVRow = ABGRToUVRow_SSSE3;
2579
0
    }
2580
0
  }
2581
0
#endif
2582
0
#if defined(HAS_ABGRTOYROW_AVX2)
2583
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2584
0
    ABGRToYRow = ABGRToYRow_Any_AVX2;
2585
0
    if (IS_ALIGNED(width, 32)) {
2586
0
      ABGRToYRow = ABGRToYRow_AVX2;
2587
0
    }
2588
0
  }
2589
0
#endif
2590
0
#if defined(HAS_ABGRTOUVROW_AVX2)
2591
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2592
0
    ABGRToUVRow = ABGRToUVRow_Any_AVX2;
2593
0
    if (IS_ALIGNED(width, 32)) {
2594
0
      ABGRToUVRow = ABGRToUVRow_AVX2;
2595
0
    }
2596
0
  }
2597
0
#endif
2598
#if defined(HAS_ABGRTOYROW_NEON)
2599
  if (TestCpuFlag(kCpuHasNEON)) {
2600
    ABGRToYRow = ABGRToYRow_Any_NEON;
2601
    if (IS_ALIGNED(width, 16)) {
2602
      ABGRToYRow = ABGRToYRow_NEON;
2603
    }
2604
  }
2605
#endif
2606
#if defined(HAS_ABGRTOYROW_NEON_DOTPROD)
2607
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
2608
    ABGRToYRow = ABGRToYRow_Any_NEON_DotProd;
2609
    if (IS_ALIGNED(width, 16)) {
2610
      ABGRToYRow = ABGRToYRow_NEON_DotProd;
2611
    }
2612
  }
2613
#endif
2614
#if defined(HAS_ABGRTOUVROW_NEON)
2615
  if (TestCpuFlag(kCpuHasNEON)) {
2616
    ABGRToUVRow = ABGRToUVRow_Any_NEON;
2617
    if (IS_ALIGNED(width, 16)) {
2618
      ABGRToUVRow = ABGRToUVRow_NEON;
2619
    }
2620
  }
2621
#endif
2622
#if defined(HAS_ABGRTOUVROW_SVE2)
2623
  if (TestCpuFlag(kCpuHasSVE2)) {
2624
    ABGRToUVRow = ABGRToUVRow_Any_SVE2;
2625
    if (IS_ALIGNED(width, 2)) {
2626
      ABGRToUVRow = ABGRToUVRow_SVE2;
2627
    }
2628
  }
2629
#endif
2630
#if defined(HAS_ABGRTOYROW_MSA) && defined(HAS_ABGRTOUVROW_MSA)
2631
  if (TestCpuFlag(kCpuHasMSA)) {
2632
    ABGRToYRow = ABGRToYRow_Any_MSA;
2633
    ABGRToUVRow = ABGRToUVRow_Any_MSA;
2634
    if (IS_ALIGNED(width, 16)) {
2635
      ABGRToYRow = ABGRToYRow_MSA;
2636
      ABGRToUVRow = ABGRToUVRow_MSA;
2637
    }
2638
  }
2639
#endif
2640
#if defined(HAS_ABGRTOYROW_LSX) && defined(HAS_ABGRTOUVROW_LSX)
2641
  if (TestCpuFlag(kCpuHasLSX)) {
2642
    ABGRToYRow = ABGRToYRow_Any_LSX;
2643
    ABGRToUVRow = ABGRToUVRow_Any_LSX;
2644
    if (IS_ALIGNED(width, 16)) {
2645
      ABGRToYRow = ABGRToYRow_LSX;
2646
      ABGRToUVRow = ABGRToUVRow_LSX;
2647
    }
2648
  }
2649
#endif
2650
#if defined(HAS_ABGRTOYROW_LASX)
2651
  if (TestCpuFlag(kCpuHasLASX)) {
2652
    ABGRToYRow = ABGRToYRow_Any_LASX;
2653
    if (IS_ALIGNED(width, 32)) {
2654
      ABGRToYRow = ABGRToYRow_LASX;
2655
    }
2656
  }
2657
#endif
2658
#if defined(HAS_ABGRTOYROW_RVV)
2659
  if (TestCpuFlag(kCpuHasRVV)) {
2660
    ABGRToYRow = ABGRToYRow_RVV;
2661
  }
2662
#endif
2663
2664
0
  for (y = 0; y < height - 1; y += 2) {
2665
0
    ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
2666
0
    ABGRToYRow(src_abgr, dst_y, width);
2667
0
    ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
2668
0
    src_abgr += src_stride_abgr * 2;
2669
0
    dst_y += dst_stride_y * 2;
2670
0
    dst_u += dst_stride_u;
2671
0
    dst_v += dst_stride_v;
2672
0
  }
2673
0
  if (height & 1) {
2674
0
    ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
2675
0
    ABGRToYRow(src_abgr, dst_y, width);
2676
0
  }
2677
0
  return 0;
2678
0
}
2679
2680
// Convert RGBA to I420.
2681
LIBYUV_API
2682
int RGBAToI420(const uint8_t* src_rgba,
2683
               int src_stride_rgba,
2684
               uint8_t* dst_y,
2685
               int dst_stride_y,
2686
               uint8_t* dst_u,
2687
               int dst_stride_u,
2688
               uint8_t* dst_v,
2689
               int dst_stride_v,
2690
               int width,
2691
0
               int height) {
2692
0
  int y;
2693
0
  void (*RGBAToUVRow)(const uint8_t* src_rgba0, int src_stride_rgba,
2694
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
2695
0
      RGBAToUVRow_C;
2696
0
  void (*RGBAToYRow)(const uint8_t* src_rgba, uint8_t* dst_y, int width) =
2697
0
      RGBAToYRow_C;
2698
0
  if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2699
0
    return -1;
2700
0
  }
2701
  // Negative height means invert the image.
2702
0
  if (height < 0) {
2703
0
    height = -height;
2704
0
    src_rgba = src_rgba + (height - 1) * src_stride_rgba;
2705
0
    src_stride_rgba = -src_stride_rgba;
2706
0
  }
2707
0
#if defined(HAS_RGBATOYROW_SSSE3)
2708
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2709
0
    RGBAToYRow = RGBAToYRow_Any_SSSE3;
2710
0
    if (IS_ALIGNED(width, 16)) {
2711
0
      RGBAToYRow = RGBAToYRow_SSSE3;
2712
0
    }
2713
0
  }
2714
0
#endif
2715
0
#if defined(HAS_RGBATOUVROW_SSSE3)
2716
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2717
0
    RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
2718
0
    if (IS_ALIGNED(width, 16)) {
2719
0
      RGBAToUVRow = RGBAToUVRow_SSSE3;
2720
0
    }
2721
0
  }
2722
0
#endif
2723
#if defined(HAS_RGBATOYROW_NEON)
2724
  if (TestCpuFlag(kCpuHasNEON)) {
2725
    RGBAToYRow = RGBAToYRow_Any_NEON;
2726
    if (IS_ALIGNED(width, 16)) {
2727
      RGBAToYRow = RGBAToYRow_NEON;
2728
    }
2729
  }
2730
#endif
2731
#if defined(HAS_RGBATOYROW_NEON_DOTPROD)
2732
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
2733
    RGBAToYRow = RGBAToYRow_Any_NEON_DotProd;
2734
    if (IS_ALIGNED(width, 16)) {
2735
      RGBAToYRow = RGBAToYRow_NEON_DotProd;
2736
    }
2737
  }
2738
#endif
2739
#if defined(HAS_RGBATOUVROW_NEON)
2740
  if (TestCpuFlag(kCpuHasNEON)) {
2741
    RGBAToUVRow = RGBAToUVRow_Any_NEON;
2742
    if (IS_ALIGNED(width, 16)) {
2743
      RGBAToUVRow = RGBAToUVRow_NEON;
2744
    }
2745
  }
2746
#endif
2747
#if defined(HAS_RGBATOUVROW_SVE2)
2748
  if (TestCpuFlag(kCpuHasSVE2)) {
2749
    RGBAToUVRow = RGBAToUVRow_Any_SVE2;
2750
    if (IS_ALIGNED(width, 2)) {
2751
      RGBAToUVRow = RGBAToUVRow_SVE2;
2752
    }
2753
  }
2754
#endif
2755
#if defined(HAS_RGBATOYROW_MSA) && defined(HAS_RGBATOUVROW_MSA)
2756
  if (TestCpuFlag(kCpuHasMSA)) {
2757
    RGBAToYRow = RGBAToYRow_Any_MSA;
2758
    RGBAToUVRow = RGBAToUVRow_Any_MSA;
2759
    if (IS_ALIGNED(width, 16)) {
2760
      RGBAToYRow = RGBAToYRow_MSA;
2761
      RGBAToUVRow = RGBAToUVRow_MSA;
2762
    }
2763
  }
2764
#endif
2765
#if defined(HAS_RGBATOYROW_LSX) && defined(HAS_RGBATOUVROW_LSX)
2766
  if (TestCpuFlag(kCpuHasLSX)) {
2767
    RGBAToYRow = RGBAToYRow_Any_LSX;
2768
    RGBAToUVRow = RGBAToUVRow_Any_LSX;
2769
    if (IS_ALIGNED(width, 16)) {
2770
      RGBAToYRow = RGBAToYRow_LSX;
2771
      RGBAToUVRow = RGBAToUVRow_LSX;
2772
    }
2773
  }
2774
#endif
2775
#if defined(HAS_RGBATOYROW_LASX)
2776
  if (TestCpuFlag(kCpuHasNEON)) {
2777
    RGBAToYRow = RGBAToYRow_Any_LASX;
2778
    if (IS_ALIGNED(width, 32)) {
2779
      RGBAToYRow = RGBAToYRow_LASX;
2780
    }
2781
  }
2782
#endif
2783
#if defined(HAS_RGBATOYROW_RVV)
2784
  if (TestCpuFlag(kCpuHasRVV)) {
2785
    RGBAToYRow = RGBAToYRow_RVV;
2786
  }
2787
#endif
2788
2789
0
  for (y = 0; y < height - 1; y += 2) {
2790
0
    RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
2791
0
    RGBAToYRow(src_rgba, dst_y, width);
2792
0
    RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
2793
0
    src_rgba += src_stride_rgba * 2;
2794
0
    dst_y += dst_stride_y * 2;
2795
0
    dst_u += dst_stride_u;
2796
0
    dst_v += dst_stride_v;
2797
0
  }
2798
0
  if (height & 1) {
2799
0
    RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
2800
0
    RGBAToYRow(src_rgba, dst_y, width);
2801
0
  }
2802
0
  return 0;
2803
0
}
2804
2805
// Enabled if 1 pass is available
2806
#if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
2807
     defined(HAS_RGB24TOYROW_LSX) || defined(HAS_RGB24TOYROW_RVV))
2808
#define HAS_RGB24TOYROW
2809
#endif
2810
2811
// Convert RGB24 to I420.
2812
LIBYUV_API
2813
int RGB24ToI420(const uint8_t* src_rgb24,
2814
                int src_stride_rgb24,
2815
                uint8_t* dst_y,
2816
                int dst_stride_y,
2817
                uint8_t* dst_u,
2818
                int dst_stride_u,
2819
                uint8_t* dst_v,
2820
                int dst_stride_v,
2821
                int width,
2822
0
                int height) {
2823
0
  int y;
2824
#if defined(HAS_RGB24TOYROW)
2825
  void (*RGB24ToUVRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
2826
                       uint8_t* dst_u, uint8_t* dst_v, int width) =
2827
      RGB24ToUVRow_C;
2828
  void (*RGB24ToYRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
2829
      RGB24ToYRow_C;
2830
#else
2831
0
  void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
2832
0
      RGB24ToARGBRow_C;
2833
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
2834
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
2835
0
      ARGBToUVRow_C;
2836
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2837
0
      ARGBToYRow_C;
2838
0
#endif
2839
0
  if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2840
0
    return -1;
2841
0
  }
2842
  // Negative height means invert the image.
2843
0
  if (height < 0) {
2844
0
    height = -height;
2845
0
    src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
2846
0
    src_stride_rgb24 = -src_stride_rgb24;
2847
0
  }
2848
2849
#if defined(HAS_RGB24TOYROW)
2850
2851
// Neon version does direct RGB24 to YUV.
2852
#if defined(HAS_RGB24TOYROW_NEON) && defined(HAS_RGB24TOUVROW_NEON)
2853
  if (TestCpuFlag(kCpuHasNEON)) {
2854
    RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
2855
    RGB24ToYRow = RGB24ToYRow_Any_NEON;
2856
    if (IS_ALIGNED(width, 16)) {
2857
      RGB24ToYRow = RGB24ToYRow_NEON;
2858
      RGB24ToUVRow = RGB24ToUVRow_NEON;
2859
    }
2860
  }
2861
#endif
2862
#if defined(HAS_RGB24TOYROW_MSA) && defined(HAS_RGB24TOUVROW_MSA)
2863
  if (TestCpuFlag(kCpuHasMSA)) {
2864
    RGB24ToUVRow = RGB24ToUVRow_Any_MSA;
2865
    RGB24ToYRow = RGB24ToYRow_Any_MSA;
2866
    if (IS_ALIGNED(width, 16)) {
2867
      RGB24ToYRow = RGB24ToYRow_MSA;
2868
      RGB24ToUVRow = RGB24ToUVRow_MSA;
2869
    }
2870
  }
2871
#endif
2872
#if defined(HAS_RGB24TOYROW_LSX) && defined(HAS_RGB24TOUVROW_LSX)
2873
  if (TestCpuFlag(kCpuHasLSX)) {
2874
    RGB24ToUVRow = RGB24ToUVRow_Any_LSX;
2875
    RGB24ToYRow = RGB24ToYRow_Any_LSX;
2876
    if (IS_ALIGNED(width, 16)) {
2877
      RGB24ToYRow = RGB24ToYRow_LSX;
2878
      RGB24ToUVRow = RGB24ToUVRow_LSX;
2879
    }
2880
  }
2881
#endif
2882
#if defined(HAS_RGB24TOYROW_LASX) && defined(HAS_RGB24TOUVROW_LASX)
2883
  if (TestCpuFlag(kCpuHasLASX)) {
2884
    RGB24ToUVRow = RGB24ToUVRow_Any_LASX;
2885
    RGB24ToYRow = RGB24ToYRow_Any_LASX;
2886
    if (IS_ALIGNED(width, 32)) {
2887
      RGB24ToYRow = RGB24ToYRow_LASX;
2888
      RGB24ToUVRow = RGB24ToUVRow_LASX;
2889
    }
2890
  }
2891
#endif
2892
#if defined(HAS_RGB24TOYROW_RVV)
2893
  if (TestCpuFlag(kCpuHasRVV)) {
2894
    RGB24ToYRow = RGB24ToYRow_RVV;
2895
  }
2896
#endif
2897
2898
// Other platforms do intermediate conversion from RGB24 to ARGB.
2899
#else  // HAS_RGB24TOYROW
2900
2901
0
#if defined(HAS_RGB24TOARGBROW_SSSE3)
2902
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2903
0
    RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
2904
0
    if (IS_ALIGNED(width, 16)) {
2905
0
      RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
2906
0
    }
2907
0
  }
2908
0
#endif
2909
0
#if defined(HAS_ARGBTOYROW_SSSE3)
2910
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2911
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
2912
0
    if (IS_ALIGNED(width, 16)) {
2913
0
      ARGBToYRow = ARGBToYRow_SSSE3;
2914
0
    }
2915
0
  }
2916
0
#endif
2917
0
#if defined(HAS_ARGBTOYROW_AVX2)
2918
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2919
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
2920
0
    if (IS_ALIGNED(width, 32)) {
2921
0
      ARGBToYRow = ARGBToYRow_AVX2;
2922
0
    }
2923
0
  }
2924
0
#endif
2925
0
#if defined(HAS_ARGBTOUVROW_SSSE3)
2926
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2927
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
2928
0
    if (IS_ALIGNED(width, 16)) {
2929
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
2930
0
    }
2931
0
  }
2932
0
#endif
2933
0
#if defined(HAS_ARGBTOUVROW_AVX2)
2934
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2935
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
2936
0
    if (IS_ALIGNED(width, 32)) {
2937
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
2938
0
    }
2939
0
  }
2940
0
#endif
2941
0
#endif  // HAS_RGB24TOYROW
2942
2943
0
  {
2944
0
#if !defined(HAS_RGB24TOYROW)
2945
    // Allocate 2 rows of ARGB.
2946
0
    const int row_size = (width * 4 + 31) & ~31;
2947
0
    align_buffer_64(row, row_size * 2);
2948
0
    if (!row)
2949
0
      return 1;
2950
0
#endif
2951
2952
0
    for (y = 0; y < height - 1; y += 2) {
2953
#if defined(HAS_RGB24TOYROW)
2954
      RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
2955
      RGB24ToYRow(src_rgb24, dst_y, width);
2956
      RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
2957
#else
2958
0
      RGB24ToARGBRow(src_rgb24, row, width);
2959
0
      RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + row_size, width);
2960
0
      ARGBToUVRow(row, row_size, dst_u, dst_v, width);
2961
0
      ARGBToYRow(row, dst_y, width);
2962
0
      ARGBToYRow(row + row_size, dst_y + dst_stride_y, width);
2963
0
#endif
2964
0
      src_rgb24 += src_stride_rgb24 * 2;
2965
0
      dst_y += dst_stride_y * 2;
2966
0
      dst_u += dst_stride_u;
2967
0
      dst_v += dst_stride_v;
2968
0
    }
2969
0
    if (height & 1) {
2970
#if defined(HAS_RGB24TOYROW)
2971
      RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
2972
      RGB24ToYRow(src_rgb24, dst_y, width);
2973
#else
2974
0
      RGB24ToARGBRow(src_rgb24, row, width);
2975
0
      ARGBToUVRow(row, 0, dst_u, dst_v, width);
2976
0
      ARGBToYRow(row, dst_y, width);
2977
0
#endif
2978
0
    }
2979
0
#if !defined(HAS_RGB24TOYROW)
2980
0
    free_aligned_buffer_64(row);
2981
0
#endif
2982
0
  }
2983
0
  return 0;
2984
0
}
2985
#undef HAS_RGB24TOYROW
2986
2987
// Enabled if 1 pass is available
2988
#if defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2989
    defined(HAS_RGB24TOYJROW_RVV)
2990
#define HAS_RGB24TOYJROW
2991
#endif
2992
2993
// Convert RGB24 to J420.
2994
LIBYUV_API
2995
int RGB24ToJ420(const uint8_t* src_rgb24,
2996
                int src_stride_rgb24,
2997
                uint8_t* dst_y,
2998
                int dst_stride_y,
2999
                uint8_t* dst_u,
3000
                int dst_stride_u,
3001
                uint8_t* dst_v,
3002
                int dst_stride_v,
3003
                int width,
3004
0
                int height) {
3005
0
  int y;
3006
#if defined(HAS_RGB24TOYJROW)
3007
  void (*RGB24ToUVJRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
3008
                        uint8_t* dst_u, uint8_t* dst_v, int width) =
3009
      RGB24ToUVJRow_C;
3010
  void (*RGB24ToYJRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
3011
      RGB24ToYJRow_C;
3012
#else
3013
0
  void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
3014
0
      RGB24ToARGBRow_C;
3015
0
  void (*ARGBToUVJRow)(const uint8_t* src_argb0, int src_stride_argb,
3016
0
                       uint8_t* dst_u, uint8_t* dst_v, int width) =
3017
0
      ARGBToUVJRow_C;
3018
0
  void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
3019
0
      ARGBToYJRow_C;
3020
0
#endif
3021
0
  if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
3022
0
    return -1;
3023
0
  }
3024
  // Negative height means invert the image.
3025
0
  if (height < 0) {
3026
0
    height = -height;
3027
0
    src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
3028
0
    src_stride_rgb24 = -src_stride_rgb24;
3029
0
  }
3030
3031
#if defined(HAS_RGB24TOYJROW)
3032
3033
// Neon version does direct RGB24 to YUV.
3034
#if defined(HAS_RGB24TOYJROW_NEON) && defined(HAS_RGB24TOUVJROW_NEON)
3035
  if (TestCpuFlag(kCpuHasNEON)) {
3036
    RGB24ToUVJRow = RGB24ToUVJRow_Any_NEON;
3037
    RGB24ToYJRow = RGB24ToYJRow_Any_NEON;
3038
    if (IS_ALIGNED(width, 16)) {
3039
      RGB24ToYJRow = RGB24ToYJRow_NEON;
3040
      RGB24ToUVJRow = RGB24ToUVJRow_NEON;
3041
    }
3042
  }
3043
#endif
3044
#if defined(HAS_RGB24TOYJROW_MSA) && defined(HAS_RGB24TOUVJROW_MSA)
3045
  if (TestCpuFlag(kCpuHasMSA)) {
3046
    RGB24ToUVJRow = RGB24ToUVJRow_Any_MSA;
3047
    RGB24ToYJRow = RGB24ToYJRow_Any_MSA;
3048
    if (IS_ALIGNED(width, 16)) {
3049
      RGB24ToYJRow = RGB24ToYJRow_MSA;
3050
      RGB24ToUVJRow = RGB24ToUVJRow_MSA;
3051
    }
3052
  }
3053
#endif
3054
#if defined(HAS_RGB24TOYJROW_LSX)
3055
  if (TestCpuFlag(kCpuHasLSX)) {
3056
    RGB24ToYJRow = RGB24ToYJRow_Any_LSX;
3057
    if (IS_ALIGNED(width, 16)) {
3058
      RGB24ToYJRow = RGB24ToYJRow_LSX;
3059
    }
3060
  }
3061
#endif
3062
#if defined(HAS_RGB24TOYJROW_LASX)
3063
  if (TestCpuFlag(kCpuHasLASX)) {
3064
    RGB24ToYJRow = RGB24ToYJRow_Any_LASX;
3065
    if (IS_ALIGNED(width, 32)) {
3066
      RGB24ToYJRow = RGB24ToYJRow_LASX;
3067
    }
3068
  }
3069
#endif
3070
#if defined(HAS_RGB24TOYJROW_RVV)
3071
  if (TestCpuFlag(kCpuHasRVV)) {
3072
    RGB24ToYJRow = RGB24ToYJRow_RVV;
3073
  }
3074
#endif
3075
3076
// Other platforms do intermediate conversion from RGB24 to ARGB.
3077
#else  // HAS_RGB24TOYJROW
3078
3079
0
#if defined(HAS_RGB24TOARGBROW_SSSE3)
3080
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3081
0
    RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
3082
0
    if (IS_ALIGNED(width, 16)) {
3083
0
      RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
3084
0
    }
3085
0
  }
3086
0
#endif
3087
0
#if defined(HAS_ARGBTOYJROW_SSSE3)
3088
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3089
0
    ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
3090
0
    if (IS_ALIGNED(width, 16)) {
3091
0
      ARGBToYJRow = ARGBToYJRow_SSSE3;
3092
0
    }
3093
0
  }
3094
0
#endif
3095
0
#if defined(HAS_ARGBTOYJROW_AVX2)
3096
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3097
0
    ARGBToYJRow = ARGBToYJRow_Any_AVX2;
3098
0
    if (IS_ALIGNED(width, 32)) {
3099
0
      ARGBToYJRow = ARGBToYJRow_AVX2;
3100
0
    }
3101
0
  }
3102
0
#endif
3103
0
#if defined(HAS_ARGBTOUVJROW_SSSE3)
3104
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3105
0
    ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
3106
0
    if (IS_ALIGNED(width, 16)) {
3107
0
      ARGBToUVJRow = ARGBToUVJRow_SSSE3;
3108
0
    }
3109
0
  }
3110
0
#endif
3111
0
#if defined(HAS_ARGBTOUVJROW_AVX2)
3112
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3113
0
    ARGBToUVJRow = ARGBToUVJRow_Any_AVX2;
3114
0
    if (IS_ALIGNED(width, 32)) {
3115
0
      ARGBToUVJRow = ARGBToUVJRow_AVX2;
3116
0
    }
3117
0
  }
3118
0
#endif
3119
0
#endif  // HAS_RGB24TOYJROW
3120
3121
0
  {
3122
0
#if !defined(HAS_RGB24TOYJROW)
3123
    // Allocate 2 rows of ARGB.
3124
0
    const int row_size = (width * 4 + 31) & ~31;
3125
0
    align_buffer_64(row, row_size * 2);
3126
0
    if (!row)
3127
0
      return 1;
3128
0
#endif
3129
3130
0
    for (y = 0; y < height - 1; y += 2) {
3131
#if defined(HAS_RGB24TOYJROW)
3132
      RGB24ToUVJRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
3133
      RGB24ToYJRow(src_rgb24, dst_y, width);
3134
      RGB24ToYJRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
3135
#else
3136
0
      RGB24ToARGBRow(src_rgb24, row, width);
3137
0
      RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + row_size, width);
3138
0
      ARGBToUVJRow(row, row_size, dst_u, dst_v, width);
3139
0
      ARGBToYJRow(row, dst_y, width);
3140
0
      ARGBToYJRow(row + row_size, dst_y + dst_stride_y, width);
3141
0
#endif
3142
0
      src_rgb24 += src_stride_rgb24 * 2;
3143
0
      dst_y += dst_stride_y * 2;
3144
0
      dst_u += dst_stride_u;
3145
0
      dst_v += dst_stride_v;
3146
0
    }
3147
0
    if (height & 1) {
3148
#if defined(HAS_RGB24TOYJROW)
3149
      RGB24ToUVJRow(src_rgb24, 0, dst_u, dst_v, width);
3150
      RGB24ToYJRow(src_rgb24, dst_y, width);
3151
#else
3152
0
      RGB24ToARGBRow(src_rgb24, row, width);
3153
0
      ARGBToUVJRow(row, 0, dst_u, dst_v, width);
3154
0
      ARGBToYJRow(row, dst_y, width);
3155
0
#endif
3156
0
    }
3157
0
#if !defined(HAS_RGB24TOYJROW)
3158
0
    free_aligned_buffer_64(row);
3159
0
#endif
3160
0
  }
3161
0
  return 0;
3162
0
}
3163
#undef HAS_RGB24TOYJROW
3164
3165
// Enabled if 1 pass is available
3166
#if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
3167
     defined(HAS_RAWTOYROW_LSX) || defined(HAS_RAWTOYROW_RVV))
3168
#define HAS_RAWTOYROW
3169
#endif
3170
3171
// Convert RAW to I420.
3172
LIBYUV_API
3173
int RAWToI420(const uint8_t* src_raw,
3174
              int src_stride_raw,
3175
              uint8_t* dst_y,
3176
              int dst_stride_y,
3177
              uint8_t* dst_u,
3178
              int dst_stride_u,
3179
              uint8_t* dst_v,
3180
              int dst_stride_v,
3181
              int width,
3182
0
              int height) {
3183
0
  int y;
3184
#if defined(HAS_RAWTOYROW)
3185
  void (*RAWToUVRow)(const uint8_t* src_raw, int src_stride_raw, uint8_t* dst_u,
3186
                     uint8_t* dst_v, int width) = RAWToUVRow_C;
3187
  void (*RAWToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
3188
      RAWToYRow_C;
3189
#else
3190
0
  void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
3191
0
      RAWToARGBRow_C;
3192
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
3193
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
3194
0
      ARGBToUVRow_C;
3195
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
3196
0
      ARGBToYRow_C;
3197
0
#endif
3198
0
  if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
3199
0
    return -1;
3200
0
  }
3201
  // Negative height means invert the image.
3202
0
  if (height < 0) {
3203
0
    height = -height;
3204
0
    src_raw = src_raw + (height - 1) * src_stride_raw;
3205
0
    src_stride_raw = -src_stride_raw;
3206
0
  }
3207
3208
#if defined(HAS_RAWTOYROW)
3209
3210
// Neon version does direct RAW to YUV.
3211
#if defined(HAS_RAWTOYROW_NEON) && defined(HAS_RAWTOUVROW_NEON)
3212
  if (TestCpuFlag(kCpuHasNEON)) {
3213
    RAWToUVRow = RAWToUVRow_Any_NEON;
3214
    RAWToYRow = RAWToYRow_Any_NEON;
3215
    if (IS_ALIGNED(width, 16)) {
3216
      RAWToYRow = RAWToYRow_NEON;
3217
      RAWToUVRow = RAWToUVRow_NEON;
3218
    }
3219
  }
3220
#endif
3221
#if defined(HAS_RAWTOYROW_MSA) && defined(HAS_RAWTOUVROW_MSA)
3222
  if (TestCpuFlag(kCpuHasMSA)) {
3223
    RAWToUVRow = RAWToUVRow_Any_MSA;
3224
    RAWToYRow = RAWToYRow_Any_MSA;
3225
    if (IS_ALIGNED(width, 16)) {
3226
      RAWToYRow = RAWToYRow_MSA;
3227
      RAWToUVRow = RAWToUVRow_MSA;
3228
    }
3229
  }
3230
#endif
3231
#if defined(HAS_RAWTOYROW_LSX) && defined(HAS_RAWTOUVROW_LSX)
3232
  if (TestCpuFlag(kCpuHasLSX)) {
3233
    RAWToUVRow = RAWToUVRow_Any_LSX;
3234
    RAWToYRow = RAWToYRow_Any_LSX;
3235
    if (IS_ALIGNED(width, 16)) {
3236
      RAWToYRow = RAWToYRow_LSX;
3237
      RAWToUVRow = RAWToUVRow_LSX;
3238
    }
3239
  }
3240
#endif
3241
#if defined(HAS_RAWTOYROW_LASX) && defined(HAS_RAWTOUVROW_LASX)
3242
  if (TestCpuFlag(kCpuHasLASX)) {
3243
    RAWToUVRow = RAWToUVRow_Any_LASX;
3244
    RAWToYRow = RAWToYRow_Any_LASX;
3245
    if (IS_ALIGNED(width, 32)) {
3246
      RAWToYRow = RAWToYRow_LASX;
3247
      RAWToUVRow = RAWToUVRow_LASX;
3248
    }
3249
  }
3250
#endif
3251
#if defined(HAS_RAWTOYROW_RVV)
3252
  if (TestCpuFlag(kCpuHasRVV)) {
3253
    RAWToYRow = RAWToYRow_RVV;
3254
  }
3255
#endif
3256
3257
// Other platforms do intermediate conversion from RAW to ARGB.
3258
#else  // HAS_RAWTOYROW
3259
3260
0
#if defined(HAS_RAWTOARGBROW_SSSE3)
3261
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3262
0
    RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
3263
0
    if (IS_ALIGNED(width, 16)) {
3264
0
      RAWToARGBRow = RAWToARGBRow_SSSE3;
3265
0
    }
3266
0
  }
3267
0
#endif
3268
0
#if defined(HAS_RAWTOARGBROW_AVX2)
3269
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3270
0
    RAWToARGBRow = RAWToARGBRow_Any_AVX2;
3271
0
    if (IS_ALIGNED(width, 32)) {
3272
0
      RAWToARGBRow = RAWToARGBRow_AVX2;
3273
0
    }
3274
0
  }
3275
0
#endif
3276
0
#if defined(HAS_ARGBTOYROW_SSSE3)
3277
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3278
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
3279
0
    if (IS_ALIGNED(width, 16)) {
3280
0
      ARGBToYRow = ARGBToYRow_SSSE3;
3281
0
    }
3282
0
  }
3283
0
#endif
3284
0
#if defined(HAS_ARGBTOYROW_AVX2)
3285
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3286
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
3287
0
    if (IS_ALIGNED(width, 32)) {
3288
0
      ARGBToYRow = ARGBToYRow_AVX2;
3289
0
    }
3290
0
  }
3291
0
#endif
3292
0
#if defined(HAS_ARGBTOUVROW_SSSE3)
3293
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3294
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
3295
0
    if (IS_ALIGNED(width, 16)) {
3296
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
3297
0
    }
3298
0
  }
3299
0
#endif
3300
0
#if defined(HAS_ARGBTOUVROW_AVX2)
3301
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3302
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
3303
0
    if (IS_ALIGNED(width, 32)) {
3304
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
3305
0
    }
3306
0
  }
3307
0
#endif
3308
0
#endif  // HAS_RAWTOYROW
3309
3310
0
  {
3311
0
#if !defined(HAS_RAWTOYROW)
3312
    // Allocate 2 rows of ARGB.
3313
0
    const int row_size = (width * 4 + 31) & ~31;
3314
0
    align_buffer_64(row, row_size * 2);
3315
0
    if (!row)
3316
0
      return 1;
3317
0
#endif
3318
3319
0
    for (y = 0; y < height - 1; y += 2) {
3320
#if defined(HAS_RAWTOYROW)
3321
      RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
3322
      RAWToYRow(src_raw, dst_y, width);
3323
      RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
3324
#else
3325
0
      RAWToARGBRow(src_raw, row, width);
3326
0
      RAWToARGBRow(src_raw + src_stride_raw, row + row_size, width);
3327
0
      ARGBToUVRow(row, row_size, dst_u, dst_v, width);
3328
0
      ARGBToYRow(row, dst_y, width);
3329
0
      ARGBToYRow(row + row_size, dst_y + dst_stride_y, width);
3330
0
#endif
3331
0
      src_raw += src_stride_raw * 2;
3332
0
      dst_y += dst_stride_y * 2;
3333
0
      dst_u += dst_stride_u;
3334
0
      dst_v += dst_stride_v;
3335
0
    }
3336
0
    if (height & 1) {
3337
#if defined(HAS_RAWTOYROW)
3338
      RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
3339
      RAWToYRow(src_raw, dst_y, width);
3340
#else
3341
0
      RAWToARGBRow(src_raw, row, width);
3342
0
      ARGBToUVRow(row, 0, dst_u, dst_v, width);
3343
0
      ARGBToYRow(row, dst_y, width);
3344
0
#endif
3345
0
    }
3346
0
#if !defined(HAS_RAWTOYROW)
3347
0
    free_aligned_buffer_64(row);
3348
0
#endif
3349
0
  }
3350
0
  return 0;
3351
0
}
3352
#undef HAS_RAWTOYROW
3353
3354
// Enabled if 1 pass is available
3355
#if defined(HAS_RAWTOYJROW_NEON) || defined(HAS_RAWTOYJROW_MSA) || \
3356
    defined(HAS_RAWTOYJROW_RVV)
3357
#define HAS_RAWTOYJROW
3358
#endif
3359
3360
// Convert RAW to J420.
3361
LIBYUV_API
3362
int RAWToJ420(const uint8_t* src_raw,
3363
              int src_stride_raw,
3364
              uint8_t* dst_y,
3365
              int dst_stride_y,
3366
              uint8_t* dst_u,
3367
              int dst_stride_u,
3368
              uint8_t* dst_v,
3369
              int dst_stride_v,
3370
              int width,
3371
60
              int height) {
3372
60
  int y;
3373
#if defined(HAS_RAWTOYJROW)
3374
  void (*RAWToUVJRow)(const uint8_t* src_raw, int src_stride_raw,
3375
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
3376
      RAWToUVJRow_C;
3377
  void (*RAWToYJRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
3378
      RAWToYJRow_C;
3379
#else
3380
60
  void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
3381
60
      RAWToARGBRow_C;
3382
60
  void (*ARGBToUVJRow)(const uint8_t* src_argb0, int src_stride_argb,
3383
60
                       uint8_t* dst_u, uint8_t* dst_v, int width) =
3384
60
      ARGBToUVJRow_C;
3385
60
  void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
3386
60
      ARGBToYJRow_C;
3387
60
#endif
3388
60
  if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
3389
0
    return -1;
3390
0
  }
3391
  // Negative height means invert the image.
3392
60
  if (height < 0) {
3393
0
    height = -height;
3394
0
    src_raw = src_raw + (height - 1) * src_stride_raw;
3395
0
    src_stride_raw = -src_stride_raw;
3396
0
  }
3397
3398
#if defined(HAS_RAWTOYJROW)
3399
3400
// Neon version does direct RAW to YUV.
3401
#if defined(HAS_RAWTOYJROW_NEON) && defined(HAS_RAWTOUVJROW_NEON)
3402
  if (TestCpuFlag(kCpuHasNEON)) {
3403
    RAWToUVJRow = RAWToUVJRow_Any_NEON;
3404
    RAWToYJRow = RAWToYJRow_Any_NEON;
3405
    if (IS_ALIGNED(width, 16)) {
3406
      RAWToYJRow = RAWToYJRow_NEON;
3407
      RAWToUVJRow = RAWToUVJRow_NEON;
3408
    }
3409
  }
3410
#endif
3411
#if defined(HAS_RAWTOYJROW_MSA) && defined(HAS_RAWTOUVJROW_MSA)
3412
  if (TestCpuFlag(kCpuHasMSA)) {
3413
    RAWToUVJRow = RAWToUVJRow_Any_MSA;
3414
    RAWToYJRow = RAWToYJRow_Any_MSA;
3415
    if (IS_ALIGNED(width, 16)) {
3416
      RAWToYJRow = RAWToYJRow_MSA;
3417
      RAWToUVJRow = RAWToUVJRow_MSA;
3418
    }
3419
  }
3420
#endif
3421
#if defined(HAS_RAWTOYJROW_LSX) && defined(HAS_RAWTOUVJROW_LSX)
3422
  if (TestCpuFlag(kCpuHasLSX)) {
3423
    RAWToUVJRow = RAWToUVJRow_Any_LSX;
3424
    RAWToYJRow = RAWToYJRow_Any_LSX;
3425
    if (IS_ALIGNED(width, 16)) {
3426
      RAWToYJRow = RAWToYJRow_LSX;
3427
      RAWToUVJRow = RAWToUVJRow_LSX;
3428
    }
3429
  }
3430
#endif
3431
#if defined(HAS_RAWTOYJROW_LASX) && defined(HAS_RAWTOUVJROW_LASX)
3432
  if (TestCpuFlag(kCpuHasLASX)) {
3433
    RAWToUVJRow = RAWToUVJRow_Any_LASX;
3434
    RAWToYJRow = RAWToYJRow_Any_LASX;
3435
    if (IS_ALIGNED(width, 32)) {
3436
      RAWToYJRow = RAWToYJRow_LASX;
3437
      RAWToUVJRow = RAWToUVJRow_LASX;
3438
    }
3439
  }
3440
#endif
3441
#if defined(HAS_RAWTOYJROW_RVV)
3442
  if (TestCpuFlag(kCpuHasRVV)) {
3443
    RAWToYJRow = RAWToYJRow_RVV;
3444
  }
3445
#endif
3446
3447
// Other platforms do intermediate conversion from RAW to ARGB.
3448
#else  // HAS_RAWTOYJROW
3449
3450
60
#if defined(HAS_RAWTOARGBROW_SSSE3)
3451
60
  if (TestCpuFlag(kCpuHasSSSE3)) {
3452
60
    RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
3453
60
    if (IS_ALIGNED(width, 16)) {
3454
8
      RAWToARGBRow = RAWToARGBRow_SSSE3;
3455
8
    }
3456
60
  }
3457
60
#endif
3458
60
#if defined(HAS_RAWTOARGBROW_AVX2)
3459
60
  if (TestCpuFlag(kCpuHasAVX2)) {
3460
60
    RAWToARGBRow = RAWToARGBRow_Any_AVX2;
3461
60
    if (IS_ALIGNED(width, 32)) {
3462
2
      RAWToARGBRow = RAWToARGBRow_AVX2;
3463
2
    }
3464
60
  }
3465
60
#endif
3466
60
#if defined(HAS_ARGBTOYJROW_SSSE3)
3467
60
  if (TestCpuFlag(kCpuHasSSSE3)) {
3468
60
    ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
3469
60
    if (IS_ALIGNED(width, 16)) {
3470
8
      ARGBToYJRow = ARGBToYJRow_SSSE3;
3471
8
    }
3472
60
  }
3473
60
#endif
3474
60
#if defined(HAS_ARGBTOYJROW_AVX2)
3475
60
  if (TestCpuFlag(kCpuHasAVX2)) {
3476
60
    ARGBToYJRow = ARGBToYJRow_Any_AVX2;
3477
60
    if (IS_ALIGNED(width, 32)) {
3478
2
      ARGBToYJRow = ARGBToYJRow_AVX2;
3479
2
    }
3480
60
  }
3481
60
#endif
3482
60
#if defined(HAS_ARGBTOUVJROW_SSSE3)
3483
60
  if (TestCpuFlag(kCpuHasSSSE3)) {
3484
60
    ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
3485
60
    if (IS_ALIGNED(width, 16)) {
3486
8
      ARGBToUVJRow = ARGBToUVJRow_SSSE3;
3487
8
    }
3488
60
  }
3489
60
#endif
3490
60
#if defined(HAS_ARGBTOUVJROW_AVX2)
3491
60
  if (TestCpuFlag(kCpuHasAVX2)) {
3492
60
    ARGBToUVJRow = ARGBToUVJRow_Any_AVX2;
3493
60
    if (IS_ALIGNED(width, 32)) {
3494
2
      ARGBToUVJRow = ARGBToUVJRow_AVX2;
3495
2
    }
3496
60
  }
3497
60
#endif
3498
60
#endif  // HAS_RAWTOYJROW
3499
3500
60
  {
3501
60
#if !defined(HAS_RAWTOYJROW)
3502
    // Allocate 2 rows of ARGB.
3503
60
    const int row_size = (width * 4 + 31) & ~31;
3504
60
    align_buffer_64(row, row_size * 2);
3505
60
    if (!row)
3506
0
      return 1;
3507
60
#endif
3508
3509
534k
    for (y = 0; y < height - 1; y += 2) {
3510
#if defined(HAS_RAWTOYJROW)
3511
      RAWToUVJRow(src_raw, src_stride_raw, dst_u, dst_v, width);
3512
      RAWToYJRow(src_raw, dst_y, width);
3513
      RAWToYJRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
3514
#else
3515
534k
      RAWToARGBRow(src_raw, row, width);
3516
534k
      RAWToARGBRow(src_raw + src_stride_raw, row + row_size, width);
3517
534k
      ARGBToUVJRow(row, row_size, dst_u, dst_v, width);
3518
534k
      ARGBToYJRow(row, dst_y, width);
3519
534k
      ARGBToYJRow(row + row_size, dst_y + dst_stride_y, width);
3520
534k
#endif
3521
534k
      src_raw += src_stride_raw * 2;
3522
534k
      dst_y += dst_stride_y * 2;
3523
534k
      dst_u += dst_stride_u;
3524
534k
      dst_v += dst_stride_v;
3525
534k
    }
3526
60
    if (height & 1) {
3527
#if defined(HAS_RAWTOYJROW)
3528
      RAWToUVJRow(src_raw, 0, dst_u, dst_v, width);
3529
      RAWToYJRow(src_raw, dst_y, width);
3530
#else
3531
26
      RAWToARGBRow(src_raw, row, width);
3532
26
      ARGBToUVJRow(row, 0, dst_u, dst_v, width);
3533
26
      ARGBToYJRow(row, dst_y, width);
3534
26
#endif
3535
26
    }
3536
60
#if !defined(HAS_RAWTOYJROW)
3537
60
    free_aligned_buffer_64(row);
3538
60
#endif
3539
60
  }
3540
0
  return 0;
3541
60
}
3542
#undef HAS_RAWTOYJROW
3543
3544
// RAW big endian (rgb in memory) to I444
3545
// 2 step conversion of RAWToARGB then ARGBToY and ARGBToUV444
3546
LIBYUV_API
3547
int RAWToI444(const uint8_t* src_raw,
3548
              int src_stride_raw,
3549
              uint8_t* dst_y,
3550
              int dst_stride_y,
3551
              uint8_t* dst_u,
3552
              int dst_stride_u,
3553
              uint8_t* dst_v,
3554
              int dst_stride_v,
3555
              int width,
3556
0
              int height) {
3557
0
  int y;
3558
0
  void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
3559
0
      RAWToARGBRow_C;
3560
0
  void (*ARGBToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
3561
0
      ARGBToYRow_C;
3562
0
  void (*ARGBToUV444Row)(const uint8_t* src_raw, uint8_t* dst_u, uint8_t* dst_v,
3563
0
                         int width) = ARGBToUV444Row_C;
3564
0
  if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
3565
0
    return -1;
3566
0
  }
3567
0
  if (height < 0) {
3568
0
    height = -height;
3569
0
    src_raw = src_raw + (height - 1) * src_stride_raw;
3570
0
    src_stride_raw = -src_stride_raw;
3571
0
  }
3572
  // TODO: add row coalesce when main loop handles large width in blocks
3573
  // TODO: implement UV444 or trim the ifdef below
3574
0
#if defined(HAS_ARGBTOUV444ROW_SSSE3)
3575
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3576
0
    ARGBToUV444Row = ARGBToUV444Row_Any_SSSE3;
3577
0
    if (IS_ALIGNED(width, 16)) {
3578
0
      ARGBToUV444Row = ARGBToUV444Row_SSSE3;
3579
0
    }
3580
0
  }
3581
0
#endif
3582
0
#if defined(HAS_ARGBTOUV444ROW_AVX2)
3583
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3584
0
    ARGBToUV444Row = ARGBToUV444Row_Any_AVX2;
3585
0
    if (IS_ALIGNED(width, 32)) {
3586
0
      ARGBToUV444Row = ARGBToUV444Row_AVX2;
3587
0
    }
3588
0
  }
3589
0
#endif
3590
#if defined(HAS_ARGBTOUV444ROW_NEON)
3591
  if (TestCpuFlag(kCpuHasNEON)) {
3592
    ARGBToUV444Row = ARGBToUV444Row_Any_NEON;
3593
    if (IS_ALIGNED(width, 8)) {
3594
      ARGBToUV444Row = ARGBToUV444Row_NEON;
3595
    }
3596
  }
3597
#endif
3598
#if defined(HAS_ARGBTOUV444ROW_NEON_I8MM)
3599
  if (TestCpuFlag(kCpuHasNeonI8MM)) {
3600
    ARGBToUV444Row = ARGBToUV444Row_Any_NEON_I8MM;
3601
    if (IS_ALIGNED(width, 8)) {
3602
      ARGBToUV444Row = ARGBToUV444Row_NEON_I8MM;
3603
    }
3604
  }
3605
#endif
3606
#if defined(HAS_ARGBTOUV444ROW_MSA)
3607
  if (TestCpuFlag(kCpuHasMSA)) {
3608
    ARGBToUV444Row = ARGBToUV444Row_Any_MSA;
3609
    if (IS_ALIGNED(width, 16)) {
3610
      ARGBToUV444Row = ARGBToUV444Row_MSA;
3611
    }
3612
  }
3613
#endif
3614
#if defined(HAS_ARGBTOUV444ROW_LSX)
3615
  if (TestCpuFlag(kCpuHasLSX)) {
3616
    ARGBToUV444Row = ARGBToUV444Row_Any_LSX;
3617
    if (IS_ALIGNED(width, 16)) {
3618
      ARGBToUV444Row = ARGBToUV444Row_LSX;
3619
    }
3620
  }
3621
#endif
3622
#if defined(HAS_ARGBTOUV444ROW_LASX)
3623
  if (TestCpuFlag(kCpuHasLASX)) {
3624
    ARGBToUV444Row = ARGBToUV444Row_Any_LASX;
3625
    if (IS_ALIGNED(width, 32)) {
3626
      ARGBToUV444Row = ARGBToUV444Row_LASX;
3627
    }
3628
  }
3629
#endif
3630
0
#if defined(HAS_ARGBTOYROW_SSSE3)
3631
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3632
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
3633
0
    if (IS_ALIGNED(width, 16)) {
3634
0
      ARGBToYRow = ARGBToYRow_SSSE3;
3635
0
    }
3636
0
  }
3637
0
#endif
3638
0
#if defined(HAS_ARGBTOYROW_AVX2)
3639
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3640
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
3641
0
    if (IS_ALIGNED(width, 32)) {
3642
0
      ARGBToYRow = ARGBToYRow_AVX2;
3643
0
    }
3644
0
  }
3645
0
#endif
3646
#if defined(HAS_ARGBTOYROW_NEON)
3647
  if (TestCpuFlag(kCpuHasNEON)) {
3648
    ARGBToYRow = ARGBToYRow_Any_NEON;
3649
    if (IS_ALIGNED(width, 16)) {
3650
      ARGBToYRow = ARGBToYRow_NEON;
3651
    }
3652
  }
3653
#endif
3654
#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
3655
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
3656
    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
3657
    if (IS_ALIGNED(width, 16)) {
3658
      ARGBToYRow = ARGBToYRow_NEON_DotProd;
3659
    }
3660
  }
3661
#endif
3662
#if defined(HAS_ARGBTOYROW_MSA)
3663
  if (TestCpuFlag(kCpuHasMSA)) {
3664
    ARGBToYRow = ARGBToYRow_Any_MSA;
3665
    if (IS_ALIGNED(width, 16)) {
3666
      ARGBToYRow = ARGBToYRow_MSA;
3667
    }
3668
  }
3669
#endif
3670
#if defined(HAS_ARGBTOYROW_LSX)
3671
  if (TestCpuFlag(kCpuHasLSX)) {
3672
    ARGBToYRow = ARGBToYRow_Any_LSX;
3673
    if (IS_ALIGNED(width, 16)) {
3674
      ARGBToYRow = ARGBToYRow_LSX;
3675
    }
3676
  }
3677
#endif
3678
#if defined(HAS_ARGBTOYROW_LASX)
3679
  if (TestCpuFlag(kCpuHasLASX)) {
3680
    ARGBToYRow = ARGBToYRow_Any_LASX;
3681
    if (IS_ALIGNED(width, 32)) {
3682
      ARGBToYRow = ARGBToYRow_LASX;
3683
    }
3684
  }
3685
#endif
3686
#if defined(HAS_ARGBTOYROW_RVV)
3687
  if (TestCpuFlag(kCpuHasRVV)) {
3688
    ARGBToYRow = ARGBToYRow_RVV;
3689
  }
3690
#endif
3691
3692
0
#if defined(HAS_RAWTOARGBROW_SSSE3)
3693
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3694
0
    RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
3695
0
    if (IS_ALIGNED(width, 16)) {
3696
0
      RAWToARGBRow = RAWToARGBRow_SSSE3;
3697
0
    }
3698
0
  }
3699
0
#endif
3700
0
#if defined(HAS_RAWTOARGBROW_AVX2)
3701
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3702
0
    RAWToARGBRow = RAWToARGBRow_Any_AVX2;
3703
0
    if (IS_ALIGNED(width, 32)) {
3704
0
      RAWToARGBRow = RAWToARGBRow_AVX2;
3705
0
    }
3706
0
  }
3707
0
#endif
3708
#if defined(HAS_RAWTOARGBROW_NEON)
3709
  if (TestCpuFlag(kCpuHasNEON)) {
3710
    RAWToARGBRow = RAWToARGBRow_Any_NEON;
3711
    if (IS_ALIGNED(width, 8)) {
3712
      RAWToARGBRow = RAWToARGBRow_NEON;
3713
    }
3714
  }
3715
#endif
3716
#if defined(HAS_RAWTOARGBROW_SVE2)
3717
  if (TestCpuFlag(kCpuHasSVE2)) {
3718
    RAWToARGBRow = RAWToARGBRow_SVE2;
3719
  }
3720
#endif
3721
#if defined(HAS_RAWTOARGBROW_MSA)
3722
  if (TestCpuFlag(kCpuHasMSA)) {
3723
    RAWToARGBRow = RAWToARGBRow_Any_MSA;
3724
    if (IS_ALIGNED(width, 16)) {
3725
      RAWToARGBRow = RAWToARGBRow_MSA;
3726
    }
3727
  }
3728
#endif
3729
#if defined(HAS_RAWTOARGBROW_LSX)
3730
  if (TestCpuFlag(kCpuHasLSX)) {
3731
    RAWToARGBRow = RAWToARGBRow_Any_LSX;
3732
    if (IS_ALIGNED(width, 16)) {
3733
      RAWToARGBRow = RAWToARGBRow_LSX;
3734
    }
3735
  }
3736
#endif
3737
#if defined(HAS_RAWTOARGBROW_LASX)
3738
  if (TestCpuFlag(kCpuHasLASX)) {
3739
    RAWToARGBRow = RAWToARGBRow_Any_LASX;
3740
    if (IS_ALIGNED(width, 32)) {
3741
      RAWToARGBRow = RAWToARGBRow_LASX;
3742
    }
3743
  }
3744
#endif
3745
#if defined(HAS_RAWTOARGBROW_RVV)
3746
  if (TestCpuFlag(kCpuHasRVV)) {
3747
    RAWToARGBRow = RAWToARGBRow_RVV;
3748
  }
3749
#endif
3750
3751
0
  {
3752
    // Allocate a row of ARGB.
3753
0
    const int row_size = width * 4;
3754
0
    align_buffer_64(row, row_size);
3755
0
    if (!row)
3756
0
      return 1;
3757
3758
0
    for (y = 0; y < height; ++y) {
3759
0
      RAWToARGBRow(src_raw, row, width);
3760
0
      ARGBToUV444Row(row, dst_u, dst_v, width);
3761
0
      ARGBToYRow(row, dst_y, width);
3762
0
      src_raw += src_stride_raw;
3763
0
      dst_y += dst_stride_y;
3764
0
      dst_u += dst_stride_u;
3765
0
      dst_v += dst_stride_v;
3766
0
    }
3767
0
    free_aligned_buffer_64(row);
3768
0
  }
3769
0
  return 0;
3770
0
}
3771
3772
// RAW big endian (rgb in memory) to J444
3773
// 2 step conversion of RAWToARGB then ARGBToYJ and ARGBToUVJ444
3774
LIBYUV_API
3775
int RAWToJ444(const uint8_t* src_raw,
3776
              int src_stride_raw,
3777
              uint8_t* dst_y,
3778
              int dst_stride_y,
3779
              uint8_t* dst_u,
3780
              int dst_stride_u,
3781
              uint8_t* dst_v,
3782
              int dst_stride_v,
3783
              int width,
3784
0
              int height) {
3785
0
  int y;
3786
0
  void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
3787
0
      RAWToARGBRow_C;
3788
0
  void (*ARGBToYJRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
3789
0
      ARGBToYJRow_C;
3790
0
  void (*ARGBToUVJ444Row)(const uint8_t* src_raw, uint8_t* dst_u,
3791
0
                          uint8_t* dst_v, int width) = ARGBToUVJ444Row_C;
3792
0
  if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
3793
0
    return -1;
3794
0
  }
3795
0
  if (height < 0) {
3796
0
    height = -height;
3797
0
    src_raw = src_raw + (height - 1) * src_stride_raw;
3798
0
    src_stride_raw = -src_stride_raw;
3799
0
  }
3800
  // TODO: add row coalesce when main loop handles large width in blocks
3801
0
#if defined(HAS_ARGBTOUVJ444ROW_SSSE3)
3802
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3803
0
    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_SSSE3;
3804
0
    if (IS_ALIGNED(width, 16)) {
3805
0
      ARGBToUVJ444Row = ARGBToUVJ444Row_SSSE3;
3806
0
    }
3807
0
  }
3808
0
#endif
3809
0
#if defined(HAS_ARGBTOUVJ444ROW_AVX2)
3810
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3811
0
    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_AVX2;
3812
0
    if (IS_ALIGNED(width, 32)) {
3813
0
      ARGBToUVJ444Row = ARGBToUVJ444Row_AVX2;
3814
0
    }
3815
0
  }
3816
0
#endif
3817
#if defined(HAS_ARGBTOUVJ444ROW_NEON)
3818
  if (TestCpuFlag(kCpuHasNEON)) {
3819
    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_NEON;
3820
    if (IS_ALIGNED(width, 8)) {
3821
      ARGBToUVJ444Row = ARGBToUVJ444Row_NEON;
3822
    }
3823
  }
3824
#endif
3825
#if defined(HAS_ARGBTOUVJ444ROW_NEON_I8MM)
3826
  if (TestCpuFlag(kCpuHasNeonI8MM)) {
3827
    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_NEON_I8MM;
3828
    if (IS_ALIGNED(width, 8)) {
3829
      ARGBToUVJ444Row = ARGBToUVJ444Row_NEON_I8MM;
3830
    }
3831
  }
3832
#endif
3833
#if defined(HAS_ARGBTOUVJ444ROW_MSA)
3834
  if (TestCpuFlag(kCpuHasMSA)) {
3835
    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_MSA;
3836
    if (IS_ALIGNED(width, 16)) {
3837
      ARGBToUVJ444Row = ARGBToUVJ444Row_MSA;
3838
    }
3839
  }
3840
#endif
3841
#if defined(HAS_ARGBTOUVJ444ROW_LSX)
3842
  if (TestCpuFlag(kCpuHasLSX)) {
3843
    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_LSX;
3844
    if (IS_ALIGNED(width, 16)) {
3845
      ARGBToUVJ444Row = ARGBToUVJ444Row_LSX;
3846
    }
3847
  }
3848
#endif
3849
#if defined(HAS_ARGBTOUVJ444ROW_LASX)
3850
  if (TestCpuFlag(kCpuHasLASX)) {
3851
    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_LASX;
3852
    if (IS_ALIGNED(width, 32)) {
3853
      ARGBToUVJ444Row = ARGBToUVJ444Row_LASX;
3854
    }
3855
  }
3856
#endif
3857
0
#if defined(HAS_ARGBTOYJROW_SSSE3)
3858
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3859
0
    ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
3860
0
    if (IS_ALIGNED(width, 16)) {
3861
0
      ARGBToYJRow = ARGBToYJRow_SSSE3;
3862
0
    }
3863
0
  }
3864
0
#endif
3865
0
#if defined(HAS_ARGBTOYJROW_AVX2)
3866
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3867
0
    ARGBToYJRow = ARGBToYJRow_Any_AVX2;
3868
0
    if (IS_ALIGNED(width, 32)) {
3869
0
      ARGBToYJRow = ARGBToYJRow_AVX2;
3870
0
    }
3871
0
  }
3872
0
#endif
3873
#if defined(HAS_ARGBTOYJROW_NEON)
3874
  if (TestCpuFlag(kCpuHasNEON)) {
3875
    ARGBToYJRow = ARGBToYJRow_Any_NEON;
3876
    if (IS_ALIGNED(width, 16)) {
3877
      ARGBToYJRow = ARGBToYJRow_NEON;
3878
    }
3879
  }
3880
#endif
3881
#if defined(HAS_ARGBTOYJROW_NEON_DOTPROD)
3882
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
3883
    ARGBToYJRow = ARGBToYJRow_Any_NEON_DotProd;
3884
    if (IS_ALIGNED(width, 16)) {
3885
      ARGBToYJRow = ARGBToYJRow_NEON_DotProd;
3886
    }
3887
  }
3888
#endif
3889
#if defined(HAS_ARGBTOYJROW_MSA)
3890
  if (TestCpuFlag(kCpuHasMSA)) {
3891
    ARGBToYJRow = ARGBToYJRow_Any_MSA;
3892
    if (IS_ALIGNED(width, 16)) {
3893
      ARGBToYJRow = ARGBToYJRow_MSA;
3894
    }
3895
  }
3896
#endif
3897
#if defined(HAS_ARGBTOYJROW_LSX)
3898
  if (TestCpuFlag(kCpuHasLSX)) {
3899
    ARGBToYJRow = ARGBToYJRow_Any_LSX;
3900
    if (IS_ALIGNED(width, 16)) {
3901
      ARGBToYJRow = ARGBToYJRow_LSX;
3902
    }
3903
  }
3904
#endif
3905
#if defined(HAS_ARGBTOYJROW_LASX)
3906
  if (TestCpuFlag(kCpuHasLASX)) {
3907
    ARGBToYJRow = ARGBToYJRow_Any_LASX;
3908
    if (IS_ALIGNED(width, 32)) {
3909
      ARGBToYJRow = ARGBToYJRow_LASX;
3910
    }
3911
  }
3912
#endif
3913
#if defined(HAS_ARGBTOYJROW_RVV)
3914
  if (TestCpuFlag(kCpuHasRVV)) {
3915
    ARGBToYJRow = ARGBToYJRow_RVV;
3916
  }
3917
#endif
3918
3919
0
#if defined(HAS_RAWTOARGBROW_SSSE3)
3920
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3921
0
    RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
3922
0
    if (IS_ALIGNED(width, 16)) {
3923
0
      RAWToARGBRow = RAWToARGBRow_SSSE3;
3924
0
    }
3925
0
  }
3926
0
#endif
3927
0
#if defined(HAS_RAWTOARGBROW_AVX2)
3928
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3929
0
    RAWToARGBRow = RAWToARGBRow_Any_AVX2;
3930
0
    if (IS_ALIGNED(width, 32)) {
3931
0
      RAWToARGBRow = RAWToARGBRow_AVX2;
3932
0
    }
3933
0
  }
3934
0
#endif
3935
#if defined(HAS_RAWTOARGBROW_NEON)
3936
  if (TestCpuFlag(kCpuHasNEON)) {
3937
    RAWToARGBRow = RAWToARGBRow_Any_NEON;
3938
    if (IS_ALIGNED(width, 8)) {
3939
      RAWToARGBRow = RAWToARGBRow_NEON;
3940
    }
3941
  }
3942
#endif
3943
#if defined(HAS_RAWTOARGBROW_SVE2)
3944
  if (TestCpuFlag(kCpuHasSVE2)) {
3945
    RAWToARGBRow = RAWToARGBRow_SVE2;
3946
  }
3947
#endif
3948
#if defined(HAS_RAWTOARGBROW_MSA)
3949
  if (TestCpuFlag(kCpuHasMSA)) {
3950
    RAWToARGBRow = RAWToARGBRow_Any_MSA;
3951
    if (IS_ALIGNED(width, 16)) {
3952
      RAWToARGBRow = RAWToARGBRow_MSA;
3953
    }
3954
  }
3955
#endif
3956
#if defined(HAS_RAWTOARGBROW_LSX)
3957
  if (TestCpuFlag(kCpuHasLSX)) {
3958
    RAWToARGBRow = RAWToARGBRow_Any_LSX;
3959
    if (IS_ALIGNED(width, 16)) {
3960
      RAWToARGBRow = RAWToARGBRow_LSX;
3961
    }
3962
  }
3963
#endif
3964
#if defined(HAS_RAWTOARGBROW_LASX)
3965
  if (TestCpuFlag(kCpuHasLASX)) {
3966
    RAWToARGBRow = RAWToARGBRow_Any_LASX;
3967
    if (IS_ALIGNED(width, 32)) {
3968
      RAWToARGBRow = RAWToARGBRow_LASX;
3969
    }
3970
  }
3971
#endif
3972
#if defined(HAS_RAWTOARGBROW_RVV)
3973
  if (TestCpuFlag(kCpuHasRVV)) {
3974
    RAWToARGBRow = RAWToARGBRow_RVV;
3975
  }
3976
#endif
3977
3978
0
  {
3979
    // Allocate a row of ARGB.
3980
0
    const int row_size = width * 4;
3981
0
    align_buffer_64(row, row_size);
3982
0
    if (!row)
3983
0
      return 1;
3984
3985
0
    for (y = 0; y < height; ++y) {
3986
0
      RAWToARGBRow(src_raw, row, width);
3987
0
      ARGBToUVJ444Row(row, dst_u, dst_v, width);
3988
0
      ARGBToYJRow(row, dst_y, width);
3989
0
      src_raw += src_stride_raw;
3990
0
      dst_y += dst_stride_y;
3991
0
      dst_u += dst_stride_u;
3992
0
      dst_v += dst_stride_v;
3993
0
    }
3994
0
    free_aligned_buffer_64(row);
3995
0
  }
3996
0
  return 0;
3997
0
}
3998
3999
// Convert RGB565 to I420.
4000
LIBYUV_API
4001
int RGB565ToI420(const uint8_t* src_rgb565,
4002
                 int src_stride_rgb565,
4003
                 uint8_t* dst_y,
4004
                 int dst_stride_y,
4005
                 uint8_t* dst_u,
4006
                 int dst_stride_u,
4007
                 uint8_t* dst_v,
4008
                 int dst_stride_v,
4009
                 int width,
4010
0
                 int height) {
4011
0
  int y;
4012
#if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
4013
     defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
4014
  void (*RGB565ToUVRow)(const uint8_t* src_rgb565, int src_stride_rgb565,
4015
                        uint8_t* dst_u, uint8_t* dst_v, int width) =
4016
      RGB565ToUVRow_C;
4017
  void (*RGB565ToYRow)(const uint8_t* src_rgb565, uint8_t* dst_y, int width) =
4018
      RGB565ToYRow_C;
4019
#else
4020
0
  void (*RGB565ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
4021
0
                          int width) = RGB565ToARGBRow_C;
4022
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
4023
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
4024
0
      ARGBToUVRow_C;
4025
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
4026
0
      ARGBToYRow_C;
4027
0
#endif
4028
0
  if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
4029
0
    return -1;
4030
0
  }
4031
  // Negative height means invert the image.
4032
0
  if (height < 0) {
4033
0
    height = -height;
4034
0
    src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
4035
0
    src_stride_rgb565 = -src_stride_rgb565;
4036
0
  }
4037
4038
// Neon version does direct RGB565 to YUV.
4039
#if defined(HAS_RGB565TOYROW_NEON)
4040
  if (TestCpuFlag(kCpuHasNEON)) {
4041
    RGB565ToYRow = RGB565ToYRow_Any_NEON;
4042
    if (IS_ALIGNED(width, 16)) {
4043
      RGB565ToYRow = RGB565ToYRow_NEON;
4044
    }
4045
  }
4046
#endif
4047
// Neon version does direct RGB565 to YUV.
4048
#if defined(HAS_RGB565TOUVROW_NEON)
4049
  if (TestCpuFlag(kCpuHasNEON)) {
4050
    RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
4051
    if (IS_ALIGNED(width, 16)) {
4052
      RGB565ToUVRow = RGB565ToUVRow_NEON;
4053
    }
4054
  }
4055
#endif
4056
// MSA version does direct RGB565 to YUV.
4057
#if defined(HAS_RGB565TOYROW_MSA) && defined(HAS_RGB565TOUVROW_MSA)
4058
  if (TestCpuFlag(kCpuHasMSA)) {
4059
    RGB565ToUVRow = RGB565ToUVRow_Any_MSA;
4060
    RGB565ToYRow = RGB565ToYRow_Any_MSA;
4061
    if (IS_ALIGNED(width, 16)) {
4062
      RGB565ToYRow = RGB565ToYRow_MSA;
4063
      RGB565ToUVRow = RGB565ToUVRow_MSA;
4064
    }
4065
  }
4066
#endif
4067
#if defined(HAS_RGB565TOYROW_LSX) && defined(HAS_RGB565TOUVROW_LSX)
4068
  if (TestCpuFlag(kCpuHasLSX)) {
4069
    RGB565ToUVRow = RGB565ToUVRow_Any_LSX;
4070
    RGB565ToYRow = RGB565ToYRow_Any_LSX;
4071
    if (IS_ALIGNED(width, 16)) {
4072
      RGB565ToYRow = RGB565ToYRow_LSX;
4073
      RGB565ToUVRow = RGB565ToUVRow_LSX;
4074
    }
4075
  }
4076
#endif
4077
#if defined(HAS_RGB565TOYROW_LASX) && defined(HAS_RGB565TOUVROW_LASX)
4078
  if (TestCpuFlag(kCpuHasLASX)) {
4079
    RGB565ToUVRow = RGB565ToUVRow_Any_LASX;
4080
    RGB565ToYRow = RGB565ToYRow_Any_LASX;
4081
    if (IS_ALIGNED(width, 32)) {
4082
      RGB565ToYRow = RGB565ToYRow_LASX;
4083
      RGB565ToUVRow = RGB565ToUVRow_LASX;
4084
    }
4085
  }
4086
#endif
4087
// Other platforms do intermediate conversion from RGB565 to ARGB.
4088
0
#if defined(HAS_RGB565TOARGBROW_SSE2)
4089
0
  if (TestCpuFlag(kCpuHasSSE2)) {
4090
0
    RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
4091
0
    if (IS_ALIGNED(width, 8)) {
4092
0
      RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
4093
0
    }
4094
0
  }
4095
0
#endif
4096
#if defined(HAS_RGB565TOARGBROW_AVX2)
4097
  if (TestCpuFlag(kCpuHasAVX2)) {
4098
    RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
4099
    if (IS_ALIGNED(width, 16)) {
4100
      RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
4101
    }
4102
  }
4103
#endif
4104
0
#if defined(HAS_ARGBTOYROW_SSSE3)
4105
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
4106
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
4107
0
    if (IS_ALIGNED(width, 16)) {
4108
0
      ARGBToYRow = ARGBToYRow_SSSE3;
4109
0
    }
4110
0
  }
4111
0
#endif
4112
0
#if defined(HAS_ARGBTOYROW_AVX2)
4113
0
  if (TestCpuFlag(kCpuHasAVX2)) {
4114
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
4115
0
    if (IS_ALIGNED(width, 32)) {
4116
0
      ARGBToYRow = ARGBToYRow_AVX2;
4117
0
    }
4118
0
  }
4119
0
#endif
4120
0
#if defined(HAS_ARGBTOUVROW_SSSE3)
4121
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
4122
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
4123
0
    if (IS_ALIGNED(width, 16)) {
4124
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
4125
0
    }
4126
0
  }
4127
0
#endif
4128
0
#if defined(HAS_ARGBTOUVROW_AVX2)
4129
0
  if (TestCpuFlag(kCpuHasAVX2)) {
4130
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
4131
0
    if (IS_ALIGNED(width, 32)) {
4132
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
4133
0
    }
4134
0
  }
4135
0
#endif
4136
0
  {
4137
0
#if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
4138
0
      defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
4139
    // Allocate 2 rows of ARGB.
4140
0
    const int row_size = (width * 4 + 31) & ~31;
4141
0
    align_buffer_64(row, row_size * 2);
4142
0
    if (!row)
4143
0
      return 1;
4144
0
#endif
4145
0
    for (y = 0; y < height - 1; y += 2) {
4146
#if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
4147
     defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
4148
      RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
4149
      RGB565ToYRow(src_rgb565, dst_y, width);
4150
      RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
4151
#else
4152
0
      RGB565ToARGBRow(src_rgb565, row, width);
4153
0
      RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + row_size, width);
4154
0
      ARGBToUVRow(row, row_size, dst_u, dst_v, width);
4155
0
      ARGBToYRow(row, dst_y, width);
4156
0
      ARGBToYRow(row + row_size, dst_y + dst_stride_y, width);
4157
0
#endif
4158
0
      src_rgb565 += src_stride_rgb565 * 2;
4159
0
      dst_y += dst_stride_y * 2;
4160
0
      dst_u += dst_stride_u;
4161
0
      dst_v += dst_stride_v;
4162
0
    }
4163
0
    if (height & 1) {
4164
#if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
4165
     defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
4166
      RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
4167
      RGB565ToYRow(src_rgb565, dst_y, width);
4168
#else
4169
0
      RGB565ToARGBRow(src_rgb565, row, width);
4170
0
      ARGBToUVRow(row, 0, dst_u, dst_v, width);
4171
0
      ARGBToYRow(row, dst_y, width);
4172
0
#endif
4173
0
    }
4174
0
#if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
4175
0
      defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
4176
0
    free_aligned_buffer_64(row);
4177
0
#endif
4178
0
  }
4179
0
  return 0;
4180
0
}
4181
4182
// Convert ARGB1555 to I420.
4183
LIBYUV_API
4184
int ARGB1555ToI420(const uint8_t* src_argb1555,
4185
                   int src_stride_argb1555,
4186
                   uint8_t* dst_y,
4187
                   int dst_stride_y,
4188
                   uint8_t* dst_u,
4189
                   int dst_stride_u,
4190
                   uint8_t* dst_v,
4191
                   int dst_stride_v,
4192
                   int width,
4193
0
                   int height) {
4194
0
  int y;
4195
#if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
4196
     defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
4197
  void (*ARGB1555ToUVRow)(const uint8_t* src_argb1555, int src_stride_argb1555,
4198
                          uint8_t* dst_u, uint8_t* dst_v, int width) =
4199
      ARGB1555ToUVRow_C;
4200
  void (*ARGB1555ToYRow)(const uint8_t* src_argb1555, uint8_t* dst_y,
4201
                         int width) = ARGB1555ToYRow_C;
4202
#else
4203
0
  void (*ARGB1555ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
4204
0
                            int width) = ARGB1555ToARGBRow_C;
4205
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
4206
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
4207
0
      ARGBToUVRow_C;
4208
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
4209
0
      ARGBToYRow_C;
4210
0
#endif
4211
0
  if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
4212
0
      height == 0) {
4213
0
    return -1;
4214
0
  }
4215
  // Negative height means invert the image.
4216
0
  if (height < 0) {
4217
0
    height = -height;
4218
0
    src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
4219
0
    src_stride_argb1555 = -src_stride_argb1555;
4220
0
  }
4221
4222
// Neon version does direct ARGB1555 to YUV.
4223
#if defined(HAS_ARGB1555TOYROW_NEON)
4224
  if (TestCpuFlag(kCpuHasNEON)) {
4225
    ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
4226
    if (IS_ALIGNED(width, 8)) {
4227
      ARGB1555ToYRow = ARGB1555ToYRow_NEON;
4228
    }
4229
  }
4230
#endif
4231
#if defined(HAS_ARGB1555TOUVROW_NEON)
4232
  if (TestCpuFlag(kCpuHasNEON)) {
4233
    ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
4234
    if (IS_ALIGNED(width, 16)) {
4235
      ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
4236
    }
4237
  }
4238
#endif
4239
4240
// MSA version does direct ARGB1555 to YUV.
4241
#if defined(HAS_ARGB1555TOYROW_MSA) && defined(HAS_ARGB1555TOUVROW_MSA)
4242
  if (TestCpuFlag(kCpuHasMSA)) {
4243
    ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA;
4244
    ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA;
4245
    if (IS_ALIGNED(width, 16)) {
4246
      ARGB1555ToYRow = ARGB1555ToYRow_MSA;
4247
      ARGB1555ToUVRow = ARGB1555ToUVRow_MSA;
4248
    }
4249
  }
4250
#endif
4251
#if defined(HAS_ARGB1555TOYROW_LSX) && defined(HAS_ARGB1555TOUVROW_LSX)
4252
  if (TestCpuFlag(kCpuHasLSX)) {
4253
    ARGB1555ToUVRow = ARGB1555ToUVRow_Any_LSX;
4254
    ARGB1555ToYRow = ARGB1555ToYRow_Any_LSX;
4255
    if (IS_ALIGNED(width, 16)) {
4256
      ARGB1555ToYRow = ARGB1555ToYRow_LSX;
4257
      ARGB1555ToUVRow = ARGB1555ToUVRow_LSX;
4258
    }
4259
  }
4260
#endif
4261
#if defined(HAS_ARGB1555TOYROW_LASX) && defined(HAS_ARGB1555TOUVROW_LASX)
4262
  if (TestCpuFlag(kCpuHasLASX)) {
4263
    ARGB1555ToUVRow = ARGB1555ToUVRow_Any_LASX;
4264
    ARGB1555ToYRow = ARGB1555ToYRow_Any_LASX;
4265
    if (IS_ALIGNED(width, 32)) {
4266
      ARGB1555ToYRow = ARGB1555ToYRow_LASX;
4267
      ARGB1555ToUVRow = ARGB1555ToUVRow_LASX;
4268
    }
4269
  }
4270
#endif
4271
4272
// Other platforms do intermediate conversion from ARGB1555 to ARGB.
4273
0
#if defined(HAS_ARGB1555TOARGBROW_SSE2)
4274
0
  if (TestCpuFlag(kCpuHasSSE2)) {
4275
0
    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
4276
0
    if (IS_ALIGNED(width, 8)) {
4277
0
      ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
4278
0
    }
4279
0
  }
4280
0
#endif
4281
#if defined(HAS_ARGB1555TOARGBROW_AVX2)
4282
  if (TestCpuFlag(kCpuHasAVX2)) {
4283
    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
4284
    if (IS_ALIGNED(width, 16)) {
4285
      ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
4286
    }
4287
  }
4288
#endif
4289
0
#if defined(HAS_ARGBTOYROW_SSSE3)
4290
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
4291
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
4292
0
    if (IS_ALIGNED(width, 16)) {
4293
0
      ARGBToYRow = ARGBToYRow_SSSE3;
4294
0
    }
4295
0
  }
4296
0
#endif
4297
0
#if defined(HAS_ARGBTOUVROW_SSSE3)
4298
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
4299
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
4300
0
    if (IS_ALIGNED(width, 16)) {
4301
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
4302
0
    }
4303
0
  }
4304
0
#endif
4305
0
#if defined(HAS_ARGBTOYROW_AVX2)
4306
0
  if (TestCpuFlag(kCpuHasAVX2)) {
4307
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
4308
0
    if (IS_ALIGNED(width, 32)) {
4309
0
      ARGBToYRow = ARGBToYRow_AVX2;
4310
0
    }
4311
0
  }
4312
0
#endif
4313
0
#if defined(HAS_ARGBTOUVROW_AVX2)
4314
0
  if (TestCpuFlag(kCpuHasAVX2)) {
4315
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
4316
0
    if (IS_ALIGNED(width, 32)) {
4317
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
4318
0
    }
4319
0
  }
4320
0
#endif
4321
0
  {
4322
0
#if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
4323
0
      defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
4324
    // Allocate 2 rows of ARGB.
4325
0
    const int row_size = (width * 4 + 31) & ~31;
4326
0
    align_buffer_64(row, row_size * 2);
4327
0
    if (!row)
4328
0
      return 1;
4329
0
#endif
4330
4331
0
    for (y = 0; y < height - 1; y += 2) {
4332
#if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
4333
     defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
4334
      ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
4335
      ARGB1555ToYRow(src_argb1555, dst_y, width);
4336
      ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
4337
                     width);
4338
#else
4339
0
      ARGB1555ToARGBRow(src_argb1555, row, width);
4340
0
      ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + row_size,
4341
0
                        width);
4342
0
      ARGBToUVRow(row, row_size, dst_u, dst_v, width);
4343
0
      ARGBToYRow(row, dst_y, width);
4344
0
      ARGBToYRow(row + row_size, dst_y + dst_stride_y, width);
4345
0
#endif
4346
0
      src_argb1555 += src_stride_argb1555 * 2;
4347
0
      dst_y += dst_stride_y * 2;
4348
0
      dst_u += dst_stride_u;
4349
0
      dst_v += dst_stride_v;
4350
0
    }
4351
0
    if (height & 1) {
4352
#if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
4353
     defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
4354
      ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
4355
      ARGB1555ToYRow(src_argb1555, dst_y, width);
4356
#else
4357
0
      ARGB1555ToARGBRow(src_argb1555, row, width);
4358
0
      ARGBToUVRow(row, 0, dst_u, dst_v, width);
4359
0
      ARGBToYRow(row, dst_y, width);
4360
0
#endif
4361
0
    }
4362
0
#if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
4363
0
      defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
4364
0
    free_aligned_buffer_64(row);
4365
0
#endif
4366
0
  }
4367
0
  return 0;
4368
0
}
4369
4370
// Convert ARGB4444 to I420.
4371
LIBYUV_API
4372
int ARGB4444ToI420(const uint8_t* src_argb4444,
4373
                   int src_stride_argb4444,
4374
                   uint8_t* dst_y,
4375
                   int dst_stride_y,
4376
                   uint8_t* dst_u,
4377
                   int dst_stride_u,
4378
                   uint8_t* dst_v,
4379
                   int dst_stride_v,
4380
                   int width,
4381
0
                   int height) {
4382
0
  int y;
4383
#if defined(HAS_ARGB4444TOYROW_NEON)
4384
  void (*ARGB4444ToUVRow)(const uint8_t* src_argb4444, int src_stride_argb4444,
4385
                          uint8_t* dst_u, uint8_t* dst_v, int width) =
4386
      ARGB4444ToUVRow_C;
4387
  void (*ARGB4444ToYRow)(const uint8_t* src_argb4444, uint8_t* dst_y,
4388
                         int width) = ARGB4444ToYRow_C;
4389
#else
4390
0
  void (*ARGB4444ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
4391
0
                            int width) = ARGB4444ToARGBRow_C;
4392
0
  void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
4393
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
4394
0
      ARGBToUVRow_C;
4395
0
  void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
4396
0
      ARGBToYRow_C;
4397
0
#endif
4398
0
  if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
4399
0
      height == 0) {
4400
0
    return -1;
4401
0
  }
4402
  // Negative height means invert the image.
4403
0
  if (height < 0) {
4404
0
    height = -height;
4405
0
    src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
4406
0
    src_stride_argb4444 = -src_stride_argb4444;
4407
0
  }
4408
4409
// Neon version does direct ARGB4444 to YUV.
4410
#if defined(HAS_ARGB4444TOYROW_NEON)
4411
  if (TestCpuFlag(kCpuHasNEON)) {
4412
    ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
4413
    if (IS_ALIGNED(width, 8)) {
4414
      ARGB4444ToYRow = ARGB4444ToYRow_NEON;
4415
    }
4416
  }
4417
#endif
4418
#if defined(HAS_ARGB4444TOUVROW_NEON)
4419
  if (TestCpuFlag(kCpuHasNEON)) {
4420
    ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
4421
    if (IS_ALIGNED(width, 16)) {
4422
      ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
4423
    }
4424
  }
4425
#endif
4426
0
#if defined(HAS_ARGB4444TOARGBROW_SSE2)
4427
0
  if (TestCpuFlag(kCpuHasSSE2)) {
4428
0
    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
4429
0
    if (IS_ALIGNED(width, 8)) {
4430
0
      ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
4431
0
    }
4432
0
  }
4433
0
#endif
4434
#if defined(HAS_ARGB4444TOARGBROW_AVX2)
4435
  if (TestCpuFlag(kCpuHasAVX2)) {
4436
    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
4437
    if (IS_ALIGNED(width, 16)) {
4438
      ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
4439
    }
4440
  }
4441
#endif
4442
#if defined(HAS_ARGB4444TOARGBROW_MSA)
4443
  if (TestCpuFlag(kCpuHasMSA)) {
4444
    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
4445
    if (IS_ALIGNED(width, 16)) {
4446
      ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
4447
    }
4448
  }
4449
#endif
4450
#if defined(HAS_ARGB4444TOARGBROW_LSX)
4451
  if (TestCpuFlag(kCpuHasLSX)) {
4452
    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_LSX;
4453
    if (IS_ALIGNED(width, 16)) {
4454
      ARGB4444ToARGBRow = ARGB4444ToARGBRow_LSX;
4455
    }
4456
  }
4457
#endif
4458
#if defined(HAS_ARGB4444TOARGBROW_LASX)
4459
  if (TestCpuFlag(kCpuHasLASX)) {
4460
    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_LASX;
4461
    if (IS_ALIGNED(width, 32)) {
4462
      ARGB4444ToARGBRow = ARGB4444ToARGBRow_LASX;
4463
    }
4464
  }
4465
#endif
4466
0
#if defined(HAS_ARGBTOYROW_SSSE3)
4467
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
4468
0
    ARGBToYRow = ARGBToYRow_Any_SSSE3;
4469
0
    if (IS_ALIGNED(width, 16)) {
4470
0
      ARGBToYRow = ARGBToYRow_SSSE3;
4471
0
    }
4472
0
  }
4473
0
#endif
4474
0
#if defined(HAS_ARGBTOUVROW_SSSE3)
4475
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
4476
0
    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
4477
0
    if (IS_ALIGNED(width, 16)) {
4478
0
      ARGBToUVRow = ARGBToUVRow_SSSE3;
4479
0
    }
4480
0
  }
4481
0
#endif
4482
0
#if defined(HAS_ARGBTOYROW_AVX2)
4483
0
  if (TestCpuFlag(kCpuHasAVX2)) {
4484
0
    ARGBToYRow = ARGBToYRow_Any_AVX2;
4485
0
    if (IS_ALIGNED(width, 32)) {
4486
0
      ARGBToYRow = ARGBToYRow_AVX2;
4487
0
    }
4488
0
  }
4489
0
#endif
4490
0
#if defined(HAS_ARGBTOUVROW_AVX2)
4491
0
  if (TestCpuFlag(kCpuHasAVX2)) {
4492
0
    ARGBToUVRow = ARGBToUVRow_Any_AVX2;
4493
0
    if (IS_ALIGNED(width, 32)) {
4494
0
      ARGBToUVRow = ARGBToUVRow_AVX2;
4495
0
    }
4496
0
  }
4497
0
#endif
4498
#if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
4499
  if (TestCpuFlag(kCpuHasMSA)) {
4500
    ARGBToUVRow = ARGBToUVRow_Any_MSA;
4501
    ARGBToYRow = ARGBToYRow_Any_MSA;
4502
    if (IS_ALIGNED(width, 16)) {
4503
      ARGBToYRow = ARGBToYRow_MSA;
4504
      if (IS_ALIGNED(width, 32)) {
4505
        ARGBToUVRow = ARGBToUVRow_MSA;
4506
      }
4507
    }
4508
  }
4509
#endif
4510
#if defined(HAS_ARGBTOYROW_LSX)
4511
  if (TestCpuFlag(kCpuHasLSX)) {
4512
    ARGBToYRow = ARGBToYRow_Any_LSX;
4513
    if (IS_ALIGNED(width, 16)) {
4514
      ARGBToYRow = ARGBToYRow_LSX;
4515
    }
4516
  }
4517
#endif
4518
#if defined(HAS_ARGBTOYROW_LSX) && defined(HAS_ARGBTOUVROW_LSX)
4519
  if (TestCpuFlag(kCpuHasLSX)) {
4520
    ARGBToYRow = ARGBToYRow_Any_LSX;
4521
    ARGBToUVRow = ARGBToUVRow_Any_LSX;
4522
    if (IS_ALIGNED(width, 16)) {
4523
      ARGBToYRow = ARGBToYRow_LSX;
4524
      ARGBToUVRow = ARGBToUVRow_LSX;
4525
    }
4526
  }
4527
#endif
4528
#if defined(HAS_ARGBTOYROW_LASX) && defined(HAS_ARGBTOUVROW_LASX)
4529
  if (TestCpuFlag(kCpuHasLASX)) {
4530
    ARGBToYRow = ARGBToYRow_Any_LASX;
4531
    ARGBToUVRow = ARGBToUVRow_Any_LASX;
4532
    if (IS_ALIGNED(width, 32)) {
4533
      ARGBToYRow = ARGBToYRow_LASX;
4534
      ARGBToUVRow = ARGBToUVRow_LASX;
4535
    }
4536
  }
4537
#endif
4538
4539
0
  {
4540
0
#if !(defined(HAS_ARGB4444TOYROW_NEON))
4541
    // Allocate 2 rows of ARGB.
4542
0
    const int row_size = (width * 4 + 31) & ~31;
4543
0
    align_buffer_64(row, row_size * 2);
4544
0
    if (!row)
4545
0
      return 1;
4546
0
#endif
4547
4548
0
    for (y = 0; y < height - 1; y += 2) {
4549
#if defined(HAS_ARGB4444TOYROW_NEON)
4550
      ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
4551
      ARGB4444ToYRow(src_argb4444, dst_y, width);
4552
      ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
4553
                     width);
4554
#else
4555
0
      ARGB4444ToARGBRow(src_argb4444, row, width);
4556
0
      ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + row_size,
4557
0
                        width);
4558
0
      ARGBToUVRow(row, row_size, dst_u, dst_v, width);
4559
0
      ARGBToYRow(row, dst_y, width);
4560
0
      ARGBToYRow(row + row_size, dst_y + dst_stride_y, width);
4561
0
#endif
4562
0
      src_argb4444 += src_stride_argb4444 * 2;
4563
0
      dst_y += dst_stride_y * 2;
4564
0
      dst_u += dst_stride_u;
4565
0
      dst_v += dst_stride_v;
4566
0
    }
4567
0
    if (height & 1) {
4568
#if defined(HAS_ARGB4444TOYROW_NEON)
4569
      ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
4570
      ARGB4444ToYRow(src_argb4444, dst_y, width);
4571
#else
4572
0
      ARGB4444ToARGBRow(src_argb4444, row, width);
4573
0
      ARGBToUVRow(row, 0, dst_u, dst_v, width);
4574
0
      ARGBToYRow(row, dst_y, width);
4575
0
#endif
4576
0
    }
4577
0
#if !(defined(HAS_ARGB4444TOYROW_NEON))
4578
0
    free_aligned_buffer_64(row);
4579
0
#endif
4580
0
  }
4581
0
  return 0;
4582
0
}
4583
4584
// Convert RGB24 to J400.
4585
LIBYUV_API
4586
int RGB24ToJ400(const uint8_t* src_rgb24,
4587
                int src_stride_rgb24,
4588
                uint8_t* dst_yj,
4589
                int dst_stride_yj,
4590
                int width,
4591
0
                int height) {
4592
0
  int y;
4593
0
  void (*RGB24ToYJRow)(const uint8_t* src_rgb24, uint8_t* dst_yj, int width) =
4594
0
      RGB24ToYJRow_C;
4595
0
  if (!src_rgb24 || !dst_yj || width <= 0 || height == 0) {
4596
0
    return -1;
4597
0
  }
4598
0
  if (height < 0) {
4599
0
    height = -height;
4600
0
    src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
4601
0
    src_stride_rgb24 = -src_stride_rgb24;
4602
0
  }
4603
  // Coalesce rows.
4604
0
  if (src_stride_rgb24 == width * 3 && dst_stride_yj == width) {
4605
0
    width *= height;
4606
0
    height = 1;
4607
0
    src_stride_rgb24 = dst_stride_yj = 0;
4608
0
  }
4609
0
#if defined(HAS_RGB24TOYJROW_SSSE3)
4610
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
4611
0
    RGB24ToYJRow = RGB24ToYJRow_Any_SSSE3;
4612
0
    if (IS_ALIGNED(width, 16)) {
4613
0
      RGB24ToYJRow = RGB24ToYJRow_SSSE3;
4614
0
    }
4615
0
  }
4616
0
#endif
4617
0
#if defined(HAS_RGB24TOYJROW_AVX2)
4618
0
  if (TestCpuFlag(kCpuHasAVX2)) {
4619
0
    RGB24ToYJRow = RGB24ToYJRow_Any_AVX2;
4620
0
    if (IS_ALIGNED(width, 32)) {
4621
0
      RGB24ToYJRow = RGB24ToYJRow_AVX2;
4622
0
    }
4623
0
  }
4624
0
#endif
4625
#if defined(HAS_RGB24TOYJROW_NEON)
4626
  if (TestCpuFlag(kCpuHasNEON)) {
4627
    RGB24ToYJRow = RGB24ToYJRow_Any_NEON;
4628
    if (IS_ALIGNED(width, 16)) {
4629
      RGB24ToYJRow = RGB24ToYJRow_NEON;
4630
    }
4631
  }
4632
#endif
4633
#if defined(HAS_RGB24TOYJROW_MSA)
4634
  if (TestCpuFlag(kCpuHasMSA)) {
4635
    RGB24ToYJRow = RGB24ToYJRow_Any_MSA;
4636
    if (IS_ALIGNED(width, 16)) {
4637
      RGB24ToYJRow = RGB24ToYJRow_MSA;
4638
    }
4639
  }
4640
#endif
4641
#if defined(HAS_RGB24TOYJROW_LSX)
4642
  if (TestCpuFlag(kCpuHasLSX)) {
4643
    RGB24ToYJRow = RGB24ToYJRow_Any_LSX;
4644
    if (IS_ALIGNED(width, 16)) {
4645
      RGB24ToYJRow = RGB24ToYJRow_LSX;
4646
    }
4647
  }
4648
#endif
4649
#if defined(HAS_RGB24TOYJROW_LASX)
4650
  if (TestCpuFlag(kCpuHasLASX)) {
4651
    RGB24ToYJRow = RGB24ToYJRow_Any_LASX;
4652
    if (IS_ALIGNED(width, 32)) {
4653
      RGB24ToYJRow = RGB24ToYJRow_LASX;
4654
    }
4655
  }
4656
#endif
4657
#if defined(HAS_RGB24TOYJROW_RVV)
4658
  if (TestCpuFlag(kCpuHasRVV)) {
4659
    RGB24ToYJRow = RGB24ToYJRow_RVV;
4660
  }
4661
#endif
4662
4663
0
  for (y = 0; y < height; ++y) {
4664
0
    RGB24ToYJRow(src_rgb24, dst_yj, width);
4665
0
    src_rgb24 += src_stride_rgb24;
4666
0
    dst_yj += dst_stride_yj;
4667
0
  }
4668
0
  return 0;
4669
0
}
4670
4671
// Convert RAW to J400.
4672
LIBYUV_API
4673
int RAWToJ400(const uint8_t* src_raw,
4674
              int src_stride_raw,
4675
              uint8_t* dst_yj,
4676
              int dst_stride_yj,
4677
              int width,
4678
47
              int height) {
4679
47
  int y;
4680
47
  void (*RAWToYJRow)(const uint8_t* src_raw, uint8_t* dst_yj, int width) =
4681
47
      RAWToYJRow_C;
4682
47
  if (!src_raw || !dst_yj || width <= 0 || height == 0) {
4683
0
    return -1;
4684
0
  }
4685
4686
47
  if (height < 0) {
4687
0
    height = -height;
4688
0
    src_raw = src_raw + (height - 1) * src_stride_raw;
4689
0
    src_stride_raw = -src_stride_raw;
4690
0
  }
4691
  // Coalesce rows.
4692
47
  if (src_stride_raw == width * 3 && dst_stride_yj == width) {
4693
47
    width *= height;
4694
47
    height = 1;
4695
47
    src_stride_raw = dst_stride_yj = 0;
4696
47
  }
4697
4698
47
#if defined(HAS_RAWTOYJROW_SSSE3)
4699
47
  if (TestCpuFlag(kCpuHasSSSE3)) {
4700
47
    RAWToYJRow = RAWToYJRow_Any_SSSE3;
4701
47
    if (IS_ALIGNED(width, 16)) {
4702
5
      RAWToYJRow = RAWToYJRow_SSSE3;
4703
5
    }
4704
47
  }
4705
47
#endif
4706
47
#if defined(HAS_RAWTOYJROW_AVX2)
4707
47
  if (TestCpuFlag(kCpuHasAVX2)) {
4708
47
    RAWToYJRow = RAWToYJRow_Any_AVX2;
4709
47
    if (IS_ALIGNED(width, 32)) {
4710
3
      RAWToYJRow = RAWToYJRow_AVX2;
4711
3
    }
4712
47
  }
4713
47
#endif
4714
#if defined(HAS_RAWTOYJROW_NEON)
4715
  if (TestCpuFlag(kCpuHasNEON)) {
4716
    RAWToYJRow = RAWToYJRow_Any_NEON;
4717
    if (IS_ALIGNED(width, 16)) {
4718
      RAWToYJRow = RAWToYJRow_NEON;
4719
    }
4720
  }
4721
#endif
4722
#if defined(HAS_RAWTOYJROW_MSA)
4723
  if (TestCpuFlag(kCpuHasMSA)) {
4724
    RAWToYJRow = RAWToYJRow_Any_MSA;
4725
    if (IS_ALIGNED(width, 16)) {
4726
      RAWToYJRow = RAWToYJRow_MSA;
4727
    }
4728
  }
4729
#endif
4730
#if defined(HAS_RAWTOYJROW_LSX)
4731
  if (TestCpuFlag(kCpuHasLSX)) {
4732
    RAWToYJRow = RAWToYJRow_Any_LSX;
4733
    if (IS_ALIGNED(width, 16)) {
4734
      RAWToYJRow = RAWToYJRow_LSX;
4735
    }
4736
  }
4737
#endif
4738
#if defined(HAS_RAWTOYJROW_LASX)
4739
  if (TestCpuFlag(kCpuHasLASX)) {
4740
    RAWToYJRow = RAWToYJRow_Any_LASX;
4741
    if (IS_ALIGNED(width, 32)) {
4742
      RAWToYJRow = RAWToYJRow_LASX;
4743
    }
4744
  }
4745
#endif
4746
#if defined(HAS_RAWTOYJROW_RVV)
4747
  if (TestCpuFlag(kCpuHasRVV)) {
4748
    RAWToYJRow = RAWToYJRow_RVV;
4749
  }
4750
#endif
4751
4752
94
  for (y = 0; y < height; ++y) {
4753
47
    RAWToYJRow(src_raw, dst_yj, width);
4754
47
    src_raw += src_stride_raw;
4755
47
    dst_yj += dst_stride_yj;
4756
47
  }
4757
47
  return 0;
4758
47
}
4759
4760
// Convert Android420 to I420.
4761
LIBYUV_API
4762
int Android420ToI420(const uint8_t* src_y,
4763
                     int src_stride_y,
4764
                     const uint8_t* src_u,
4765
                     int src_stride_u,
4766
                     const uint8_t* src_v,
4767
                     int src_stride_v,
4768
                     int src_pixel_stride_uv,
4769
                     uint8_t* dst_y,
4770
                     int dst_stride_y,
4771
                     uint8_t* dst_u,
4772
                     int dst_stride_u,
4773
                     uint8_t* dst_v,
4774
                     int dst_stride_v,
4775
                     int width,
4776
0
                     int height) {
4777
0
  return Android420ToI420Rotate(src_y, src_stride_y, src_u, src_stride_u, src_v,
4778
0
                                src_stride_v, src_pixel_stride_uv, dst_y,
4779
0
                                dst_stride_y, dst_u, dst_stride_u, dst_v,
4780
0
                                dst_stride_v, width, height, kRotate0);
4781
0
}
4782
4783
// depth is source bits measured from lsb; For msb use 16
4784
static int Biplanar16bitTo8bit(const uint16_t* src_y,
4785
                               int src_stride_y,
4786
                               const uint16_t* src_uv,
4787
                               int src_stride_uv,
4788
                               uint8_t* dst_y,
4789
                               int dst_stride_y,
4790
                               uint8_t* dst_uv,
4791
                               int dst_stride_uv,
4792
                               int width,
4793
                               int height,
4794
                               int subsample_x,
4795
                               int subsample_y,
4796
0
                               int depth) {
4797
0
  int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
4798
0
  int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
4799
0
  int scale = 1 << (24 - depth);
4800
0
  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
4801
0
    return -1;
4802
0
  }
4803
  // Negative height means invert the image.
4804
0
  if (height < 0) {
4805
0
    height = -height;
4806
0
    uv_height = -uv_height;
4807
0
    src_y = src_y + (height - 1) * src_stride_y;
4808
0
    src_uv = src_uv + (uv_height - 1) * src_stride_uv;
4809
0
    src_stride_y = -src_stride_y;
4810
0
    src_stride_uv = -src_stride_uv;
4811
0
  }
4812
4813
  // Convert Y plane.
4814
0
  if (dst_y) {
4815
0
    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
4816
0
                      height);
4817
0
  }
4818
  // Convert UV planes.
4819
0
  Convert16To8Plane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, scale,
4820
0
                    uv_width * 2, uv_height);
4821
0
  return 0;
4822
0
}
4823
4824
// Convert 10 bit P010 to 8 bit NV12.
4825
// Depth set to 16 because P010 uses 10 msb and this function keeps the upper 8
4826
// bits of the specified number of bits.
4827
LIBYUV_API
4828
int P010ToNV12(const uint16_t* src_y,
4829
               int src_stride_y,
4830
               const uint16_t* src_uv,
4831
               int src_stride_uv,
4832
               uint8_t* dst_y,
4833
               int dst_stride_y,
4834
               uint8_t* dst_uv,
4835
               int dst_stride_uv,
4836
               int width,
4837
0
               int height) {
4838
0
  return Biplanar16bitTo8bit(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
4839
0
                             dst_stride_y, dst_uv, dst_stride_uv, width, height,
4840
0
                             1, 1, 16);
4841
0
}
4842
4843
static int Planar8bitTo8bit(const uint8_t* src_y,
4844
                            int src_stride_y,
4845
                            const uint8_t* src_u,
4846
                            int src_stride_u,
4847
                            const uint8_t* src_v,
4848
                            int src_stride_v,
4849
                            uint8_t* dst_y,
4850
                            int dst_stride_y,
4851
                            uint8_t* dst_u,
4852
                            int dst_stride_u,
4853
                            uint8_t* dst_v,
4854
                            int dst_stride_v,
4855
                            int width,
4856
                            int height,
4857
                            int subsample_x,
4858
                            int subsample_y,
4859
                            int scale_y,
4860
                            int bias_y,
4861
                            int scale_uv,
4862
0
                            int bias_uv) {
4863
0
  int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
4864
0
  int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
4865
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
4866
0
      height == 0) {
4867
0
    return -1;
4868
0
  }
4869
  // Negative height means invert the image.
4870
0
  if (height < 0) {
4871
0
    height = -height;
4872
0
    uv_height = -uv_height;
4873
0
    src_y = src_y + (height - 1) * src_stride_y;
4874
0
    src_u = src_u + (uv_height - 1) * src_stride_u;
4875
0
    src_v = src_v + (uv_height - 1) * src_stride_v;
4876
0
    src_stride_y = -src_stride_y;
4877
0
    src_stride_u = -src_stride_u;
4878
0
    src_stride_v = -src_stride_v;
4879
0
  }
4880
4881
  // Convert Y plane.
4882
0
  if (dst_y) {
4883
0
    Convert8To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale_y, bias_y,
4884
0
                     width, height);
4885
0
  }
4886
  // Convert UV planes.
4887
0
  Convert8To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, scale_uv, bias_uv,
4888
0
                   uv_width, uv_height);
4889
0
  Convert8To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, scale_uv, bias_uv,
4890
0
                   uv_width, uv_height);
4891
0
  return 0;
4892
0
}
4893
4894
LIBYUV_API
4895
int J420ToI420(const uint8_t* src_y,
4896
               int src_stride_y,
4897
               const uint8_t* src_u,
4898
               int src_stride_u,
4899
               const uint8_t* src_v,
4900
               int src_stride_v,
4901
               uint8_t* dst_y,
4902
               int dst_stride_y,
4903
               uint8_t* dst_u,
4904
               int dst_stride_u,
4905
               uint8_t* dst_v,
4906
               int dst_stride_v,
4907
               int width,
4908
0
               int height) {
4909
0
  return Planar8bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
4910
0
                          src_stride_v, dst_y, dst_stride_y, dst_u,
4911
0
                          dst_stride_u, dst_v, dst_stride_v, width, height, 1,
4912
0
                          1, 220, 16, 225, 16);
4913
0
}
4914
4915
#ifdef __cplusplus
4916
}  // extern "C"
4917
}  // namespace libyuv
4918
#endif