Coverage Report

Created: 2026-01-09 06:51

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