Coverage Report

Created: 2026-10-17 06:28

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 <limits.h>
14
15
#include "libyuv/basic_types.h"
16
#include "libyuv/convert_from_argb.h"
17
#include "libyuv/cpu_id.h"
18
#include "libyuv/planar_functions.h"
19
#include "libyuv/rotate.h"
20
#include "libyuv/row.h"
21
#include "libyuv/scale.h"      // For ScalePlane()
22
#include "libyuv/scale_row.h"  // For FixedDiv
23
#include "libyuv/scale_uv.h"   // For UVScale()
24
25
#ifdef __cplusplus
26
namespace libyuv {
27
28
extern const struct ArgbConstants kArgbI601Constants;
29
extern const struct ArgbConstants kArgbJPEGConstants;
30
extern "C" {
31
#endif
32
33
// Subsample amount uses a shift.
34
//   v is value
35
//   a is amount to add to round up
36
//   s is shift to subsample down
37
0
#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
38
0
static __inline int Abs(int v) {
39
0
  return v >= 0 ? v : -v;
40
0
}
41
42
// Any I4xx To I420 format
43
static int I4xxToI420(const uint8_t* src_y,
44
                      int src_stride_y,
45
                      const uint8_t* src_u,
46
                      int src_stride_u,
47
                      const uint8_t* src_v,
48
                      int src_stride_v,
49
                      uint8_t* dst_y,
50
                      int dst_stride_y,
51
                      uint8_t* dst_u,
52
                      int dst_stride_u,
53
                      uint8_t* dst_v,
54
                      int dst_stride_v,
55
                      int src_y_width,
56
                      int src_y_height,
57
                      int src_uv_width,
58
0
                      int src_uv_height) {
59
0
  int r;
60
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v ||
61
0
      src_y_width <= 0 || src_y_height == 0 || src_y_height == INT_MIN ||
62
0
      src_uv_width <= 0 || src_uv_height == 0) {
63
0
    return -1;
64
0
  }
65
0
  const int dst_y_width = src_y_width;
66
0
  const int dst_y_height = Abs(src_y_height);
67
0
  const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
68
0
  const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
69
0
  if (dst_y) {
70
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, src_y_width,
71
0
              src_y_height);
72
0
  }
73
0
  r = ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
74
0
                 dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
75
0
  if (r != 0) {
76
0
    return r;
77
0
  }
78
0
  r = ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
79
0
                 dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
80
0
  return r;
81
0
}
82
83
// Copy I420 with optional vertical flipping using negative height.
84
LIBYUV_API
85
int I420Copy(const uint8_t* src_y,
86
             int src_stride_y,
87
             const uint8_t* src_u,
88
             int src_stride_u,
89
             const uint8_t* src_v,
90
             int src_stride_v,
91
             uint8_t* dst_y,
92
             int dst_stride_y,
93
             uint8_t* dst_u,
94
             int dst_stride_u,
95
             uint8_t* dst_v,
96
             int dst_stride_v,
97
             int width,
98
0
             int height) {
99
0
  int halfwidth = (width + 1) >> 1;
100
0
  int halfheight = (height + 1) >> 1;
101
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
102
0
      height == 0 || height == INT_MIN) {
103
0
    return -1;
104
0
  }
105
  // Negative height means invert the image.
106
0
  if (height < 0) {
107
0
    height = -height;
108
0
    halfheight = (height + 1) >> 1;
109
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
110
0
    src_u = src_u + (ptrdiff_t)(halfheight - 1) * src_stride_u;
111
0
    src_v = src_v + (ptrdiff_t)(halfheight - 1) * src_stride_v;
112
0
    src_stride_y = -src_stride_y;
113
0
    src_stride_u = -src_stride_u;
114
0
    src_stride_v = -src_stride_v;
115
0
  }
116
117
0
  if (dst_y) {
118
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
119
0
  }
120
  // Copy UV planes.
121
0
  CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
122
0
  CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
123
0
  return 0;
124
0
}
125
126
// Copy I010 with optional flipping.
127
LIBYUV_API
128
int I010Copy(const uint16_t* src_y,
129
             int src_stride_y,
130
             const uint16_t* src_u,
131
             int src_stride_u,
132
             const uint16_t* src_v,
133
             int src_stride_v,
134
             uint16_t* dst_y,
135
             int dst_stride_y,
136
             uint16_t* dst_u,
137
             int dst_stride_u,
138
             uint16_t* dst_v,
139
             int dst_stride_v,
140
             int width,
141
0
             int height) {
142
0
  int halfwidth = (width + 1) >> 1;
143
0
  int halfheight = (height + 1) >> 1;
144
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
145
0
      height == 0 || height == INT_MIN) {
146
0
    return -1;
147
0
  }
148
  // Negative height means invert the image.
149
0
  if (height < 0) {
150
0
    height = -height;
151
0
    halfheight = (height + 1) >> 1;
152
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
153
0
    src_u = src_u + (ptrdiff_t)(halfheight - 1) * src_stride_u;
154
0
    src_v = src_v + (ptrdiff_t)(halfheight - 1) * src_stride_v;
155
0
    src_stride_y = -src_stride_y;
156
0
    src_stride_u = -src_stride_u;
157
0
    src_stride_v = -src_stride_v;
158
0
  }
159
160
0
  if (dst_y) {
161
0
    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
162
0
  }
163
  // Copy UV planes.
164
0
  CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
165
0
  CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
166
0
  return 0;
167
0
}
168
169
static int Planar16bitTo8bit(const uint16_t* src_y,
170
                             int src_stride_y,
171
                             const uint16_t* src_u,
172
                             int src_stride_u,
173
                             const uint16_t* src_v,
174
                             int src_stride_v,
175
                             uint8_t* dst_y,
176
                             int dst_stride_y,
177
                             uint8_t* dst_u,
178
                             int dst_stride_u,
179
                             uint8_t* dst_v,
180
                             int dst_stride_v,
181
                             int width,
182
                             int height,
183
                             int subsample_x,
184
                             int subsample_y,
185
0
                             int depth) {
186
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
187
0
      height == 0 || height == INT_MIN) {
188
0
    return -1;
189
0
  }
190
0
  int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
191
0
  int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
192
0
  int scale = 1 << (24 - depth);
193
  // Negative height means invert the image.
194
0
  if (height < 0) {
195
0
    height = -height;
196
0
    uv_height = -uv_height;
197
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
198
0
    src_u = src_u + (ptrdiff_t)(uv_height - 1) * src_stride_u;
199
0
    src_v = src_v + (ptrdiff_t)(uv_height - 1) * src_stride_v;
200
0
    src_stride_y = -src_stride_y;
201
0
    src_stride_u = -src_stride_u;
202
0
    src_stride_v = -src_stride_v;
203
0
  }
204
205
  // Convert Y plane.
206
0
  if (dst_y) {
207
0
    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
208
0
                      height);
209
0
  }
210
  // Convert UV planes.
211
0
  Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, scale, uv_width,
212
0
                    uv_height);
213
0
  Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, scale, uv_width,
214
0
                    uv_height);
215
0
  return 0;
216
0
}
217
218
static int I41xToI420(const uint16_t* src_y,
219
                      int src_stride_y,
220
                      const uint16_t* src_u,
221
                      int src_stride_u,
222
                      const uint16_t* src_v,
223
                      int src_stride_v,
224
                      uint8_t* dst_y,
225
                      int dst_stride_y,
226
                      uint8_t* dst_u,
227
                      int dst_stride_u,
228
                      uint8_t* dst_v,
229
                      int dst_stride_v,
230
                      int width,
231
                      int height,
232
0
                      int depth) {
233
0
  int y;
234
0
  const int scale = 1 << (24 - depth);
235
0
  const int uv_width = SUBSAMPLE(width, 1, 1);
236
0
  void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale,
237
0
                          int width) = Convert16To8Row_C;
238
0
  void (*HalfWidthRow_16To8)(const uint16_t* src_uv, ptrdiff_t src_uv_stride,
239
0
                             uint8_t* dst_uv, int scale, int width) =
240
0
      (width & 1) ? HalfWidthRow_16To8_Odd_C : HalfWidthRow_16To8_C;
241
242
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
243
0
      height == 0 || height == INT_MIN) {
244
0
    return -1;
245
0
  }
246
  // Negative height means invert the image.
247
0
  if (height < 0) {
248
0
    height = -height;
249
0
    if (src_y) {
250
0
      src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
251
0
      src_stride_y = -src_stride_y;
252
0
    }
253
0
    src_u = src_u + (ptrdiff_t)(height - 1) * src_stride_u;
254
0
    src_v = src_v + (ptrdiff_t)(height - 1) * src_stride_v;
255
0
    src_stride_u = -src_stride_u;
256
0
    src_stride_v = -src_stride_v;
257
0
  }
258
259
#if defined(HAS_CONVERT16TO8ROW_NEON)
260
  if (TestCpuFlag(kCpuHasNEON)) {
261
    Convert16To8Row = Convert16To8Row_Any_NEON;
262
    if (IS_ALIGNED(width, 16)) {
263
      Convert16To8Row = Convert16To8Row_NEON;
264
    }
265
  }
266
#endif
267
#if defined(HAS_CONVERT16TO8ROW_SVE2)
268
  if (TestCpuFlag(kCpuHasSVE2)) {
269
    Convert16To8Row = Convert16To8Row_SVE2;
270
  }
271
#endif
272
#if defined(HAS_CONVERT16TO8ROW_SME)
273
  if (TestCpuFlag(kCpuHasSME)) {
274
    Convert16To8Row = Convert16To8Row_SME;
275
  }
276
#endif
277
0
#if defined(HAS_CONVERT16TO8ROW_SSSE3)
278
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
279
0
    Convert16To8Row = Convert16To8Row_Any_SSSE3;
280
0
    if (IS_ALIGNED(width, 16)) {
281
0
      Convert16To8Row = Convert16To8Row_SSSE3;
282
0
    }
283
0
  }
284
0
#endif
285
0
#if defined(HAS_CONVERT16TO8ROW_AVX2)
286
0
  if (TestCpuFlag(kCpuHasAVX2)) {
287
0
    Convert16To8Row = Convert16To8Row_Any_AVX2;
288
0
    if (IS_ALIGNED(width, 32)) {
289
0
      Convert16To8Row = Convert16To8Row_AVX2;
290
0
    }
291
0
  }
292
0
#endif
293
0
#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
294
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
295
0
    Convert16To8Row = Convert16To8Row_Any_AVX512BW;
296
0
    if (IS_ALIGNED(width, 64)) {
297
0
      Convert16To8Row = Convert16To8Row_AVX512BW;
298
0
    }
299
0
  }
300
0
#endif
301
#if defined(HAS_CONVERT16TO8ROW_RVV)
302
  if (TestCpuFlag(kCpuHasRVV)) {
303
    Convert16To8Row = Convert16To8Row_RVV;
304
  }
305
#endif
306
307
0
  if (IS_ALIGNED(width, 2)) {
308
#if defined(HAS_HALFWIDTHROW_16TO8_NEON)
309
    if (TestCpuFlag(kCpuHasNEON)) {
310
      HalfWidthRow_16To8 = HalfWidthRow_16To8_Any_NEON;
311
      if (IS_ALIGNED(uv_width, 8)) {
312
        HalfWidthRow_16To8 = HalfWidthRow_16To8_NEON;
313
      }
314
    }
315
#endif
316
#if defined(HAS_HALFWIDTHROW_16TO8_SVE2)
317
    if (TestCpuFlag(kCpuHasSVE2)) {
318
      HalfWidthRow_16To8 = HalfWidthRow_16To8_SVE2;
319
    }
320
#endif
321
#if defined(HAS_HALFWIDTHROW_16TO8_SME)
322
    if (TestCpuFlag(kCpuHasSME)) {
323
      HalfWidthRow_16To8 = HalfWidthRow_16To8_SME;
324
    }
325
#endif
326
0
#if defined(HAS_HALFWIDTHROW_16TO8_SSSE3)
327
0
    if (TestCpuFlag(kCpuHasSSSE3)) {
328
0
      HalfWidthRow_16To8 = HalfWidthRow_16To8_Any_SSSE3;
329
0
      if (IS_ALIGNED(uv_width, 8)) {
330
0
        HalfWidthRow_16To8 = HalfWidthRow_16To8_SSSE3;
331
0
      }
332
0
    }
333
0
#endif
334
0
#if defined(HAS_HALFWIDTHROW_16TO8_AVX2)
335
0
    if (TestCpuFlag(kCpuHasAVX2)) {
336
0
      HalfWidthRow_16To8 = HalfWidthRow_16To8_Any_AVX2;
337
0
      if (IS_ALIGNED(uv_width, 16)) {
338
0
        HalfWidthRow_16To8 = HalfWidthRow_16To8_AVX2;
339
0
      }
340
0
    }
341
0
#endif
342
0
#if defined(HAS_HALFWIDTHROW_16TO8_AVX512BW)
343
0
    if (TestCpuFlag(kCpuHasAVX512BW)) {
344
0
      HalfWidthRow_16To8 = HalfWidthRow_16To8_Any_AVX512BW;
345
0
      if (IS_ALIGNED(uv_width, 32)) {
346
0
        HalfWidthRow_16To8 = HalfWidthRow_16To8_AVX512BW;
347
0
      }
348
0
    }
349
0
#endif
350
#if defined(HAS_HALFWIDTHROW_16TO8_RVV)
351
    if (TestCpuFlag(kCpuHasRVV)) {
352
      HalfWidthRow_16To8 = HalfWidthRow_16To8_RVV;
353
    }
354
#endif
355
0
  }
356
357
0
  for (y = 0; y < height - 1; y += 2) {
358
0
    HalfWidthRow_16To8(src_u, src_stride_u, dst_u, scale, uv_width);
359
0
    HalfWidthRow_16To8(src_v, src_stride_v, dst_v, scale, uv_width);
360
0
    if (dst_y) {
361
0
      Convert16To8Row(src_y, dst_y, scale, width);
362
0
      Convert16To8Row(src_y + src_stride_y, dst_y + dst_stride_y, scale, width);
363
0
      src_y += src_stride_y * 2;
364
0
      dst_y += dst_stride_y * 2;
365
0
    }
366
0
    src_u += src_stride_u * 2;
367
0
    src_v += src_stride_v * 2;
368
0
    dst_u += dst_stride_u;
369
0
    dst_v += dst_stride_v;
370
0
  }
371
0
  if (height & 1) {
372
0
    HalfWidthRow_16To8(src_u, 0, dst_u, scale, uv_width);
373
0
    HalfWidthRow_16To8(src_v, 0, dst_v, scale, uv_width);
374
0
    if (dst_y) {
375
0
      Convert16To8Row(src_y, dst_y, scale, width);
376
0
    }
377
0
  }
378
0
  return 0;
379
0
}
380
381
static int I21xToI420(const uint16_t* src_y,
382
                      int src_stride_y,
383
                      const uint16_t* src_u,
384
                      int src_stride_u,
385
                      const uint16_t* src_v,
386
                      int src_stride_v,
387
                      uint8_t* dst_y,
388
                      int dst_stride_y,
389
                      uint8_t* dst_u,
390
                      int dst_stride_u,
391
                      uint8_t* dst_v,
392
                      int dst_stride_v,
393
                      int width,
394
                      int height,
395
0
                      int depth) {
396
0
  int y;
397
0
  const int scale = 1 << (24 - depth);
398
0
  const int uv_width = SUBSAMPLE(width, 1, 1);
399
0
  void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale,
400
0
                          int width) = Convert16To8Row_C;
401
0
  void (*HalfRow_16To8)(const uint16_t* src_uv, ptrdiff_t src_uv_stride,
402
0
                        uint8_t* dst_uv, int scale, int width) =
403
0
      HalfRow_16To8_C;
404
405
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
406
0
      height == 0 || height == INT_MIN) {
407
0
    return -1;
408
0
  }
409
  // Negative height means invert the image.
410
0
  if (height < 0) {
411
0
    height = -height;
412
0
    if (src_y) {
413
0
      src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
414
0
      src_stride_y = -src_stride_y;
415
0
    }
416
0
    src_u = src_u + (ptrdiff_t)(height - 1) * src_stride_u;
417
0
    src_v = src_v + (ptrdiff_t)(height - 1) * src_stride_v;
418
0
    src_stride_u = -src_stride_u;
419
0
    src_stride_v = -src_stride_v;
420
0
  }
421
422
#if defined(HAS_CONVERT16TO8ROW_NEON)
423
  if (TestCpuFlag(kCpuHasNEON)) {
424
    Convert16To8Row = Convert16To8Row_Any_NEON;
425
    if (IS_ALIGNED(width, 16)) {
426
      Convert16To8Row = Convert16To8Row_NEON;
427
    }
428
  }
429
#endif
430
#if defined(HAS_CONVERT16TO8ROW_SVE2)
431
  if (TestCpuFlag(kCpuHasSVE2)) {
432
    Convert16To8Row = Convert16To8Row_SVE2;
433
  }
434
#endif
435
#if defined(HAS_CONVERT16TO8ROW_SME)
436
  if (TestCpuFlag(kCpuHasSME)) {
437
    Convert16To8Row = Convert16To8Row_SME;
438
  }
439
#endif
440
0
#if defined(HAS_CONVERT16TO8ROW_SSSE3)
441
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
442
0
    Convert16To8Row = Convert16To8Row_Any_SSSE3;
443
0
    if (IS_ALIGNED(width, 16)) {
444
0
      Convert16To8Row = Convert16To8Row_SSSE3;
445
0
    }
446
0
  }
447
0
#endif
448
0
#if defined(HAS_CONVERT16TO8ROW_AVX2)
449
0
  if (TestCpuFlag(kCpuHasAVX2)) {
450
0
    Convert16To8Row = Convert16To8Row_Any_AVX2;
451
0
    if (IS_ALIGNED(width, 32)) {
452
0
      Convert16To8Row = Convert16To8Row_AVX2;
453
0
    }
454
0
  }
455
0
#endif
456
0
#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
457
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
458
0
    Convert16To8Row = Convert16To8Row_Any_AVX512BW;
459
0
    if (IS_ALIGNED(width, 64)) {
460
0
      Convert16To8Row = Convert16To8Row_AVX512BW;
461
0
    }
462
0
  }
463
0
#endif
464
#if defined(HAS_CONVERT16TO8ROW_RVV)
465
  if (TestCpuFlag(kCpuHasRVV)) {
466
    Convert16To8Row = Convert16To8Row_RVV;
467
  }
468
#endif
469
470
#if defined(HAS_HALFROW_16TO8_NEON)
471
  if (TestCpuFlag(kCpuHasNEON)) {
472
    HalfRow_16To8 = HalfRow_16To8_Any_NEON;
473
    if (IS_ALIGNED(uv_width, 16)) {
474
      HalfRow_16To8 = HalfRow_16To8_NEON;
475
    }
476
  }
477
#endif
478
#if defined(HAS_HALFROW_16TO8_SVE2)
479
  if (TestCpuFlag(kCpuHasSVE2)) {
480
    HalfRow_16To8 = HalfRow_16To8_SVE2;
481
  }
482
#endif
483
#if defined(HAS_HALFROW_16TO8_SME)
484
  if (TestCpuFlag(kCpuHasSME)) {
485
    HalfRow_16To8 = HalfRow_16To8_SME;
486
  }
487
#endif
488
0
#if defined(HAS_HALFROW_16TO8_SSSE3)
489
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
490
0
    HalfRow_16To8 = HalfRow_16To8_Any_SSSE3;
491
0
    if (IS_ALIGNED(uv_width, 16)) {
492
0
      HalfRow_16To8 = HalfRow_16To8_SSSE3;
493
0
    }
494
0
  }
495
0
#endif
496
0
#if defined(HAS_HALFROW_16TO8_AVX2)
497
0
  if (TestCpuFlag(kCpuHasAVX2)) {
498
0
    HalfRow_16To8 = HalfRow_16To8_Any_AVX2;
499
0
    if (IS_ALIGNED(uv_width, 32)) {
500
0
      HalfRow_16To8 = HalfRow_16To8_AVX2;
501
0
    }
502
0
  }
503
0
#endif
504
0
#if defined(HAS_HALFROW_16TO8_AVX512BW)
505
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
506
0
    HalfRow_16To8 = HalfRow_16To8_Any_AVX512BW;
507
0
    if (IS_ALIGNED(uv_width, 64)) {
508
0
      HalfRow_16To8 = HalfRow_16To8_AVX512BW;
509
0
    }
510
0
  }
511
0
#endif
512
#if defined(HAS_HALFROW_16TO8_RVV)
513
  if (TestCpuFlag(kCpuHasRVV)) {
514
    HalfRow_16To8 = HalfRow_16To8_RVV;
515
  }
516
#endif
517
518
0
  for (y = 0; y < height - 1; y += 2) {
519
0
    HalfRow_16To8(src_u, src_stride_u, dst_u, scale, uv_width);
520
0
    HalfRow_16To8(src_v, src_stride_v, dst_v, scale, uv_width);
521
0
    if (dst_y) {
522
0
      Convert16To8Row(src_y, dst_y, scale, width);
523
0
      Convert16To8Row(src_y + src_stride_y, dst_y + dst_stride_y, scale, width);
524
0
      src_y += src_stride_y * 2;
525
0
      dst_y += dst_stride_y * 2;
526
0
    }
527
0
    src_u += src_stride_u * 2;
528
0
    src_v += src_stride_v * 2;
529
0
    dst_u += dst_stride_u;
530
0
    dst_v += dst_stride_v;
531
0
  }
532
0
  if (height & 1) {
533
0
    HalfRow_16To8(src_u, 0, dst_u, scale, uv_width);
534
0
    HalfRow_16To8(src_v, 0, dst_v, scale, uv_width);
535
0
    if (dst_y) {
536
0
      Convert16To8Row(src_y, dst_y, scale, width);
537
0
    }
538
0
  }
539
0
  return 0;
540
0
}
541
542
// Convert 10 bit YUV to 8 bit.
543
LIBYUV_API
544
int I010ToI420(const uint16_t* src_y,
545
               int src_stride_y,
546
               const uint16_t* src_u,
547
               int src_stride_u,
548
               const uint16_t* src_v,
549
               int src_stride_v,
550
               uint8_t* dst_y,
551
               int dst_stride_y,
552
               uint8_t* dst_u,
553
               int dst_stride_u,
554
               uint8_t* dst_v,
555
               int dst_stride_v,
556
               int width,
557
0
               int height) {
558
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
559
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
560
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 1,
561
0
                           1, 10);
562
0
}
563
564
LIBYUV_API
565
int I210ToI420(const uint16_t* src_y,
566
               int src_stride_y,
567
               const uint16_t* src_u,
568
               int src_stride_u,
569
               const uint16_t* src_v,
570
               int src_stride_v,
571
               uint8_t* dst_y,
572
               int dst_stride_y,
573
               uint8_t* dst_u,
574
               int dst_stride_u,
575
               uint8_t* dst_v,
576
               int dst_stride_v,
577
               int width,
578
0
               int height) {
579
0
  return I21xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
580
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
581
0
                    dst_v, dst_stride_v, width, height, 10);
582
0
}
583
584
LIBYUV_API
585
int I210ToI422(const uint16_t* src_y,
586
               int src_stride_y,
587
               const uint16_t* src_u,
588
               int src_stride_u,
589
               const uint16_t* src_v,
590
               int src_stride_v,
591
               uint8_t* dst_y,
592
               int dst_stride_y,
593
               uint8_t* dst_u,
594
               int dst_stride_u,
595
               uint8_t* dst_v,
596
               int dst_stride_v,
597
               int width,
598
0
               int height) {
599
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
600
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
601
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 1,
602
0
                           0, 10);
603
0
}
604
605
LIBYUV_API
606
int I410ToI420(const uint16_t* src_y,
607
               int src_stride_y,
608
               const uint16_t* src_u,
609
               int src_stride_u,
610
               const uint16_t* src_v,
611
               int src_stride_v,
612
               uint8_t* dst_y,
613
               int dst_stride_y,
614
               uint8_t* dst_u,
615
               int dst_stride_u,
616
               uint8_t* dst_v,
617
               int dst_stride_v,
618
               int width,
619
0
               int height) {
620
0
  return I41xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
621
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
622
0
                    dst_v, dst_stride_v, width, height, 10);
623
0
}
624
625
LIBYUV_API
626
int I410ToI444(const uint16_t* src_y,
627
               int src_stride_y,
628
               const uint16_t* src_u,
629
               int src_stride_u,
630
               const uint16_t* src_v,
631
               int src_stride_v,
632
               uint8_t* dst_y,
633
               int dst_stride_y,
634
               uint8_t* dst_u,
635
               int dst_stride_u,
636
               uint8_t* dst_v,
637
               int dst_stride_v,
638
               int width,
639
0
               int height) {
640
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
641
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
642
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 0,
643
0
                           0, 10);
644
0
}
645
646
LIBYUV_API
647
int I012ToI420(const uint16_t* src_y,
648
               int src_stride_y,
649
               const uint16_t* src_u,
650
               int src_stride_u,
651
               const uint16_t* src_v,
652
               int src_stride_v,
653
               uint8_t* dst_y,
654
               int dst_stride_y,
655
               uint8_t* dst_u,
656
               int dst_stride_u,
657
               uint8_t* dst_v,
658
               int dst_stride_v,
659
               int width,
660
0
               int height) {
661
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
662
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
663
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 1,
664
0
                           1, 12);
665
0
}
666
667
LIBYUV_API
668
int I212ToI422(const uint16_t* src_y,
669
               int src_stride_y,
670
               const uint16_t* src_u,
671
               int src_stride_u,
672
               const uint16_t* src_v,
673
               int src_stride_v,
674
               uint8_t* dst_y,
675
               int dst_stride_y,
676
               uint8_t* dst_u,
677
               int dst_stride_u,
678
               uint8_t* dst_v,
679
               int dst_stride_v,
680
               int width,
681
0
               int height) {
682
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
683
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
684
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 1,
685
0
                           0, 12);
686
0
}
687
688
LIBYUV_API
689
int I212ToI420(const uint16_t* src_y,
690
               int src_stride_y,
691
               const uint16_t* src_u,
692
               int src_stride_u,
693
               const uint16_t* src_v,
694
               int src_stride_v,
695
               uint8_t* dst_y,
696
               int dst_stride_y,
697
               uint8_t* dst_u,
698
               int dst_stride_u,
699
               uint8_t* dst_v,
700
               int dst_stride_v,
701
               int width,
702
0
               int height) {
703
0
  return I21xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
704
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
705
0
                    dst_v, dst_stride_v, width, height, 12);
706
0
}
707
708
LIBYUV_API
709
int I412ToI444(const uint16_t* src_y,
710
               int src_stride_y,
711
               const uint16_t* src_u,
712
               int src_stride_u,
713
               const uint16_t* src_v,
714
               int src_stride_v,
715
               uint8_t* dst_y,
716
               int dst_stride_y,
717
               uint8_t* dst_u,
718
               int dst_stride_u,
719
               uint8_t* dst_v,
720
               int dst_stride_v,
721
               int width,
722
0
               int height) {
723
0
  return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
724
0
                           src_stride_v, dst_y, dst_stride_y, dst_u,
725
0
                           dst_stride_u, dst_v, dst_stride_v, width, height, 0,
726
0
                           0, 12);
727
0
}
728
729
LIBYUV_API
730
int I412ToI420(const uint16_t* src_y,
731
               int src_stride_y,
732
               const uint16_t* src_u,
733
               int src_stride_u,
734
               const uint16_t* src_v,
735
               int src_stride_v,
736
               uint8_t* dst_y,
737
               int dst_stride_y,
738
               uint8_t* dst_u,
739
               int dst_stride_u,
740
               uint8_t* dst_v,
741
               int dst_stride_v,
742
               int width,
743
0
               int height) {
744
0
  return I41xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
745
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
746
0
                    dst_v, dst_stride_v, width, height, 12);
747
0
}
748
749
// Any Ix10 To I010 format
750
static int Ix10ToI010(const uint16_t* src_y,
751
                      int src_stride_y,
752
                      const uint16_t* src_u,
753
                      int src_stride_u,
754
                      const uint16_t* src_v,
755
                      int src_stride_v,
756
                      uint16_t* dst_y,
757
                      int dst_stride_y,
758
                      uint16_t* dst_u,
759
                      int dst_stride_u,
760
                      uint16_t* dst_v,
761
                      int dst_stride_v,
762
                      int width,
763
                      int height,
764
                      int subsample_x,
765
0
                      int subsample_y) {
766
0
  int r;
767
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
768
0
      height == 0 || height == INT_MIN) {
769
0
    return -1;
770
0
  }
771
0
  const int dst_y_width = width;
772
0
  const int dst_y_height = Abs(height);
773
0
  const int src_uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
774
0
  const int src_uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
775
0
  const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
776
0
  const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
777
0
  if (dst_y) {
778
0
    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
779
0
  }
780
0
  r = ScalePlane_12(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
781
0
                    dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
782
0
  if (r != 0) {
783
0
    return r;
784
0
  }
785
0
  r = ScalePlane_12(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
786
0
                    dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
787
0
  return r;
788
0
}
789
790
LIBYUV_API
791
int I410ToI010(const uint16_t* src_y,
792
               int src_stride_y,
793
               const uint16_t* src_u,
794
               int src_stride_u,
795
               const uint16_t* src_v,
796
               int src_stride_v,
797
               uint16_t* dst_y,
798
               int dst_stride_y,
799
               uint16_t* dst_u,
800
               int dst_stride_u,
801
               uint16_t* dst_v,
802
               int dst_stride_v,
803
               int width,
804
0
               int height) {
805
0
  return Ix10ToI010(src_y, src_stride_y, src_u, src_stride_u, src_v,
806
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
807
0
                    dst_v, dst_stride_v, width, height, 0, 0);
808
0
}
809
810
LIBYUV_API
811
int I210ToI010(const uint16_t* src_y,
812
               int src_stride_y,
813
               const uint16_t* src_u,
814
               int src_stride_u,
815
               const uint16_t* src_v,
816
               int src_stride_v,
817
               uint16_t* dst_y,
818
               int dst_stride_y,
819
               uint16_t* dst_u,
820
               int dst_stride_u,
821
               uint16_t* dst_v,
822
               int dst_stride_v,
823
               int width,
824
0
               int height) {
825
0
  return Ix10ToI010(src_y, src_stride_y, src_u, src_stride_u, src_v,
826
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
827
0
                    dst_v, dst_stride_v, width, height, 1, 0);
828
0
}
829
830
// Any I[420]1[02] to P[420]1[02] format
831
static int IxxxToPxxx(const uint16_t* src_y,
832
                      int src_stride_y,
833
                      const uint16_t* src_u,
834
                      int src_stride_u,
835
                      const uint16_t* src_v,
836
                      int src_stride_v,
837
                      uint16_t* dst_y,
838
                      int dst_stride_y,
839
                      uint16_t* dst_uv,
840
                      int dst_stride_uv,
841
                      int width,
842
                      int height,
843
                      int subsample_x,
844
                      int subsample_y,
845
0
                      int depth) {
846
0
  if (width <= 0 || height == 0 || height == INT_MIN) {
847
0
    return -1;
848
0
  }
849
0
  const int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
850
0
  const int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
851
852
0
  ConvertToMSBPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
853
0
                       depth);
854
0
  MergeUVPlane_16(src_u, src_stride_u, src_v, src_stride_v, dst_uv,
855
0
                  dst_stride_uv, uv_width, uv_height, depth);
856
0
  return 0;
857
0
}
858
859
LIBYUV_API
860
int I010ToP010(const uint16_t* src_y,
861
               int src_stride_y,
862
               const uint16_t* src_u,
863
               int src_stride_u,
864
               const uint16_t* src_v,
865
               int src_stride_v,
866
               uint16_t* dst_y,
867
               int dst_stride_y,
868
               uint16_t* dst_uv,
869
               int dst_stride_uv,
870
               int width,
871
0
               int height) {
872
0
  return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
873
0
                    src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
874
0
                    width, height, 1, 1, 10);
875
0
}
876
877
LIBYUV_API
878
int I010ToNV12(const uint16_t* src_y,
879
               int src_stride_y,
880
               const uint16_t* src_u,
881
               int src_stride_u,
882
               const uint16_t* src_v,
883
               int src_stride_v,
884
               uint8_t* dst_y,
885
               int dst_stride_y,
886
               uint8_t* dst_uv,
887
               int dst_stride_uv,
888
               int width,
889
0
               int height) {
890
0
  int y;
891
0
  int halfwidth = (width + 1) >> 1;
892
0
  int halfheight = (height + 1) >> 1;
893
0
  const int scale = 16385;  // 16384 for 10 bits
894
0
  void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale,
895
0
                          int width) = Convert16To8Row_C;
896
0
  void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
897
0
                     uint8_t* dst_uv, int width) = MergeUVRow_C;
898
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_uv || width <= 0 ||
899
0
      height == 0 || height == INT_MIN) {
900
0
    return -1;
901
0
  }
902
  // Negative height means invert the image.
903
0
  if (height < 0) {
904
0
    height = -height;
905
0
    halfheight = (height + 1) >> 1;
906
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
907
0
    src_u = src_u + (ptrdiff_t)(halfheight - 1) * src_stride_u;
908
0
    src_v = src_v + (ptrdiff_t)(halfheight - 1) * src_stride_v;
909
0
    src_stride_y = -src_stride_y;
910
0
    src_stride_u = -src_stride_u;
911
0
    src_stride_v = -src_stride_v;
912
0
  }
913
#if defined(HAS_CONVERT16TO8ROW_NEON)
914
  if (TestCpuFlag(kCpuHasNEON)) {
915
    Convert16To8Row = Convert16To8Row_Any_NEON;
916
    if (IS_ALIGNED(halfwidth, 16)) {
917
      Convert16To8Row = Convert16To8Row_NEON;
918
    }
919
  }
920
#endif
921
#if defined(HAS_CONVERT16TO8ROW_SME)
922
  if (TestCpuFlag(kCpuHasSME)) {
923
    Convert16To8Row = Convert16To8Row_SME;
924
  }
925
#endif
926
0
#if defined(HAS_CONVERT16TO8ROW_SSSE3)
927
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
928
0
    Convert16To8Row = Convert16To8Row_Any_SSSE3;
929
0
    if (IS_ALIGNED(halfwidth, 16)) {
930
0
      Convert16To8Row = Convert16To8Row_SSSE3;
931
0
    }
932
0
  }
933
0
#endif
934
0
#if defined(HAS_CONVERT16TO8ROW_AVX2)
935
0
  if (TestCpuFlag(kCpuHasAVX2)) {
936
0
    Convert16To8Row = Convert16To8Row_Any_AVX2;
937
0
    if (IS_ALIGNED(halfwidth, 32)) {
938
0
      Convert16To8Row = Convert16To8Row_AVX2;
939
0
    }
940
0
  }
941
0
#endif
942
0
#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
943
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
944
0
    Convert16To8Row = Convert16To8Row_Any_AVX512BW;
945
0
    if (IS_ALIGNED(halfwidth, 64)) {
946
0
      Convert16To8Row = Convert16To8Row_AVX512BW;
947
0
    }
948
0
  }
949
0
#endif
950
951
0
#if defined(HAS_MERGEUVROW_SSE2)
952
0
  if (TestCpuFlag(kCpuHasSSE2)) {
953
0
    MergeUVRow = MergeUVRow_Any_SSE2;
954
0
    if (IS_ALIGNED(halfwidth, 16)) {
955
0
      MergeUVRow = MergeUVRow_SSE2;
956
0
    }
957
0
  }
958
0
#endif
959
0
#if defined(HAS_MERGEUVROW_AVX2)
960
0
  if (TestCpuFlag(kCpuHasAVX2)) {
961
0
    MergeUVRow = MergeUVRow_Any_AVX2;
962
0
    if (IS_ALIGNED(halfwidth, 32)) {
963
0
      MergeUVRow = MergeUVRow_AVX2;
964
0
    }
965
0
  }
966
0
#endif
967
0
#if defined(HAS_MERGEUVROW_AVX512BW)
968
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
969
0
    MergeUVRow = MergeUVRow_Any_AVX512BW;
970
0
    if (IS_ALIGNED(halfwidth, 32)) {
971
0
      MergeUVRow = MergeUVRow_AVX512BW;
972
0
    }
973
0
  }
974
0
#endif
975
#if defined(HAS_MERGEUVROW_NEON)
976
  if (TestCpuFlag(kCpuHasNEON)) {
977
    MergeUVRow = MergeUVRow_Any_NEON;
978
    if (IS_ALIGNED(halfwidth, 16)) {
979
      MergeUVRow = MergeUVRow_NEON;
980
    }
981
  }
982
#endif
983
#if defined(HAS_MERGEUVROW_SVE2)
984
  if (TestCpuFlag(kCpuHasSVE2)) {
985
    MergeUVRow = MergeUVRow_SVE2;
986
  }
987
#endif
988
#if defined(HAS_MERGEUVROW_SME)
989
  if (TestCpuFlag(kCpuHasSME)) {
990
    MergeUVRow = MergeUVRow_SME;
991
  }
992
#endif
993
#if defined(HAS_MERGEUVROW_LSX)
994
  if (TestCpuFlag(kCpuHasLSX)) {
995
    MergeUVRow = MergeUVRow_Any_LSX;
996
    if (IS_ALIGNED(halfwidth, 16)) {
997
      MergeUVRow = MergeUVRow_LSX;
998
    }
999
  }
1000
#endif
1001
#if defined(HAS_MERGEUVROW_RVV)
1002
  if (TestCpuFlag(kCpuHasRVV)) {
1003
    MergeUVRow = MergeUVRow_RVV;
1004
  }
1005
#endif
1006
1007
  // Convert Y plane.
1008
0
  if (dst_y) {
1009
0
    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
1010
0
                      height);
1011
0
  }
1012
1013
0
  {
1014
    // Allocate a row of uv.
1015
0
    align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2);
1016
0
    uint8_t* row_v = row_u + ((halfwidth + 31) & ~31);
1017
0
    if (!row_u)
1018
0
      return 1;
1019
1020
0
    for (y = 0; y < halfheight; ++y) {
1021
0
      Convert16To8Row(src_u, row_u, scale, halfwidth);
1022
0
      Convert16To8Row(src_v, row_v, scale, halfwidth);
1023
0
      MergeUVRow(row_u, row_v, dst_uv, halfwidth);
1024
0
      src_u += src_stride_u;
1025
0
      src_v += src_stride_v;
1026
0
      dst_uv += dst_stride_uv;
1027
0
    }
1028
0
    free_aligned_buffer_64(row_u);
1029
0
  }
1030
0
  return 0;
1031
0
}
1032
1033
LIBYUV_API
1034
int I210ToP210(const uint16_t* src_y,
1035
               int src_stride_y,
1036
               const uint16_t* src_u,
1037
               int src_stride_u,
1038
               const uint16_t* src_v,
1039
               int src_stride_v,
1040
               uint16_t* dst_y,
1041
               int dst_stride_y,
1042
               uint16_t* dst_uv,
1043
               int dst_stride_uv,
1044
               int width,
1045
0
               int height) {
1046
0
  return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
1047
0
                    src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
1048
0
                    width, height, 1, 0, 10);
1049
0
}
1050
1051
LIBYUV_API
1052
int I012ToP012(const uint16_t* src_y,
1053
               int src_stride_y,
1054
               const uint16_t* src_u,
1055
               int src_stride_u,
1056
               const uint16_t* src_v,
1057
               int src_stride_v,
1058
               uint16_t* dst_y,
1059
               int dst_stride_y,
1060
               uint16_t* dst_uv,
1061
               int dst_stride_uv,
1062
               int width,
1063
0
               int height) {
1064
0
  return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
1065
0
                    src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
1066
0
                    width, height, 1, 1, 12);
1067
0
}
1068
1069
LIBYUV_API
1070
int I212ToP212(const uint16_t* src_y,
1071
               int src_stride_y,
1072
               const uint16_t* src_u,
1073
               int src_stride_u,
1074
               const uint16_t* src_v,
1075
               int src_stride_v,
1076
               uint16_t* dst_y,
1077
               int dst_stride_y,
1078
               uint16_t* dst_uv,
1079
               int dst_stride_uv,
1080
               int width,
1081
0
               int height) {
1082
0
  return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
1083
0
                    src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
1084
0
                    width, height, 1, 0, 12);
1085
0
}
1086
1087
// 422 chroma is 1/2 width, 1x height
1088
// 420 chroma is 1/2 width, 1/2 height
1089
LIBYUV_API
1090
int I422ToI420(const uint8_t* src_y,
1091
               int src_stride_y,
1092
               const uint8_t* src_u,
1093
               int src_stride_u,
1094
               const uint8_t* src_v,
1095
               int src_stride_v,
1096
               uint8_t* dst_y,
1097
               int dst_stride_y,
1098
               uint8_t* dst_u,
1099
               int dst_stride_u,
1100
               uint8_t* dst_v,
1101
               int dst_stride_v,
1102
               int width,
1103
0
               int height) {
1104
0
  const int src_uv_width = SUBSAMPLE(width, 1, 1);
1105
0
  return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
1106
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
1107
0
                    dst_v, dst_stride_v, width, height, src_uv_width, height);
1108
0
}
1109
1110
LIBYUV_API
1111
int I422ToI210(const uint8_t* src_y,
1112
               int src_stride_y,
1113
               const uint8_t* src_u,
1114
               int src_stride_u,
1115
               const uint8_t* src_v,
1116
               int src_stride_v,
1117
               uint16_t* dst_y,
1118
               int dst_stride_y,
1119
               uint16_t* dst_u,
1120
               int dst_stride_u,
1121
               uint16_t* dst_v,
1122
               int dst_stride_v,
1123
               int width,
1124
0
               int height) {
1125
0
  int halfwidth = (width + 1) >> 1;
1126
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
1127
0
      height == 0 || height == INT_MIN) {
1128
0
    return -1;
1129
0
  }
1130
  // Negative height means invert the image.
1131
0
  if (height < 0) {
1132
0
    height = -height;
1133
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1134
0
    src_u = src_u + (ptrdiff_t)(height - 1) * src_stride_u;
1135
0
    src_v = src_v + (ptrdiff_t)(height - 1) * src_stride_v;
1136
0
    src_stride_y = -src_stride_y;
1137
0
    src_stride_u = -src_stride_u;
1138
0
    src_stride_v = -src_stride_v;
1139
0
  }
1140
1141
  // Convert Y plane.
1142
0
  Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width,
1143
0
                    height);
1144
  // Convert UV planes.
1145
0
  Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth,
1146
0
                    height);
1147
0
  Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth,
1148
0
                    height);
1149
0
  return 0;
1150
0
}
1151
1152
// TODO(fbarchard): Implement row conversion.
1153
LIBYUV_API
1154
int I422ToNV21(const uint8_t* src_y,
1155
               int src_stride_y,
1156
               const uint8_t* src_u,
1157
               int src_stride_u,
1158
               const uint8_t* src_v,
1159
               int src_stride_v,
1160
               uint8_t* dst_y,
1161
               int dst_stride_y,
1162
               uint8_t* dst_vu,
1163
               int dst_stride_vu,
1164
               int width,
1165
0
               int height) {
1166
0
  int r;
1167
0
  if (width <= 0 || height == 0 || height == INT_MIN) {
1168
0
    return -1;
1169
0
  }
1170
0
  int halfwidth = (width + 1) >> 1;
1171
0
  int halfheight = (height + 1) >> 1;
1172
  // Negative height means invert the image.
1173
0
  if (height < 0) {
1174
0
    height = -height;
1175
0
    halfheight = (height + 1) >> 1;
1176
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1177
0
    src_u = src_u + (ptrdiff_t)(height - 1) * src_stride_u;
1178
0
    src_v = src_v + (ptrdiff_t)(height - 1) * src_stride_v;
1179
0
    src_stride_y = -src_stride_y;
1180
0
    src_stride_u = -src_stride_u;
1181
0
    src_stride_v = -src_stride_v;
1182
0
  }
1183
1184
  // Allocate u and v buffers
1185
0
  const uint64_t plane_size = (uint64_t)halfwidth * halfheight;
1186
0
  if (plane_size > SIZE_MAX / 2)
1187
0
    return 1;
1188
0
  align_buffer_64(plane_u, (size_t)plane_size * 2);
1189
0
  if (!plane_u)
1190
0
    return 1;
1191
0
  uint8_t* plane_v = plane_u + (size_t)plane_size;
1192
1193
0
  r = I422ToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
1194
0
                 dst_y, dst_stride_y, plane_u, halfwidth, plane_v, halfwidth,
1195
0
                 width, height);
1196
0
  if (r != 0) {
1197
0
    return r;
1198
0
  }
1199
0
  MergeUVPlane(plane_v, halfwidth, plane_u, halfwidth, dst_vu, dst_stride_vu,
1200
0
               halfwidth, halfheight);
1201
0
  free_aligned_buffer_64(plane_u);
1202
0
  return 0;
1203
0
}
1204
1205
LIBYUV_API
1206
int MM21ToNV12(const uint8_t* src_y,
1207
               int src_stride_y,
1208
               const uint8_t* src_uv,
1209
               int src_stride_uv,
1210
               uint8_t* dst_y,
1211
               int dst_stride_y,
1212
               uint8_t* dst_uv,
1213
               int dst_stride_uv,
1214
               int width,
1215
0
               int height) {
1216
0
  if (!src_uv || !dst_uv || width <= 0) {
1217
0
    return -1;
1218
0
  }
1219
1220
0
  int sign = height < 0 ? -1 : 1;
1221
1222
0
  if (dst_y) {
1223
0
    DetilePlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height, 32);
1224
0
  }
1225
0
  DetilePlane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, (width + 1) & ~1,
1226
0
              (height + sign) / 2, 16);
1227
1228
0
  return 0;
1229
0
}
1230
1231
LIBYUV_API
1232
int MM21ToI420(const uint8_t* src_y,
1233
               int src_stride_y,
1234
               const uint8_t* src_uv,
1235
               int src_stride_uv,
1236
               uint8_t* dst_y,
1237
               int dst_stride_y,
1238
               uint8_t* dst_u,
1239
               int dst_stride_u,
1240
               uint8_t* dst_v,
1241
               int dst_stride_v,
1242
               int width,
1243
0
               int height) {
1244
0
  int sign = height < 0 ? -1 : 1;
1245
1246
0
  if (!src_uv || !dst_u || !dst_v || width <= 0) {
1247
0
    return -1;
1248
0
  }
1249
1250
0
  if (dst_y) {
1251
0
    DetilePlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height, 32);
1252
0
  }
1253
0
  DetileSplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
1254
0
                     dst_stride_v, (width + 1) & ~1, (height + sign) / 2, 16);
1255
1256
0
  return 0;
1257
0
}
1258
1259
LIBYUV_API
1260
int MM21ToYUY2(const uint8_t* src_y,
1261
               int src_stride_y,
1262
               const uint8_t* src_uv,
1263
               int src_stride_uv,
1264
               uint8_t* dst_yuy2,
1265
               int dst_stride_yuy2,
1266
               int width,
1267
0
               int height) {
1268
0
  if (!src_y || !src_uv || !dst_yuy2 || width <= 0) {
1269
0
    return -1;
1270
0
  }
1271
1272
0
  DetileToYUY2(src_y, src_stride_y, src_uv, src_stride_uv, dst_yuy2,
1273
0
               dst_stride_yuy2, width, height, 32);
1274
1275
0
  return 0;
1276
0
}
1277
1278
// Convert MT2T into P010. See tinyurl.com/mtk-10bit-video-format for format
1279
// documentation.
1280
// TODO(greenjustin): Add an MT2T to I420 conversion.
1281
LIBYUV_API
1282
int MT2TToP010(const uint8_t* src_y,
1283
               int src_stride_y,
1284
               const uint8_t* src_uv,
1285
               int src_stride_uv,
1286
               uint16_t* dst_y,
1287
               int dst_stride_y,
1288
               uint16_t* dst_uv,
1289
               int dst_stride_uv,
1290
               int width,
1291
0
               int height) {
1292
0
  if (width <= 0 || height == 0 || height == INT_MIN || !src_uv || !dst_uv) {
1293
0
    return -1;
1294
0
  }
1295
1296
0
  {
1297
0
    int uv_width = (width + 1) & ~1;
1298
0
    int uv_height = (height + 1) / 2;
1299
0
    int y = 0;
1300
0
    const int tile_width = 16;
1301
0
    const int y_tile_height = 32;
1302
0
    const int uv_tile_height = 16;
1303
0
    int padded_width = (width + tile_width - 1) & ~(tile_width - 1);
1304
0
    int y_tile_row_size = padded_width * y_tile_height * 10 / 8;
1305
0
    int uv_tile_row_size = padded_width * uv_tile_height * 10 / 8;
1306
0
    size_t row_buf_size = padded_width * y_tile_height * sizeof(uint16_t);
1307
0
    void (*UnpackMT2T)(const uint8_t* src, uint16_t* dst, size_t size) =
1308
0
        UnpackMT2T_C;
1309
0
    align_buffer_64(row_buf, row_buf_size);
1310
0
    if (!row_buf)
1311
0
      return 1;
1312
1313
#if defined(HAS_UNPACKMT2T_NEON)
1314
    if (TestCpuFlag(kCpuHasNEON)) {
1315
      UnpackMT2T = UnpackMT2T_NEON;
1316
    }
1317
#endif
1318
    // Negative height means invert the image.
1319
0
    if (height < 0) {
1320
0
      height = -height;
1321
0
      uv_height = (height + 1) / 2;
1322
0
      if (dst_y) {
1323
0
        dst_y = dst_y + (ptrdiff_t)(height - 1) * dst_stride_y;
1324
0
        dst_stride_y = -dst_stride_y;
1325
0
      }
1326
0
      dst_uv = dst_uv + (ptrdiff_t)(uv_height - 1) * dst_stride_uv;
1327
0
      dst_stride_uv = -dst_stride_uv;
1328
0
    }
1329
1330
    // Unpack and detile Y in rows of tiles
1331
0
    if (src_y && dst_y) {
1332
0
      for (y = 0; y < (height & ~(y_tile_height - 1)); y += y_tile_height) {
1333
0
        UnpackMT2T(src_y, (uint16_t*)row_buf, y_tile_row_size);
1334
0
        DetilePlane_16((uint16_t*)row_buf, padded_width, dst_y, dst_stride_y,
1335
0
                       width, y_tile_height, y_tile_height);
1336
0
        src_y += src_stride_y * y_tile_height;
1337
0
        dst_y += dst_stride_y * y_tile_height;
1338
0
      }
1339
0
      if (height & (y_tile_height - 1)) {
1340
0
        UnpackMT2T(src_y, (uint16_t*)row_buf, y_tile_row_size);
1341
0
        DetilePlane_16((uint16_t*)row_buf, padded_width, dst_y, dst_stride_y,
1342
0
                       width, height & (y_tile_height - 1), y_tile_height);
1343
0
      }
1344
0
    }
1345
1346
    // Unpack and detile UV plane
1347
0
    for (y = 0; y < (uv_height & ~(uv_tile_height - 1)); y += uv_tile_height) {
1348
0
      UnpackMT2T(src_uv, (uint16_t*)row_buf, uv_tile_row_size);
1349
0
      DetilePlane_16((uint16_t*)row_buf, padded_width, dst_uv, dst_stride_uv,
1350
0
                     uv_width, uv_tile_height, uv_tile_height);
1351
0
      src_uv += src_stride_uv * uv_tile_height;
1352
0
      dst_uv += dst_stride_uv * uv_tile_height;
1353
0
    }
1354
0
    if (uv_height & (uv_tile_height - 1)) {
1355
0
      UnpackMT2T(src_uv, (uint16_t*)row_buf, uv_tile_row_size);
1356
0
      DetilePlane_16((uint16_t*)row_buf, padded_width, dst_uv, dst_stride_uv,
1357
0
                     uv_width, uv_height & (uv_tile_height - 1),
1358
0
                     uv_tile_height);
1359
0
    }
1360
0
    free_aligned_buffer_64(row_buf);
1361
0
  }
1362
0
  return 0;
1363
0
}
1364
1365
#ifdef I422TONV21_ROW_VERSION
1366
// Unittest fails for this version.
1367
// 422 chroma is 1/2 width, 1x height
1368
// 420 chroma is 1/2 width, 1/2 height
1369
// Swap src_u and src_v to implement I422ToNV12
1370
LIBYUV_API
1371
int I422ToNV21(const uint8_t* src_y,
1372
               int src_stride_y,
1373
               const uint8_t* src_u,
1374
               int src_stride_u,
1375
               const uint8_t* src_v,
1376
               int src_stride_v,
1377
               uint8_t* dst_y,
1378
               int dst_stride_y,
1379
               uint8_t* dst_vu,
1380
               int dst_stride_vu,
1381
               int width,
1382
               int height) {
1383
  int y;
1384
  void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
1385
                     uint8_t* dst_uv, int width) = MergeUVRow_C;
1386
  void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr,
1387
                         ptrdiff_t src_stride, int dst_width,
1388
                         int source_y_fraction) = InterpolateRow_C;
1389
  int halfwidth = (width + 1) >> 1;
1390
  int halfheight = (height + 1) >> 1;
1391
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_vu || width <= 0 ||
1392
      height == 0 || height == INT_MIN) {
1393
    return -1;
1394
  }
1395
  // Negative height means invert the image.
1396
  if (height < 0) {
1397
    height = -height;
1398
    halfheight = (height + 1) >> 1;
1399
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1400
    src_u = src_u + (ptrdiff_t)(halfheight - 1) * src_stride_u;
1401
    src_v = src_v + (ptrdiff_t)(halfheight - 1) * src_stride_v;
1402
    src_stride_y = -src_stride_y;
1403
    src_stride_u = -src_stride_u;
1404
    src_stride_v = -src_stride_v;
1405
  }
1406
#if defined(HAS_MERGEUVROW_SSE2)
1407
  if (TestCpuFlag(kCpuHasSSE2)) {
1408
    MergeUVRow = MergeUVRow_Any_SSE2;
1409
    if (IS_ALIGNED(halfwidth, 16)) {
1410
      MergeUVRow = MergeUVRow_SSE2;
1411
    }
1412
  }
1413
#endif
1414
#if defined(HAS_MERGEUVROW_AVX2)
1415
  if (TestCpuFlag(kCpuHasAVX2)) {
1416
    MergeUVRow = MergeUVRow_Any_AVX2;
1417
    if (IS_ALIGNED(halfwidth, 32)) {
1418
      MergeUVRow = MergeUVRow_AVX2;
1419
    }
1420
  }
1421
#endif
1422
#if defined(HAS_MERGEUVROW_AVX512BW)
1423
  if (TestCpuFlag(kCpuHasAVX512BW)) {
1424
    MergeUVRow = MergeUVRow_Any_AVX512BW;
1425
    if (IS_ALIGNED(halfwidth, 32)) {
1426
      MergeUVRow = MergeUVRow_AVX512BW;
1427
    }
1428
  }
1429
#endif
1430
#if defined(HAS_MERGEUVROW_NEON)
1431
  if (TestCpuFlag(kCpuHasNEON)) {
1432
    MergeUVRow = MergeUVRow_Any_NEON;
1433
    if (IS_ALIGNED(halfwidth, 16)) {
1434
      MergeUVRow = MergeUVRow_NEON;
1435
    }
1436
  }
1437
#endif
1438
#if defined(HAS_MERGEUVROW_SVE2)
1439
  if (TestCpuFlag(kCpuHasSVE2)) {
1440
    MergeUVRow = MergeUVRow_SVE2;
1441
  }
1442
#endif
1443
#if defined(HAS_MERGEUVROW_SME)
1444
  if (TestCpuFlag(kCpuHasSME)) {
1445
    MergeUVRow = MergeUVRow_SME;
1446
  }
1447
#endif
1448
#if defined(HAS_MERGEUVROW_LSX)
1449
  if (TestCpuFlag(kCpuHasLSX)) {
1450
    MergeUVRow = MergeUVRow_Any_LSX;
1451
    if (IS_ALIGNED(halfwidth, 16)) {
1452
      MergeUVRow = MergeUVRow_LSX;
1453
    }
1454
  }
1455
#endif
1456
#if defined(HAS_MERGEUVROW_RVV)
1457
  if (TestCpuFlag(kCpuHasRVV)) {
1458
    MergeUVRow = MergeUVRow_RVV;
1459
  }
1460
#endif
1461
#if defined(HAS_INTERPOLATEROW_AVX2)
1462
  if (TestCpuFlag(kCpuHasAVX2)) {
1463
    InterpolateRow = InterpolateRow_Any_AVX2;
1464
    if (IS_ALIGNED(width, 32)) {
1465
      InterpolateRow = InterpolateRow_AVX2;
1466
    }
1467
  }
1468
#endif
1469
#if defined(HAS_INTERPOLATEROW_NEON)
1470
  if (TestCpuFlag(kCpuHasNEON)) {
1471
    InterpolateRow = InterpolateRow_Any_NEON;
1472
    if (IS_ALIGNED(width, 16)) {
1473
      InterpolateRow = InterpolateRow_NEON;
1474
    }
1475
  }
1476
#endif
1477
#if defined(HAS_INTERPOLATEROW_SVE2)
1478
  if (TestCpuFlag(kCpuHasSVE2)) {
1479
    InterpolateRow = InterpolateRow_SVE2;
1480
  }
1481
#endif
1482
#if defined(HAS_INTERPOLATEROW_SME)
1483
  if (TestCpuFlag(kCpuHasSME)) {
1484
    InterpolateRow = InterpolateRow_SME;
1485
  }
1486
#endif
1487
#if defined(HAS_INTERPOLATEROW_LSX)
1488
  if (TestCpuFlag(kCpuHasLSX)) {
1489
    InterpolateRow = InterpolateRow_Any_LSX;
1490
    if (IS_ALIGNED(width, 32)) {
1491
      InterpolateRow = InterpolateRow_LSX;
1492
    }
1493
  }
1494
#endif
1495
#if defined(HAS_INTERPOLATEROW_RVV)
1496
  if (TestCpuFlag(kCpuHasRVV)) {
1497
    InterpolateRow = InterpolateRow_RVV;
1498
  }
1499
#endif
1500
1501
  if (dst_y) {
1502
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, halfwidth, height);
1503
  }
1504
  {
1505
    // Allocate 2 rows of vu.
1506
    int awidth = halfwidth * 2;
1507
    align_buffer_64(row_vu_0, awidth * 2);
1508
    uint8_t* row_vu_1 = row_vu_0 + awidth;
1509
    if (!row_vu_0)
1510
      return 1;
1511
1512
    for (y = 0; y < height - 1; y += 2) {
1513
      MergeUVRow(src_v, src_u, row_vu_0, halfwidth);
1514
      MergeUVRow(src_v + src_stride_v, src_u + src_stride_u, row_vu_1,
1515
                 halfwidth);
1516
      InterpolateRow(dst_vu, row_vu_0, awidth, awidth, 128);
1517
      src_u += src_stride_u * 2;
1518
      src_v += src_stride_v * 2;
1519
      dst_vu += dst_stride_vu;
1520
    }
1521
    if (height & 1) {
1522
      MergeUVRow(src_v, src_u, dst_vu, halfwidth);
1523
    }
1524
    free_aligned_buffer_64(row_vu_0);
1525
  }
1526
  return 0;
1527
}
1528
#endif  // I422TONV21_ROW_VERSION
1529
1530
// 444 chroma is 1x width, 1x height
1531
// 420 chroma is 1/2 width, 1/2 height
1532
LIBYUV_API
1533
int I444ToI420(const uint8_t* src_y,
1534
               int src_stride_y,
1535
               const uint8_t* src_u,
1536
               int src_stride_u,
1537
               const uint8_t* src_v,
1538
               int src_stride_v,
1539
               uint8_t* dst_y,
1540
               int dst_stride_y,
1541
               uint8_t* dst_u,
1542
               int dst_stride_u,
1543
               uint8_t* dst_v,
1544
               int dst_stride_v,
1545
               int width,
1546
0
               int height) {
1547
0
  return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
1548
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
1549
0
                    dst_v, dst_stride_v, width, height, width, height);
1550
0
}
1551
1552
LIBYUV_API
1553
int I444ToNV12(const uint8_t* src_y,
1554
               int src_stride_y,
1555
               const uint8_t* src_u,
1556
               int src_stride_u,
1557
               const uint8_t* src_v,
1558
               int src_stride_v,
1559
               uint8_t* dst_y,
1560
               int dst_stride_y,
1561
               uint8_t* dst_uv,
1562
               int dst_stride_uv,
1563
               int width,
1564
0
               int height) {
1565
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_uv || width <= 0 ||
1566
0
      height == 0 || height == INT_MIN) {
1567
0
    return -1;
1568
0
  }
1569
  // Negative height means invert the image.
1570
0
  if (height < 0) {
1571
0
    height = -height;
1572
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1573
0
    src_u = src_u + (ptrdiff_t)(height - 1) * src_stride_u;
1574
0
    src_v = src_v + (ptrdiff_t)(height - 1) * src_stride_v;
1575
0
    src_stride_y = -src_stride_y;
1576
0
    src_stride_u = -src_stride_u;
1577
0
    src_stride_v = -src_stride_v;
1578
0
  }
1579
0
  if (dst_y) {
1580
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1581
0
  }
1582
0
  HalfMergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv,
1583
0
                   dst_stride_uv, width, height);
1584
0
  return 0;
1585
0
}
1586
1587
LIBYUV_API
1588
int I444ToNV21(const uint8_t* src_y,
1589
               int src_stride_y,
1590
               const uint8_t* src_u,
1591
               int src_stride_u,
1592
               const uint8_t* src_v,
1593
               int src_stride_v,
1594
               uint8_t* dst_y,
1595
               int dst_stride_y,
1596
               uint8_t* dst_vu,
1597
               int dst_stride_vu,
1598
               int width,
1599
0
               int height) {
1600
0
  return I444ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
1601
0
                    src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
1602
0
                    width, height);
1603
0
}
1604
1605
// I400 is greyscale typically used in MJPG
1606
LIBYUV_API
1607
int I400ToI420(const uint8_t* src_y,
1608
               int src_stride_y,
1609
               uint8_t* dst_y,
1610
               int dst_stride_y,
1611
               uint8_t* dst_u,
1612
               int dst_stride_u,
1613
               uint8_t* dst_v,
1614
               int dst_stride_v,
1615
               int width,
1616
0
               int height) {
1617
0
  int halfwidth = (width + 1) >> 1;
1618
0
  int halfheight = (height + 1) >> 1;
1619
0
  if ((!src_y && dst_y) || !dst_u || !dst_v || width <= 0 || height == 0 ||
1620
0
      height == INT_MIN) {
1621
0
    return -1;
1622
0
  }
1623
  // Negative height means invert the image.
1624
0
  if (height < 0) {
1625
0
    height = -height;
1626
0
    halfheight = (height + 1) >> 1;
1627
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1628
0
    src_stride_y = -src_stride_y;
1629
0
  }
1630
0
  if (dst_y) {
1631
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1632
0
  }
1633
0
  SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
1634
0
  SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
1635
0
  return 0;
1636
0
}
1637
1638
// I400 is greyscale typically used in MJPG
1639
LIBYUV_API
1640
int I400ToNV21(const uint8_t* src_y,
1641
               int src_stride_y,
1642
               uint8_t* dst_y,
1643
               int dst_stride_y,
1644
               uint8_t* dst_vu,
1645
               int dst_stride_vu,
1646
               int width,
1647
0
               int height) {
1648
0
  int halfwidth = (width + 1) >> 1;
1649
0
  int halfheight = (height + 1) >> 1;
1650
0
  if ((!src_y && dst_y) || !dst_vu || width <= 0 || height == 0 ||
1651
0
      height == INT_MIN) {
1652
0
    return -1;
1653
0
  }
1654
  // Negative height means invert the image.
1655
0
  if (height < 0) {
1656
0
    height = -height;
1657
0
    halfheight = (height + 1) >> 1;
1658
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1659
0
    src_stride_y = -src_stride_y;
1660
0
  }
1661
0
  if (dst_y) {
1662
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1663
0
  }
1664
0
  SetPlane(dst_vu, dst_stride_vu, halfwidth * 2, halfheight, 128);
1665
0
  return 0;
1666
0
}
1667
1668
// Convert NV12 to I420.
1669
// TODO(fbarchard): Consider inverting destination. Faster on ARM with prfm.
1670
LIBYUV_API
1671
int NV12ToI420(const uint8_t* src_y,
1672
               int src_stride_y,
1673
               const uint8_t* src_uv,
1674
               int src_stride_uv,
1675
               uint8_t* dst_y,
1676
               int dst_stride_y,
1677
               uint8_t* dst_u,
1678
               int dst_stride_u,
1679
               uint8_t* dst_v,
1680
               int dst_stride_v,
1681
               int width,
1682
0
               int height) {
1683
0
  int halfwidth = (width + 1) >> 1;
1684
0
  int halfheight = (height + 1) >> 1;
1685
0
  if ((!src_y && dst_y) || !src_uv || !dst_u || !dst_v || width <= 0 ||
1686
0
      height == 0 || height == INT_MIN) {
1687
0
    return -1;
1688
0
  }
1689
  // Negative height means invert the image.
1690
0
  if (height < 0) {
1691
0
    height = -height;
1692
0
    halfheight = (height + 1) >> 1;
1693
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1694
0
    src_uv = src_uv + (ptrdiff_t)(halfheight - 1) * src_stride_uv;
1695
0
    src_stride_y = -src_stride_y;
1696
0
    src_stride_uv = -src_stride_uv;
1697
0
  }
1698
  // Coalesce rows.
1699
0
  if (src_stride_y == width && dst_stride_y == width &&
1700
0
      (ptrdiff_t)width * height <= INT_MAX) {
1701
0
    width *= height;
1702
0
    height = 1;
1703
0
    src_stride_y = dst_stride_y = 0;
1704
0
  }
1705
  // Coalesce rows.
1706
0
  if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
1707
0
      dst_stride_v == halfwidth &&
1708
0
      (ptrdiff_t)halfwidth * halfheight <= INT_MAX) {
1709
0
    halfwidth *= halfheight;
1710
0
    halfheight = 1;
1711
0
    src_stride_uv = dst_stride_u = dst_stride_v = 0;
1712
0
  }
1713
1714
0
  if (dst_y) {
1715
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1716
0
  }
1717
1718
  // Split UV plane - NV12 / NV21
1719
0
  SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v,
1720
0
               halfwidth, halfheight);
1721
1722
0
  return 0;
1723
0
}
1724
1725
// Convert NV21 to I420.  Same as NV12 but u and v pointers swapped.
1726
LIBYUV_API
1727
int NV21ToI420(const uint8_t* src_y,
1728
               int src_stride_y,
1729
               const uint8_t* src_vu,
1730
               int src_stride_vu,
1731
               uint8_t* dst_y,
1732
               int dst_stride_y,
1733
               uint8_t* dst_u,
1734
               int dst_stride_u,
1735
               uint8_t* dst_v,
1736
               int dst_stride_v,
1737
               int width,
1738
0
               int height) {
1739
0
  return NV12ToI420(src_y, src_stride_y, src_vu, src_stride_vu, dst_y,
1740
0
                    dst_stride_y, dst_v, dst_stride_v, dst_u, dst_stride_u,
1741
0
                    width, height);
1742
0
}
1743
1744
LIBYUV_API
1745
int NV12ToNV24(const uint8_t* src_y,
1746
               int src_stride_y,
1747
               const uint8_t* src_uv,
1748
               int src_stride_uv,
1749
               uint8_t* dst_y,
1750
               int dst_stride_y,
1751
               uint8_t* dst_uv,
1752
               int dst_stride_uv,
1753
               int width,
1754
0
               int height) {
1755
0
  int r;
1756
0
  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0 ||
1757
0
      height == INT_MIN) {
1758
0
    return -1;
1759
0
  }
1760
1761
0
  if (dst_y) {
1762
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1763
0
  }
1764
0
  r = UVScale(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1),
1765
0
              SUBSAMPLE(height, 1, 1), dst_uv, dst_stride_uv, Abs(width),
1766
0
              Abs(height), kFilterBilinear);
1767
0
  return r;
1768
0
}
1769
1770
LIBYUV_API
1771
int NV16ToNV24(const uint8_t* src_y,
1772
               int src_stride_y,
1773
               const uint8_t* src_uv,
1774
               int src_stride_uv,
1775
               uint8_t* dst_y,
1776
               int dst_stride_y,
1777
               uint8_t* dst_uv,
1778
               int dst_stride_uv,
1779
               int width,
1780
0
               int height) {
1781
0
  int r;
1782
0
  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0 ||
1783
0
      height == INT_MIN) {
1784
0
    return -1;
1785
0
  }
1786
1787
0
  if (dst_y) {
1788
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1789
0
  }
1790
0
  r = UVScale(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1), height, dst_uv,
1791
0
              dst_stride_uv, Abs(width), Abs(height), kFilterBilinear);
1792
0
  return r;
1793
0
}
1794
1795
// Any P[420]1[02] to I[420]1[02] format
1796
static int PxxxToIxxx(const uint16_t* src_y,
1797
                      int src_stride_y,
1798
                      const uint16_t* src_uv,
1799
                      int src_stride_uv,
1800
                      uint16_t* dst_y,
1801
                      int dst_stride_y,
1802
                      uint16_t* dst_u,
1803
                      int dst_stride_u,
1804
                      uint16_t* dst_v,
1805
                      int dst_stride_v,
1806
                      int width,
1807
                      int height,
1808
                      int subsample_x,
1809
                      int subsample_y,
1810
0
                      int depth) {
1811
0
  const int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
1812
0
  const int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
1813
0
  if (!src_y || !dst_y || !src_uv || !dst_u || !dst_v || width <= 0 ||
1814
0
      height == 0 || height == INT_MIN) {
1815
0
    return -1;
1816
0
  }
1817
0
  ConvertToLSBPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
1818
0
                       depth);
1819
0
  SplitUVPlane_16(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
1820
0
                  dst_stride_v, uv_width, uv_height, depth);
1821
0
  return 0;
1822
0
}
1823
1824
LIBYUV_API
1825
int P010ToI010(const uint16_t* src_y,
1826
               int src_stride_y,
1827
               const uint16_t* src_uv,
1828
               int src_stride_uv,
1829
               uint16_t* dst_y,
1830
               int dst_stride_y,
1831
               uint16_t* dst_u,
1832
               int dst_stride_u,
1833
               uint16_t* dst_v,
1834
               int dst_stride_v,
1835
               int width,
1836
0
               int height) {
1837
0
  return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
1838
0
                    dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
1839
0
                    width, height, 1, 1, 10);
1840
0
}
1841
1842
LIBYUV_API
1843
int P012ToI012(const uint16_t* src_y,
1844
               int src_stride_y,
1845
               const uint16_t* src_uv,
1846
               int src_stride_uv,
1847
               uint16_t* dst_y,
1848
               int dst_stride_y,
1849
               uint16_t* dst_u,
1850
               int dst_stride_u,
1851
               uint16_t* dst_v,
1852
               int dst_stride_v,
1853
               int width,
1854
0
               int height) {
1855
0
  return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
1856
0
                    dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
1857
0
                    width, height, 1, 1, 12);
1858
0
}
1859
1860
LIBYUV_API
1861
int P010ToP410(const uint16_t* src_y,
1862
               int src_stride_y,
1863
               const uint16_t* src_uv,
1864
               int src_stride_uv,
1865
               uint16_t* dst_y,
1866
               int dst_stride_y,
1867
               uint16_t* dst_uv,
1868
               int dst_stride_uv,
1869
               int width,
1870
0
               int height) {
1871
0
  int r;
1872
0
  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0 ||
1873
0
      height == INT_MIN) {
1874
0
    return -1;
1875
0
  }
1876
1877
0
  if (dst_y) {
1878
0
    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1879
0
  }
1880
0
  r = UVScale_16(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1),
1881
0
                 SUBSAMPLE(height, 1, 1), dst_uv, dst_stride_uv, Abs(width),
1882
0
                 Abs(height), kFilterBilinear);
1883
0
  return r;
1884
0
}
1885
1886
LIBYUV_API
1887
int P210ToP410(const uint16_t* src_y,
1888
               int src_stride_y,
1889
               const uint16_t* src_uv,
1890
               int src_stride_uv,
1891
               uint16_t* dst_y,
1892
               int dst_stride_y,
1893
               uint16_t* dst_uv,
1894
               int dst_stride_uv,
1895
               int width,
1896
0
               int height) {
1897
0
  int r;
1898
0
  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0 ||
1899
0
      height == INT_MIN) {
1900
0
    return -1;
1901
0
  }
1902
1903
0
  if (dst_y) {
1904
0
    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1905
0
  }
1906
0
  r = UVScale_16(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1), height, dst_uv,
1907
0
                 dst_stride_uv, Abs(width), Abs(height), kFilterBilinear);
1908
0
  return r;
1909
0
}
1910
1911
// Convert YUY2 to I420.
1912
LIBYUV_API
1913
int YUY2ToI420(const uint8_t* src_yuy2,
1914
               int src_stride_yuy2,
1915
               uint8_t* dst_y,
1916
               int dst_stride_y,
1917
               uint8_t* dst_u,
1918
               int dst_stride_u,
1919
               uint8_t* dst_v,
1920
               int dst_stride_v,
1921
               int width,
1922
0
               int height) {
1923
0
  int y;
1924
0
  void (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2,
1925
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
1926
0
      YUY2ToUVRow_C;
1927
0
  void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) =
1928
0
      YUY2ToYRow_C;
1929
0
  if (width <= 0 || height == 0 || height == INT_MIN) {
1930
0
    return -1;
1931
0
  }
1932
  // Negative height means invert the image.
1933
0
  if (height < 0) {
1934
0
    height = -height;
1935
0
    src_yuy2 = src_yuy2 + (ptrdiff_t)(height - 1) * src_stride_yuy2;
1936
0
    src_stride_yuy2 = -src_stride_yuy2;
1937
0
  }
1938
0
#if defined(HAS_YUY2TOYROW_SSE2)
1939
0
  if (TestCpuFlag(kCpuHasSSE2)) {
1940
0
    YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
1941
0
    YUY2ToYRow = YUY2ToYRow_Any_SSE2;
1942
0
    if (IS_ALIGNED(width, 16)) {
1943
0
      YUY2ToUVRow = YUY2ToUVRow_SSE2;
1944
0
      YUY2ToYRow = YUY2ToYRow_SSE2;
1945
0
    }
1946
0
  }
1947
0
#endif
1948
0
#if defined(HAS_YUY2TOYROW_AVX2)
1949
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1950
0
    YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
1951
0
    YUY2ToYRow = YUY2ToYRow_Any_AVX2;
1952
0
    if (IS_ALIGNED(width, 32)) {
1953
0
      YUY2ToUVRow = YUY2ToUVRow_AVX2;
1954
0
      YUY2ToYRow = YUY2ToYRow_AVX2;
1955
0
    }
1956
0
  }
1957
0
#endif
1958
#if defined(HAS_YUY2TOYROW_NEON)
1959
  if (TestCpuFlag(kCpuHasNEON)) {
1960
    YUY2ToYRow = YUY2ToYRow_Any_NEON;
1961
    YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
1962
    if (IS_ALIGNED(width, 16)) {
1963
      YUY2ToYRow = YUY2ToYRow_NEON;
1964
      YUY2ToUVRow = YUY2ToUVRow_NEON;
1965
    }
1966
  }
1967
#endif
1968
#if defined(HAS_YUY2TOYROW_SVE2) && defined(HAS_YUY2TOUVROW_SVE2)
1969
  if (TestCpuFlag(kCpuHasSVE2)) {
1970
    YUY2ToYRow = YUY2ToYRow_SVE2;
1971
    YUY2ToUVRow = YUY2ToUVRow_SVE2;
1972
  }
1973
#endif
1974
#if defined(HAS_YUY2TOYROW_LSX) && defined(HAS_YUY2TOUVROW_LSX)
1975
  if (TestCpuFlag(kCpuHasLSX)) {
1976
    YUY2ToYRow = YUY2ToYRow_Any_LSX;
1977
    YUY2ToUVRow = YUY2ToUVRow_Any_LSX;
1978
    if (IS_ALIGNED(width, 16)) {
1979
      YUY2ToYRow = YUY2ToYRow_LSX;
1980
      YUY2ToUVRow = YUY2ToUVRow_LSX;
1981
    }
1982
  }
1983
#endif
1984
#if defined(HAS_YUY2TOYROW_LASX) && defined(HAS_YUY2TOUVROW_LASX)
1985
  if (TestCpuFlag(kCpuHasLASX)) {
1986
    YUY2ToYRow = YUY2ToYRow_Any_LASX;
1987
    YUY2ToUVRow = YUY2ToUVRow_Any_LASX;
1988
    if (IS_ALIGNED(width, 32)) {
1989
      YUY2ToYRow = YUY2ToYRow_LASX;
1990
      YUY2ToUVRow = YUY2ToUVRow_LASX;
1991
    }
1992
  }
1993
#endif
1994
1995
0
  for (y = 0; y < height - 1; y += 2) {
1996
0
    YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
1997
0
    YUY2ToYRow(src_yuy2, dst_y, width);
1998
0
    YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
1999
0
    src_yuy2 += src_stride_yuy2 * 2;
2000
0
    dst_y += dst_stride_y * 2;
2001
0
    dst_u += dst_stride_u;
2002
0
    dst_v += dst_stride_v;
2003
0
  }
2004
0
  if (height & 1) {
2005
0
    YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
2006
0
    YUY2ToYRow(src_yuy2, dst_y, width);
2007
0
  }
2008
0
  return 0;
2009
0
}
2010
2011
// Convert UYVY to I420.
2012
LIBYUV_API
2013
int UYVYToI420(const uint8_t* src_uyvy,
2014
               int src_stride_uyvy,
2015
               uint8_t* dst_y,
2016
               int dst_stride_y,
2017
               uint8_t* dst_u,
2018
               int dst_stride_u,
2019
               uint8_t* dst_v,
2020
               int dst_stride_v,
2021
               int width,
2022
0
               int height) {
2023
0
  int y;
2024
0
  void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy,
2025
0
                      uint8_t* dst_u, uint8_t* dst_v, int width) =
2026
0
      UYVYToUVRow_C;
2027
0
  void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) =
2028
0
      UYVYToYRow_C;
2029
0
  if (width <= 0 || height == 0 || height == INT_MIN) {
2030
0
    return -1;
2031
0
  }
2032
  // Negative height means invert the image.
2033
0
  if (height < 0) {
2034
0
    height = -height;
2035
0
    src_uyvy = src_uyvy + (ptrdiff_t)(height - 1) * src_stride_uyvy;
2036
0
    src_stride_uyvy = -src_stride_uyvy;
2037
0
  }
2038
0
#if defined(HAS_UYVYTOYROW_SSE2)
2039
0
  if (TestCpuFlag(kCpuHasSSE2)) {
2040
0
    UYVYToUVRow = UYVYToUVRow_Any_SSE2;
2041
0
    UYVYToYRow = UYVYToYRow_Any_SSE2;
2042
0
    if (IS_ALIGNED(width, 16)) {
2043
0
      UYVYToUVRow = UYVYToUVRow_SSE2;
2044
0
      UYVYToYRow = UYVYToYRow_SSE2;
2045
0
    }
2046
0
  }
2047
0
#endif
2048
0
#if defined(HAS_UYVYTOYROW_AVX2)
2049
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2050
0
    UYVYToUVRow = UYVYToUVRow_Any_AVX2;
2051
0
    UYVYToYRow = UYVYToYRow_Any_AVX2;
2052
0
    if (IS_ALIGNED(width, 32)) {
2053
0
      UYVYToUVRow = UYVYToUVRow_AVX2;
2054
0
      UYVYToYRow = UYVYToYRow_AVX2;
2055
0
    }
2056
0
  }
2057
0
#endif
2058
#if defined(HAS_UYVYTOYROW_NEON)
2059
  if (TestCpuFlag(kCpuHasNEON)) {
2060
    UYVYToYRow = UYVYToYRow_Any_NEON;
2061
    UYVYToUVRow = UYVYToUVRow_Any_NEON;
2062
    if (IS_ALIGNED(width, 16)) {
2063
      UYVYToYRow = UYVYToYRow_NEON;
2064
      UYVYToUVRow = UYVYToUVRow_NEON;
2065
    }
2066
  }
2067
#endif
2068
#if defined(HAS_UYVYTOYROW_SVE2) && defined(HAS_UYVYTOUVROW_SVE2)
2069
  if (TestCpuFlag(kCpuHasSVE2)) {
2070
    UYVYToYRow = UYVYToYRow_SVE2;
2071
    UYVYToUVRow = UYVYToUVRow_SVE2;
2072
  }
2073
#endif
2074
#if defined(HAS_UYVYTOYROW_LSX)
2075
  if (TestCpuFlag(kCpuHasLSX)) {
2076
    UYVYToYRow = UYVYToYRow_Any_LSX;
2077
    UYVYToUVRow = UYVYToUVRow_Any_LSX;
2078
    if (IS_ALIGNED(width, 16)) {
2079
      UYVYToYRow = UYVYToYRow_LSX;
2080
      UYVYToUVRow = UYVYToUVRow_LSX;
2081
    }
2082
  }
2083
#endif
2084
#if defined(HAS_UYVYTOYROW_LSX)
2085
  if (TestCpuFlag(kCpuHasLSX)) {
2086
    UYVYToYRow = UYVYToYRow_Any_LSX;
2087
    UYVYToUVRow = UYVYToUVRow_Any_LSX;
2088
    if (IS_ALIGNED(width, 16)) {
2089
      UYVYToYRow = UYVYToYRow_LSX;
2090
      UYVYToUVRow = UYVYToUVRow_LSX;
2091
    }
2092
  }
2093
#endif
2094
#if defined(HAS_UYVYTOYROW_LASX)
2095
  if (TestCpuFlag(kCpuHasLASX)) {
2096
    UYVYToYRow = UYVYToYRow_Any_LASX;
2097
    UYVYToUVRow = UYVYToUVRow_Any_LASX;
2098
    if (IS_ALIGNED(width, 32)) {
2099
      UYVYToYRow = UYVYToYRow_LASX;
2100
      UYVYToUVRow = UYVYToUVRow_LASX;
2101
    }
2102
  }
2103
#endif
2104
2105
0
  for (y = 0; y < height - 1; y += 2) {
2106
0
    UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
2107
0
    UYVYToYRow(src_uyvy, dst_y, width);
2108
0
    UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
2109
0
    src_uyvy += src_stride_uyvy * 2;
2110
0
    dst_y += dst_stride_y * 2;
2111
0
    dst_u += dst_stride_u;
2112
0
    dst_v += dst_stride_v;
2113
0
  }
2114
0
  if (height & 1) {
2115
0
    UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
2116
0
    UYVYToYRow(src_uyvy, dst_y, width);
2117
0
  }
2118
0
  return 0;
2119
0
}
2120
2121
// Convert AYUV to NV12.
2122
LIBYUV_API
2123
int AYUVToNV12(const uint8_t* src_ayuv,
2124
               int src_stride_ayuv,
2125
               uint8_t* dst_y,
2126
               int dst_stride_y,
2127
               uint8_t* dst_uv,
2128
               int dst_stride_uv,
2129
               int width,
2130
0
               int height) {
2131
0
  int y;
2132
0
  void (*AYUVToUVRow)(const uint8_t* src_ayuv, int src_stride_ayuv,
2133
0
                      uint8_t* dst_uv, int width) = AYUVToUVRow_C;
2134
0
  void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
2135
0
      AYUVToYRow_C;
2136
0
  if (width <= 0 || height == 0 || height == INT_MIN) {
2137
0
    return -1;
2138
0
  }
2139
  // Negative height means invert the image.
2140
0
  if (height < 0) {
2141
0
    height = -height;
2142
0
    src_ayuv = src_ayuv + (ptrdiff_t)(height - 1) * src_stride_ayuv;
2143
0
    src_stride_ayuv = -src_stride_ayuv;
2144
0
  }
2145
// place holders for future intel code
2146
#if defined(HAS_AYUVTOYROW_SSE2)
2147
  if (TestCpuFlag(kCpuHasSSE2)) {
2148
    AYUVToUVRow = AYUVToUVRow_Any_SSE2;
2149
    AYUVToYRow = AYUVToYRow_Any_SSE2;
2150
    if (IS_ALIGNED(width, 16)) {
2151
      AYUVToUVRow = AYUVToUVRow_SSE2;
2152
      AYUVToYRow = AYUVToYRow_SSE2;
2153
    }
2154
  }
2155
#endif
2156
#if defined(HAS_AYUVTOYROW_AVX2)
2157
  if (TestCpuFlag(kCpuHasAVX2)) {
2158
    AYUVToUVRow = AYUVToUVRow_Any_AVX2;
2159
    AYUVToYRow = AYUVToYRow_Any_AVX2;
2160
    if (IS_ALIGNED(width, 32)) {
2161
      AYUVToUVRow = AYUVToUVRow_AVX2;
2162
      AYUVToYRow = AYUVToYRow_AVX2;
2163
    }
2164
  }
2165
#endif
2166
2167
#if defined(HAS_AYUVTOYROW_NEON)
2168
  if (TestCpuFlag(kCpuHasNEON)) {
2169
    AYUVToYRow = AYUVToYRow_Any_NEON;
2170
    AYUVToUVRow = AYUVToUVRow_Any_NEON;
2171
    if (IS_ALIGNED(width, 16)) {
2172
      AYUVToYRow = AYUVToYRow_NEON;
2173
      AYUVToUVRow = AYUVToUVRow_NEON;
2174
    }
2175
  }
2176
#endif
2177
#if defined(HAS_AYUVTOUVROW_SVE2)
2178
  if (TestCpuFlag(kCpuHasSVE2)) {
2179
    AYUVToUVRow = AYUVToUVRow_Any_SVE2;
2180
    if (IS_ALIGNED(width, 2)) {
2181
      AYUVToUVRow = AYUVToUVRow_SVE2;
2182
    }
2183
  }
2184
#endif
2185
2186
0
  for (y = 0; y < height - 1; y += 2) {
2187
0
    AYUVToUVRow(src_ayuv, src_stride_ayuv, dst_uv, width);
2188
0
    AYUVToYRow(src_ayuv, dst_y, width);
2189
0
    AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
2190
0
    src_ayuv += src_stride_ayuv * 2;
2191
0
    dst_y += dst_stride_y * 2;
2192
0
    dst_uv += dst_stride_uv;
2193
0
  }
2194
0
  if (height & 1) {
2195
0
    AYUVToUVRow(src_ayuv, 0, dst_uv, width);
2196
0
    AYUVToYRow(src_ayuv, dst_y, width);
2197
0
  }
2198
0
  return 0;
2199
0
}
2200
2201
// Convert AYUV to NV21.
2202
LIBYUV_API
2203
int AYUVToNV21(const uint8_t* src_ayuv,
2204
               int src_stride_ayuv,
2205
               uint8_t* dst_y,
2206
               int dst_stride_y,
2207
               uint8_t* dst_vu,
2208
               int dst_stride_vu,
2209
               int width,
2210
0
               int height) {
2211
0
  int y;
2212
0
  void (*AYUVToVURow)(const uint8_t* src_ayuv, int src_stride_ayuv,
2213
0
                      uint8_t* dst_vu, int width) = AYUVToVURow_C;
2214
0
  void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
2215
0
      AYUVToYRow_C;
2216
0
  if (width <= 0 || height == 0 || height == INT_MIN) {
2217
0
    return -1;
2218
0
  }
2219
  // Negative height means invert the image.
2220
0
  if (height < 0) {
2221
0
    height = -height;
2222
0
    src_ayuv = src_ayuv + (ptrdiff_t)(height - 1) * src_stride_ayuv;
2223
0
    src_stride_ayuv = -src_stride_ayuv;
2224
0
  }
2225
// place holders for future intel code
2226
#if defined(HAS_AYUVTOYROW_SSE2)
2227
  if (TestCpuFlag(kCpuHasSSE2)) {
2228
    AYUVToVURow = AYUVToVURow_Any_SSE2;
2229
    AYUVToYRow = AYUVToYRow_Any_SSE2;
2230
    if (IS_ALIGNED(width, 16)) {
2231
      AYUVToVURow = AYUVToVURow_SSE2;
2232
      AYUVToYRow = AYUVToYRow_SSE2;
2233
    }
2234
  }
2235
#endif
2236
#if defined(HAS_AYUVTOYROW_AVX2)
2237
  if (TestCpuFlag(kCpuHasAVX2)) {
2238
    AYUVToVURow = AYUVToVURow_Any_AVX2;
2239
    AYUVToYRow = AYUVToYRow_Any_AVX2;
2240
    if (IS_ALIGNED(width, 32)) {
2241
      AYUVToVURow = AYUVToVURow_AVX2;
2242
      AYUVToYRow = AYUVToYRow_AVX2;
2243
    }
2244
  }
2245
#endif
2246
2247
#if defined(HAS_AYUVTOYROW_NEON)
2248
  if (TestCpuFlag(kCpuHasNEON)) {
2249
    AYUVToYRow = AYUVToYRow_Any_NEON;
2250
    AYUVToVURow = AYUVToVURow_Any_NEON;
2251
    if (IS_ALIGNED(width, 16)) {
2252
      AYUVToYRow = AYUVToYRow_NEON;
2253
      AYUVToVURow = AYUVToVURow_NEON;
2254
    }
2255
  }
2256
#endif
2257
#if defined(HAS_AYUVTOVUROW_SVE2)
2258
  if (TestCpuFlag(kCpuHasSVE2)) {
2259
    AYUVToVURow = AYUVToVURow_Any_SVE2;
2260
    if (IS_ALIGNED(width, 2)) {
2261
      AYUVToVURow = AYUVToVURow_SVE2;
2262
    }
2263
  }
2264
#endif
2265
2266
0
  for (y = 0; y < height - 1; y += 2) {
2267
0
    AYUVToVURow(src_ayuv, src_stride_ayuv, dst_vu, width);
2268
0
    AYUVToYRow(src_ayuv, dst_y, width);
2269
0
    AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
2270
0
    src_ayuv += src_stride_ayuv * 2;
2271
0
    dst_y += dst_stride_y * 2;
2272
0
    dst_vu += dst_stride_vu;
2273
0
  }
2274
0
  if (height & 1) {
2275
0
    AYUVToVURow(src_ayuv, 0, dst_vu, width);
2276
0
    AYUVToYRow(src_ayuv, dst_y, width);
2277
0
  }
2278
0
  return 0;
2279
0
}
2280
2281
// Convert ARGB to I420.
2282
LIBYUV_API
2283
int ARGBToI420(const uint8_t* src_argb,
2284
               int src_stride_argb,
2285
               uint8_t* dst_y,
2286
               int dst_stride_y,
2287
               uint8_t* dst_u,
2288
               int dst_stride_u,
2289
               uint8_t* dst_v,
2290
               int dst_stride_v,
2291
               int width,
2292
0
               int height) {
2293
0
  return ARGBToI420Matrix(src_argb, src_stride_argb, dst_y, dst_stride_y, dst_u,
2294
0
                          dst_stride_u, dst_v, dst_stride_v,
2295
0
                          &kArgbI601Constants, width, height);
2296
0
}
2297
2298
LIBYUV_API
2299
int ARGBToI420Matrix(const uint8_t* src_argb,
2300
                     int src_stride_argb,
2301
                     uint8_t* dst_y,
2302
                     int dst_stride_y,
2303
                     uint8_t* dst_u,
2304
                     int dst_stride_u,
2305
                     uint8_t* dst_v,
2306
                     int dst_stride_v,
2307
                     const struct ArgbConstants* argbconstants,
2308
                     int width,
2309
5
                     int height) {
2310
5
  int y;
2311
5
  void (*ARGBToYMatrixRow)(const uint8_t* src_argb, uint8_t* dst_y, int width,
2312
5
                           const struct ArgbConstants* c) = ARGBToYMatrixRow_C;
2313
5
  void (*ARGBToUVMatrixRow)(const uint8_t* src_argb, int src_stride_argb,
2314
5
                            uint8_t* dst_u, uint8_t* dst_v, int width,
2315
5
                            const struct ArgbConstants* c) =
2316
5
      ARGBToUVMatrixRow_C;
2317
2318
5
#if defined(HAS_ARGBTOYMATRIXROW_SSSE3)
2319
5
  if (TestCpuFlag(kCpuHasSSSE3)) {
2320
5
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_SSSE3;
2321
5
    if (IS_ALIGNED(width, 16)) {
2322
2
      ARGBToYMatrixRow = ARGBToYMatrixRow_SSSE3;
2323
2
    }
2324
5
  }
2325
5
#endif
2326
5
#if defined(HAS_ARGBTOYMATRIXROW_AVX2)
2327
5
  if (TestCpuFlag(kCpuHasAVX2)) {
2328
5
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX2;
2329
5
    if (IS_ALIGNED(width, 32)) {
2330
2
      ARGBToYMatrixRow = ARGBToYMatrixRow_AVX2;
2331
2
    }
2332
5
  }
2333
5
#endif
2334
5
#if defined(HAS_ARGBTOYMATRIXROW_AVX512BW)
2335
5
  if (TestCpuFlag(kCpuHasAVX512BW)) {
2336
0
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX512BW;
2337
0
    if (IS_ALIGNED(width, 64)) {
2338
0
      ARGBToYMatrixRow = ARGBToYMatrixRow_AVX512BW;
2339
0
    }
2340
0
  }
2341
5
#endif
2342
#if defined(HAS_ARGBTOYMATRIXROW_NEON)
2343
  if (TestCpuFlag(kCpuHasNEON)) {
2344
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON;
2345
    if (IS_ALIGNED(width, 16)) {
2346
      ARGBToYMatrixRow = ARGBToYMatrixRow_NEON;
2347
    }
2348
  }
2349
#endif
2350
#if defined(HAS_ARGBTOYMATRIXROW_NEON_DOTPROD)
2351
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
2352
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON_DotProd;
2353
    if (IS_ALIGNED(width, 16)) {
2354
      ARGBToYMatrixRow = ARGBToYMatrixRow_NEON_DotProd;
2355
    }
2356
  }
2357
#endif
2358
#if defined(HAS_ARGBTOYMATRIXROW_SVE2)
2359
  if (TestCpuFlag(kCpuHasSVE2)) {
2360
    ARGBToYMatrixRow = ARGBToYMatrixRow_SVE2;
2361
  }
2362
#endif
2363
#if defined(HAS_ARGBTOYMATRIXROW_SME)
2364
  if (TestCpuFlag(kCpuHasSME)) {
2365
    ARGBToYMatrixRow = ARGBToYMatrixRow_SME;
2366
  }
2367
#endif
2368
#if defined(HAS_ARGBTOYMATRIXROW_LSX)
2369
  if (TestCpuFlag(kCpuHasLSX)) {
2370
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LSX;
2371
    if (IS_ALIGNED(width, 16)) {
2372
      ARGBToYMatrixRow = ARGBToYMatrixRow_LSX;
2373
    }
2374
  }
2375
#endif
2376
#if defined(HAS_ARGBTOYMATRIXROW_LASX)
2377
  if (TestCpuFlag(kCpuHasLASX)) {
2378
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LASX;
2379
    if (IS_ALIGNED(width, 32)) {
2380
      ARGBToYMatrixRow = ARGBToYMatrixRow_LASX;
2381
    }
2382
  }
2383
#endif
2384
#if defined(HAS_ARGBTOYMATRIXROW_RVV)
2385
  if (TestCpuFlag(kCpuHasRVV)) {
2386
    ARGBToYMatrixRow = ARGBToYMatrixRow_RVV;
2387
  }
2388
#endif
2389
2390
#if defined(HAS_ARGBTOUVMATRIXROW_NEON)
2391
  if (TestCpuFlag(kCpuHasNEON)) {
2392
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_NEON;
2393
    if (IS_ALIGNED(width, 16)) {
2394
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_NEON;
2395
    }
2396
  }
2397
#endif
2398
#if defined(HAS_ARGBTOUVMATRIXROW_NEON_I8MM)
2399
  if (TestCpuFlag(kCpuHasNEON) && TestCpuFlag(kCpuHasNeonI8MM)) {
2400
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_NEON_I8MM;
2401
    if (IS_ALIGNED(width, 16)) {
2402
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_NEON_I8MM;
2403
    }
2404
  }
2405
#endif
2406
#if defined(HAS_ARGBTOUVMATRIXROW_SVE2)
2407
  if (TestCpuFlag(kCpuHasSVE2)) {
2408
    if (IS_ALIGNED(width, 2)) {
2409
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_SVE2;
2410
    }
2411
  }
2412
#endif
2413
#if defined(HAS_ARGBTOUVMATRIXROW_SME)
2414
  if (TestCpuFlag(kCpuHasSME)) {
2415
    if (IS_ALIGNED(width, 2)) {
2416
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_SME;
2417
    }
2418
  }
2419
#endif
2420
5
#if defined(HAS_ARGBTOUVMATRIXROW_SSSE3)
2421
5
  if (TestCpuFlag(kCpuHasSSSE3)) {
2422
5
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_SSSE3;
2423
5
    if (IS_ALIGNED(width, 8)) {
2424
2
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_SSSE3;
2425
2
    }
2426
5
  }
2427
5
#endif
2428
5
#if defined(HAS_ARGBTOUVMATRIXROW_AVX2)
2429
5
  if (TestCpuFlag(kCpuHasAVX2)) {
2430
5
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_AVX2;
2431
5
    if (IS_ALIGNED(width, 32)) {
2432
2
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_AVX2;
2433
2
    }
2434
5
  }
2435
5
#endif
2436
5
#if defined(HAS_ARGBTOUVMATRIXROW_AVX512BW)
2437
5
  if (TestCpuFlag(kCpuHasAVX512BW)) {
2438
0
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_AVX512BW;
2439
0
    if (IS_ALIGNED(width, 64)) {
2440
0
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_AVX512BW;
2441
0
    }
2442
0
  }
2443
5
#endif
2444
#if defined(HAS_ARGBTOUVMATRIXROW_RVV)
2445
  if (TestCpuFlag(kCpuHasRVV)) {
2446
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_RVV;
2447
  }
2448
#endif
2449
5
  if (!src_argb || !dst_y || !dst_u || !dst_v || !argbconstants || width <= 0 ||
2450
5
      height == 0 || height == INT_MIN) {
2451
0
    return -1;
2452
0
  }
2453
  // Negative height means invert the image.
2454
5
  if (height < 0) {
2455
0
    height = -height;
2456
0
    src_argb = src_argb + (ptrdiff_t)(height - 1) * src_stride_argb;
2457
0
    src_stride_argb = -src_stride_argb;
2458
0
  }
2459
2460
454
  for (y = 0; y < height - 1; y += 2) {
2461
449
    ARGBToUVMatrixRow(src_argb, src_stride_argb, dst_u, dst_v, width,
2462
449
                      argbconstants);
2463
449
    ARGBToYMatrixRow(src_argb, dst_y, width, argbconstants);
2464
449
    ARGBToYMatrixRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width,
2465
449
                     argbconstants);
2466
449
    src_argb += src_stride_argb * 2;
2467
449
    dst_y += dst_stride_y * 2;
2468
449
    dst_u += dst_stride_u;
2469
449
    dst_v += dst_stride_v;
2470
449
  }
2471
5
  if (height & 1) {
2472
1
    ARGBToUVMatrixRow(src_argb, 0, dst_u, dst_v, width, argbconstants);
2473
1
    ARGBToYMatrixRow(src_argb, dst_y, width, argbconstants);
2474
1
  }
2475
5
  return 0;
2476
5
}
2477
2478
#ifdef USE_EXTRACTALPHA
2479
// Convert ARGB to I420 with Alpha
2480
// The following version calls ARGBExtractAlpha on the full image.
2481
LIBYUV_API
2482
int ARGBToI420Alpha(const uint8_t* src_argb,
2483
                    int src_stride_argb,
2484
                    uint8_t* dst_y,
2485
                    int dst_stride_y,
2486
                    uint8_t* dst_u,
2487
                    int dst_stride_u,
2488
                    uint8_t* dst_v,
2489
                    int dst_stride_v,
2490
                    uint8_t* dst_a,
2491
                    int dst_stride_a,
2492
                    int width,
2493
                    int height) {
2494
  int r = ARGBToI420(src_argb, src_stride_argb, dst_y, dst_stride_y, dst_u,
2495
                     dst_stride_u, dst_v, dst_stride_v, width, height);
2496
  if (r == 0) {
2497
    r = ARGBExtractAlpha(src_argb, src_stride_argb, dst_a, dst_stride_a, width,
2498
                         height);
2499
  }
2500
  return r;
2501
}
2502
#else  // USE_EXTRACTALPHA
2503
// Convert ARGB to I420 with Alpha
2504
LIBYUV_API
2505
int ARGBToI420Alpha(const uint8_t* src_argb,
2506
                    int src_stride_argb,
2507
                    uint8_t* dst_y,
2508
                    int dst_stride_y,
2509
                    uint8_t* dst_u,
2510
                    int dst_stride_u,
2511
                    uint8_t* dst_v,
2512
                    int dst_stride_v,
2513
                    uint8_t* dst_a,
2514
                    int dst_stride_a,
2515
                    int width,
2516
0
                    int height) {
2517
0
  int y;
2518
0
  void (*ARGBToYMatrixRow)(const uint8_t* src_argb, uint8_t* dst_y, int width,
2519
0
                           const struct ArgbConstants* c) = ARGBToYMatrixRow_C;
2520
0
  void (*ARGBToUVMatrixRow)(const uint8_t* src_argb, int src_stride_argb,
2521
0
                            uint8_t* dst_u, uint8_t* dst_v, int width,
2522
0
                            const struct ArgbConstants* c) =
2523
0
      ARGBToUVMatrixRow_C;
2524
0
  void (*ARGBExtractAlphaRow)(const uint8_t* src_argb, uint8_t* dst_a,
2525
0
                              int width) = ARGBExtractAlphaRow_C;
2526
0
  if (!src_argb || !dst_y || !dst_u || !dst_v || !dst_a || width <= 0 ||
2527
0
      height == 0 || height == INT_MIN) {
2528
0
    return -1;
2529
0
  }
2530
  // Negative height means invert the image.
2531
0
  if (height < 0) {
2532
0
    height = -height;
2533
0
    src_argb = src_argb + (ptrdiff_t)(height - 1) * src_stride_argb;
2534
0
    src_stride_argb = -src_stride_argb;
2535
0
  }
2536
2537
0
#if defined(HAS_ARGBTOYMATRIXROW_SSSE3)
2538
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2539
0
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_SSSE3;
2540
0
    if (IS_ALIGNED(width, 16)) {
2541
0
      ARGBToYMatrixRow = ARGBToYMatrixRow_SSSE3;
2542
0
    }
2543
0
  }
2544
0
#endif
2545
0
#if defined(HAS_ARGBTOYMATRIXROW_AVX2)
2546
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2547
0
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX2;
2548
0
    if (IS_ALIGNED(width, 32)) {
2549
0
      ARGBToYMatrixRow = ARGBToYMatrixRow_AVX2;
2550
0
    }
2551
0
  }
2552
0
#endif
2553
0
#if defined(HAS_ARGBTOYMATRIXROW_AVX512BW)
2554
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
2555
0
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX512BW;
2556
0
    if (IS_ALIGNED(width, 64)) {
2557
0
      ARGBToYMatrixRow = ARGBToYMatrixRow_AVX512BW;
2558
0
    }
2559
0
  }
2560
0
#endif
2561
#if defined(HAS_ARGBTOYMATRIXROW_NEON)
2562
  if (TestCpuFlag(kCpuHasNEON)) {
2563
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON;
2564
    if (IS_ALIGNED(width, 16)) {
2565
      ARGBToYMatrixRow = ARGBToYMatrixRow_NEON;
2566
    }
2567
  }
2568
#endif
2569
#if defined(HAS_ARGBTOYMATRIXROW_NEON_DOTPROD)
2570
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
2571
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON_DotProd;
2572
    if (IS_ALIGNED(width, 16)) {
2573
      ARGBToYMatrixRow = ARGBToYMatrixRow_NEON_DotProd;
2574
    }
2575
  }
2576
#endif
2577
#if defined(HAS_ARGBTOYMATRIXROW_SVE2)
2578
  if (TestCpuFlag(kCpuHasSVE2)) {
2579
    ARGBToYMatrixRow = ARGBToYMatrixRow_SVE2;
2580
  }
2581
#endif
2582
#if defined(HAS_ARGBTOYMATRIXROW_SME)
2583
  if (TestCpuFlag(kCpuHasSME)) {
2584
    ARGBToYMatrixRow = ARGBToYMatrixRow_SME;
2585
  }
2586
#endif
2587
#if defined(HAS_ARGBTOYMATRIXROW_LSX)
2588
  if (TestCpuFlag(kCpuHasLSX)) {
2589
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LSX;
2590
    if (IS_ALIGNED(width, 16)) {
2591
      ARGBToYMatrixRow = ARGBToYMatrixRow_LSX;
2592
    }
2593
  }
2594
#endif
2595
#if defined(HAS_ARGBTOYMATRIXROW_LASX)
2596
  if (TestCpuFlag(kCpuHasLASX)) {
2597
    ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LASX;
2598
    if (IS_ALIGNED(width, 32)) {
2599
      ARGBToYMatrixRow = ARGBToYMatrixRow_LASX;
2600
    }
2601
  }
2602
#endif
2603
#if defined(HAS_ARGBTOYMATRIXROW_RVV)
2604
  if (TestCpuFlag(kCpuHasRVV)) {
2605
    ARGBToYMatrixRow = ARGBToYMatrixRow_RVV;
2606
  }
2607
#endif
2608
2609
#if defined(HAS_ARGBTOUVMATRIXROW_NEON)
2610
  if (TestCpuFlag(kCpuHasNEON)) {
2611
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_NEON;
2612
    if (IS_ALIGNED(width, 16)) {
2613
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_NEON;
2614
    }
2615
  }
2616
#endif
2617
#if defined(HAS_ARGBTOUVMATRIXROW_NEON_I8MM)
2618
  if (TestCpuFlag(kCpuHasNEON) && TestCpuFlag(kCpuHasNeonI8MM)) {
2619
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_NEON_I8MM;
2620
    if (IS_ALIGNED(width, 16)) {
2621
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_NEON_I8MM;
2622
    }
2623
  }
2624
#endif
2625
#if defined(HAS_ARGBTOUVMATRIXROW_SVE2)
2626
  if (TestCpuFlag(kCpuHasSVE2)) {
2627
    if (IS_ALIGNED(width, 2)) {
2628
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_SVE2;
2629
    }
2630
  }
2631
#endif
2632
#if defined(HAS_ARGBTOUVMATRIXROW_SME)
2633
  if (TestCpuFlag(kCpuHasSME)) {
2634
    if (IS_ALIGNED(width, 2)) {
2635
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_SME;
2636
    }
2637
  }
2638
#endif
2639
0
#if defined(HAS_ARGBTOUVMATRIXROW_SSSE3)
2640
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2641
0
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_SSSE3;
2642
0
    if (IS_ALIGNED(width, 8)) {
2643
0
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_SSSE3;
2644
0
    }
2645
0
  }
2646
0
#endif
2647
0
#if defined(HAS_ARGBTOUVMATRIXROW_AVX2)
2648
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2649
0
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_AVX2;
2650
0
    if (IS_ALIGNED(width, 32)) {
2651
0
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_AVX2;
2652
0
    }
2653
0
  }
2654
0
#endif
2655
0
#if defined(HAS_ARGBTOUVMATRIXROW_AVX512BW)
2656
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
2657
0
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_AVX512BW;
2658
0
    if (IS_ALIGNED(width, 64)) {
2659
0
      ARGBToUVMatrixRow = ARGBToUVMatrixRow_AVX512BW;
2660
0
    }
2661
0
  }
2662
0
#endif
2663
#if defined(HAS_ARGBTOUVMATRIXROW_RVV)
2664
  if (TestCpuFlag(kCpuHasRVV)) {
2665
    ARGBToUVMatrixRow = ARGBToUVMatrixRow_RVV;
2666
  }
2667
#endif
2668
2669
0
#if defined(HAS_ARGBEXTRACTALPHAROW_SSE2)
2670
0
  if (TestCpuFlag(kCpuHasSSE2)) {
2671
0
    ARGBExtractAlphaRow = IS_ALIGNED(width, 8) ? ARGBExtractAlphaRow_SSE2
2672
0
                                               : ARGBExtractAlphaRow_Any_SSE2;
2673
0
  }
2674
0
#endif
2675
0
#if defined(HAS_ARGBEXTRACTALPHAROW_AVX2)
2676
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2677
0
    ARGBExtractAlphaRow = IS_ALIGNED(width, 32) ? ARGBExtractAlphaRow_AVX2
2678
0
                                                : ARGBExtractAlphaRow_Any_AVX2;
2679
0
  }
2680
0
#endif
2681
#if defined(HAS_ARGBEXTRACTALPHAROW_NEON)
2682
  if (TestCpuFlag(kCpuHasNEON)) {
2683
    ARGBExtractAlphaRow = IS_ALIGNED(width, 16) ? ARGBExtractAlphaRow_NEON
2684
                                                : ARGBExtractAlphaRow_Any_NEON;
2685
  }
2686
#endif
2687
#if defined(HAS_ARGBEXTRACTALPHAROW_LSX)
2688
  if (TestCpuFlag(kCpuHasLSX)) {
2689
    ARGBExtractAlphaRow = IS_ALIGNED(width, 16) ? ARGBExtractAlphaRow_LSX
2690
                                                : ARGBExtractAlphaRow_Any_LSX;
2691
  }
2692
#endif
2693
#if defined(HAS_ARGBEXTRACTALPHAROW_RVV)
2694
  if (TestCpuFlag(kCpuHasRVV)) {
2695
    ARGBExtractAlphaRow = ARGBExtractAlphaRow_RVV;
2696
  }
2697
#endif
2698
2699
0
  for (y = 0; y < height - 1; y += 2) {
2700
0
    ARGBToUVMatrixRow(src_argb, src_stride_argb, dst_u, dst_v, width,
2701
0
                      &kArgbI601Constants);
2702
0
    ARGBToYMatrixRow(src_argb, dst_y, width, &kArgbI601Constants);
2703
0
    ARGBToYMatrixRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width,
2704
0
                     &kArgbI601Constants);
2705
0
    ARGBExtractAlphaRow(src_argb, dst_a, width);
2706
0
    ARGBExtractAlphaRow(src_argb + src_stride_argb, dst_a + dst_stride_a,
2707
0
                        width);
2708
0
    src_argb += src_stride_argb * 2;
2709
0
    dst_y += dst_stride_y * 2;
2710
0
    dst_u += dst_stride_u;
2711
0
    dst_v += dst_stride_v;
2712
0
    dst_a += dst_stride_a * 2;
2713
0
  }
2714
0
  if (height & 1) {
2715
0
    ARGBToUVMatrixRow(src_argb, 0, dst_u, dst_v, width, &kArgbI601Constants);
2716
0
    ARGBToYMatrixRow(src_argb, dst_y, width, &kArgbI601Constants);
2717
0
    ARGBExtractAlphaRow(src_argb, dst_a, width);
2718
0
  }
2719
0
  return 0;
2720
0
}
2721
#endif  // USE_EXTRACTALPHA
2722
2723
// Convert BGRA to I420.
2724
LIBYUV_API
2725
int BGRAToI420(const uint8_t* src_bgra,
2726
               int src_stride_bgra,
2727
               uint8_t* dst_y,
2728
               int dst_stride_y,
2729
               uint8_t* dst_u,
2730
               int dst_stride_u,
2731
               uint8_t* dst_v,
2732
               int dst_stride_v,
2733
               int width,
2734
0
               int height) {
2735
0
  return ARGBToI420Matrix(src_bgra, src_stride_bgra, dst_y, dst_stride_y, dst_u,
2736
0
                          dst_stride_u, dst_v, dst_stride_v,
2737
0
                          &kBgraI601Constants, width, height);
2738
0
}
2739
2740
// Convert BGRA to I422.
2741
LIBYUV_API
2742
int BGRAToI422(const uint8_t* src_bgra,
2743
               int src_stride_bgra,
2744
               uint8_t* dst_y,
2745
               int dst_stride_y,
2746
               uint8_t* dst_u,
2747
               int dst_stride_u,
2748
               uint8_t* dst_v,
2749
               int dst_stride_v,
2750
               int width,
2751
0
               int height) {
2752
0
  return ARGBToI422Matrix(src_bgra, src_stride_bgra, dst_y, dst_stride_y, dst_u,
2753
0
                          dst_stride_u, dst_v, dst_stride_v,
2754
0
                          &kBgraI601Constants, width, height);
2755
0
}
2756
2757
// Convert ABGR to I422.
2758
LIBYUV_API
2759
int ABGRToI422(const uint8_t* src_abgr,
2760
               int src_stride_abgr,
2761
               uint8_t* dst_y,
2762
               int dst_stride_y,
2763
               uint8_t* dst_u,
2764
               int dst_stride_u,
2765
               uint8_t* dst_v,
2766
               int dst_stride_v,
2767
               int width,
2768
0
               int height) {
2769
0
  return ARGBToI422Matrix(src_abgr, src_stride_abgr, dst_y, dst_stride_y, dst_u,
2770
0
                          dst_stride_u, dst_v, dst_stride_v,
2771
0
                          &kAbgrI601Constants, width, height);
2772
0
}
2773
2774
// Convert RGBA to I422.
2775
LIBYUV_API
2776
int RGBAToI422(const uint8_t* src_rgba,
2777
               int src_stride_rgba,
2778
               uint8_t* dst_y,
2779
               int dst_stride_y,
2780
               uint8_t* dst_u,
2781
               int dst_stride_u,
2782
               uint8_t* dst_v,
2783
               int dst_stride_v,
2784
               int width,
2785
0
               int height) {
2786
0
  return ARGBToI422Matrix(src_rgba, src_stride_rgba, dst_y, dst_stride_y, dst_u,
2787
0
                          dst_stride_u, dst_v, dst_stride_v,
2788
0
                          &kRgbaI601Constants, width, height);
2789
0
}
2790
2791
// Convert ABGR to I420.
2792
LIBYUV_API
2793
int ABGRToI420(const uint8_t* src_abgr,
2794
               int src_stride_abgr,
2795
               uint8_t* dst_y,
2796
               int dst_stride_y,
2797
               uint8_t* dst_u,
2798
               int dst_stride_u,
2799
               uint8_t* dst_v,
2800
               int dst_stride_v,
2801
               int width,
2802
0
               int height) {
2803
0
  return ARGBToI420Matrix(src_abgr, src_stride_abgr, dst_y, dst_stride_y, dst_u,
2804
0
                          dst_stride_u, dst_v, dst_stride_v,
2805
0
                          &kAbgrI601Constants, width, height);
2806
0
}
2807
2808
// Convert RGBA to I420.
2809
LIBYUV_API
2810
int RGBAToI420(const uint8_t* src_rgba,
2811
               int src_stride_rgba,
2812
               uint8_t* dst_y,
2813
               int dst_stride_y,
2814
               uint8_t* dst_u,
2815
               int dst_stride_u,
2816
               uint8_t* dst_v,
2817
               int dst_stride_v,
2818
               int width,
2819
0
               int height) {
2820
0
  return ARGBToI420Matrix(src_rgba, src_stride_rgba, dst_y, dst_stride_y, dst_u,
2821
0
                          dst_stride_u, dst_v, dst_stride_v,
2822
0
                          &kRgbaI601Constants, width, height);
2823
0
}
2824
2825
// Enabled if 1 pass is available
2826
#if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_LSX) || \
2827
     defined(HAS_RGB24TOYROW_RVV))
2828
#define HAS_RGB24TOYROW
2829
#endif
2830
2831
// Convert RGB24 to I420.
2832
LIBYUV_API
2833
int RGB24ToI420(const uint8_t* src_rgb24,
2834
                int src_stride_rgb24,
2835
                uint8_t* dst_y,
2836
                int dst_stride_y,
2837
                uint8_t* dst_u,
2838
                int dst_stride_u,
2839
                uint8_t* dst_v,
2840
                int dst_stride_v,
2841
                int width,
2842
0
                int height) {
2843
0
  int y;
2844
0
  void (*RGBToUVMatrixRow)(const uint8_t* src_rgb, int src_stride_rgb,
2845
0
                           uint8_t* dst_u, uint8_t* dst_v, int width,
2846
0
                           const struct ArgbConstants* c) = RGBToUVMatrixRow_C;
2847
0
  void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
2848
0
                          const struct ArgbConstants* c) = RGBToYMatrixRow_C;
2849
2850
0
#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
2851
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2852
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
2853
0
    if (IS_ALIGNED(width, 16)) {
2854
0
      RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
2855
0
    }
2856
0
  }
2857
0
#endif
2858
0
#if defined(HAS_RGBTOYMATRIXROW_AVX2)
2859
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2860
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
2861
0
    if (IS_ALIGNED(width, 32)) {
2862
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
2863
0
    }
2864
0
  }
2865
0
#endif
2866
0
#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
2867
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
2868
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
2869
0
    if (IS_ALIGNED(width, 64)) {
2870
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
2871
0
    }
2872
0
  }
2873
0
#endif
2874
0
#if defined(HAS_RGBTOUVMATRIXROW_SSSE3)
2875
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2876
0
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_SSSE3;
2877
0
    if (IS_ALIGNED(width, 16)) {
2878
0
      RGBToUVMatrixRow = RGBToUVMatrixRow_SSSE3;
2879
0
    }
2880
0
  }
2881
0
#endif
2882
0
#if defined(HAS_RGBTOUVMATRIXROW_AVX2)
2883
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2884
0
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX2;
2885
0
    if (IS_ALIGNED(width, 32)) {
2886
0
      RGBToUVMatrixRow = RGBToUVMatrixRow_AVX2;
2887
0
    }
2888
0
  }
2889
0
#endif
2890
0
#if defined(HAS_RGBTOUVMATRIXROW_AVX512BW)
2891
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
2892
0
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX512BW;
2893
0
    if (IS_ALIGNED(width, 64)) {
2894
0
      RGBToUVMatrixRow = RGBToUVMatrixRow_AVX512BW;
2895
0
    }
2896
0
  }
2897
0
#endif
2898
#if defined(HAS_RGBTOUVMATRIXROW_NEON)
2899
  if (TestCpuFlag(kCpuHasNEON)) {
2900
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_NEON;
2901
    if (IS_ALIGNED(width, 16)) {
2902
      RGBToUVMatrixRow = RGBToUVMatrixRow_NEON;
2903
    }
2904
  }
2905
#endif
2906
#if defined(HAS_RGBTOYMATRIXROW_NEON)
2907
  if (TestCpuFlag(kCpuHasNEON)) {
2908
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
2909
    if (IS_ALIGNED(width, 16)) {
2910
      RGBToYMatrixRow = RGBToYMatrixRow_NEON;
2911
    }
2912
  }
2913
#endif
2914
#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
2915
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
2916
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
2917
    if (IS_ALIGNED(width, 16)) {
2918
      RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
2919
    }
2920
  }
2921
#endif
2922
#if defined(HAS_RGBTOUVMATRIXROW_RVV)
2923
  if (TestCpuFlag(kCpuHasRVV)) {
2924
    RGBToUVMatrixRow = RGBToUVMatrixRow_RVV;
2925
  }
2926
#endif
2927
#if defined(HAS_RGBTOYMATRIXROW_RVV)
2928
  if (TestCpuFlag(kCpuHasRVV)) {
2929
    RGBToYMatrixRow = RGBToYMatrixRow_RVV;
2930
  }
2931
#endif
2932
2933
0
  if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0 ||
2934
0
      height == INT_MIN) {
2935
0
    return -1;
2936
0
  }
2937
  // Negative height means invert the image.
2938
0
  if (height < 0) {
2939
0
    height = -height;
2940
0
    src_rgb24 = src_rgb24 + (ptrdiff_t)(height - 1) * src_stride_rgb24;
2941
0
    src_stride_rgb24 = -src_stride_rgb24;
2942
0
  }
2943
2944
0
  for (y = 0; y < height - 1; y += 2) {
2945
0
    RGBToUVMatrixRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width,
2946
0
                     &kArgbI601Constants);
2947
0
    RGBToYMatrixRow(src_rgb24, dst_y, width, &kArgbI601Constants);
2948
0
    RGBToYMatrixRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width,
2949
0
                    &kArgbI601Constants);
2950
0
    src_rgb24 += src_stride_rgb24 * 2;
2951
0
    dst_y += dst_stride_y * 2;
2952
0
    dst_u += dst_stride_u;
2953
0
    dst_v += dst_stride_v;
2954
0
  }
2955
0
  if (height & 1) {
2956
0
    RGBToYMatrixRow(src_rgb24, dst_y, width, &kArgbI601Constants);
2957
0
    RGBToUVMatrixRow(src_rgb24, 0, dst_u, dst_v, width, &kArgbI601Constants);
2958
0
  }
2959
0
  return 0;
2960
0
}
2961
#undef HAS_RGB24TOYROW
2962
2963
/// Convert RGB24 to J420.
2964
LIBYUV_API
2965
int RGB24ToJ420(const uint8_t* src_rgb24,
2966
                int src_stride_rgb24,
2967
                uint8_t* dst_y,
2968
                int dst_stride_y,
2969
                uint8_t* dst_u,
2970
                int dst_stride_u,
2971
                uint8_t* dst_v,
2972
                int dst_stride_v,
2973
                int width,
2974
0
                int height) {
2975
0
  int y;
2976
0
  void (*RGBToUVMatrixRow)(const uint8_t* src_rgb, int src_stride_rgb,
2977
0
                           uint8_t* dst_u, uint8_t* dst_v, int width,
2978
0
                           const struct ArgbConstants* c) = RGBToUVMatrixRow_C;
2979
0
  void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
2980
0
                          const struct ArgbConstants* c) = RGBToYMatrixRow_C;
2981
2982
0
#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
2983
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
2984
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
2985
0
    if (IS_ALIGNED(width, 16)) {
2986
0
      RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
2987
0
    }
2988
0
  }
2989
0
#endif
2990
0
#if defined(HAS_RGBTOYMATRIXROW_AVX2)
2991
0
  if (TestCpuFlag(kCpuHasAVX2)) {
2992
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
2993
0
    if (IS_ALIGNED(width, 32)) {
2994
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
2995
0
    }
2996
0
  }
2997
0
#endif
2998
0
#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
2999
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
3000
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3001
0
    if (IS_ALIGNED(width, 64)) {
3002
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3003
0
    }
3004
0
  }
3005
0
#endif
3006
0
#if defined(HAS_RGBTOUVMATRIXROW_SSSE3)
3007
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3008
0
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_SSSE3;
3009
0
    if (IS_ALIGNED(width, 16)) {
3010
0
      RGBToUVMatrixRow = RGBToUVMatrixRow_SSSE3;
3011
0
    }
3012
0
  }
3013
0
#endif
3014
0
#if defined(HAS_RGBTOUVMATRIXROW_AVX2)
3015
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3016
0
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX2;
3017
0
    if (IS_ALIGNED(width, 32)) {
3018
0
      RGBToUVMatrixRow = RGBToUVMatrixRow_AVX2;
3019
0
    }
3020
0
  }
3021
0
#endif
3022
0
#if defined(HAS_RGBTOUVMATRIXROW_AVX512BW)
3023
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
3024
0
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX512BW;
3025
0
    if (IS_ALIGNED(width, 64)) {
3026
0
      RGBToUVMatrixRow = RGBToUVMatrixRow_AVX512BW;
3027
0
    }
3028
0
  }
3029
0
#endif
3030
#if defined(HAS_RGBTOUVMATRIXROW_NEON)
3031
  if (TestCpuFlag(kCpuHasNEON)) {
3032
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_NEON;
3033
    if (IS_ALIGNED(width, 16)) {
3034
      RGBToUVMatrixRow = RGBToUVMatrixRow_NEON;
3035
    }
3036
  }
3037
#endif
3038
#if defined(HAS_RGBTOYMATRIXROW_NEON)
3039
  if (TestCpuFlag(kCpuHasNEON)) {
3040
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3041
    if (IS_ALIGNED(width, 16)) {
3042
      RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3043
    }
3044
  }
3045
#endif
3046
#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3047
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
3048
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3049
    if (IS_ALIGNED(width, 16)) {
3050
      RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3051
    }
3052
  }
3053
#endif
3054
#if defined(HAS_RGBTOUVMATRIXROW_RVV)
3055
  if (TestCpuFlag(kCpuHasRVV)) {
3056
    RGBToUVMatrixRow = RGBToUVMatrixRow_RVV;
3057
  }
3058
#endif
3059
#if defined(HAS_RGBTOYMATRIXROW_RVV)
3060
  if (TestCpuFlag(kCpuHasRVV)) {
3061
    RGBToYMatrixRow = RGBToYMatrixRow_RVV;
3062
  }
3063
#endif
3064
3065
0
  if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0 ||
3066
0
      height == INT_MIN) {
3067
0
    return -1;
3068
0
  }
3069
  // Negative height means invert the image.
3070
0
  if (height < 0) {
3071
0
    height = -height;
3072
0
    src_rgb24 = src_rgb24 + (ptrdiff_t)(height - 1) * src_stride_rgb24;
3073
0
    src_stride_rgb24 = -src_stride_rgb24;
3074
0
  }
3075
3076
0
  for (y = 0; y < height - 1; y += 2) {
3077
0
    RGBToUVMatrixRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width,
3078
0
                     &kArgbJPEGConstants);
3079
0
    RGBToYMatrixRow(src_rgb24, dst_y, width, &kArgbJPEGConstants);
3080
0
    RGBToYMatrixRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width,
3081
0
                    &kArgbJPEGConstants);
3082
0
    src_rgb24 += src_stride_rgb24 * 2;
3083
0
    dst_y += dst_stride_y * 2;
3084
0
    dst_u += dst_stride_u;
3085
0
    dst_v += dst_stride_v;
3086
0
  }
3087
0
  if (height & 1) {
3088
0
    RGBToYMatrixRow(src_rgb24, dst_y, width, &kArgbJPEGConstants);
3089
0
    RGBToUVMatrixRow(src_rgb24, 0, dst_u, dst_v, width, &kArgbJPEGConstants);
3090
0
  }
3091
0
  return 0;
3092
0
}
3093
3094
// Enabled if 1 pass is available
3095
#if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_LSX) || \
3096
     defined(HAS_RAWTOYROW_RVV))
3097
#define HAS_RAWTOYROW
3098
#endif
3099
3100
// Convert RAW to I420.
3101
LIBYUV_API
3102
int RAWToI420(const uint8_t* src_raw,
3103
              int src_stride_raw,
3104
              uint8_t* dst_y,
3105
              int dst_stride_y,
3106
              uint8_t* dst_u,
3107
              int dst_stride_u,
3108
              uint8_t* dst_v,
3109
              int dst_stride_v,
3110
              int width,
3111
0
              int height) {
3112
0
  int y;
3113
0
  void (*RGBToUVMatrixRow)(const uint8_t* src_rgb, int src_stride_rgb,
3114
0
                           uint8_t* dst_u, uint8_t* dst_v, int width,
3115
0
                           const struct ArgbConstants* c) = RGBToUVMatrixRow_C;
3116
0
  void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
3117
0
                          const struct ArgbConstants* c) = RGBToYMatrixRow_C;
3118
3119
0
#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
3120
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3121
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
3122
0
    if (IS_ALIGNED(width, 16)) {
3123
0
      RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
3124
0
    }
3125
0
  }
3126
0
#endif
3127
0
#if defined(HAS_RGBTOYMATRIXROW_AVX2)
3128
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3129
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
3130
0
    if (IS_ALIGNED(width, 32)) {
3131
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
3132
0
    }
3133
0
  }
3134
0
#endif
3135
0
#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
3136
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
3137
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3138
0
    if (IS_ALIGNED(width, 64)) {
3139
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3140
0
    }
3141
0
  }
3142
0
#endif
3143
0
#if defined(HAS_RGBTOUVMATRIXROW_SSSE3)
3144
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3145
0
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_SSSE3;
3146
0
    if (IS_ALIGNED(width, 16)) {
3147
0
      RGBToUVMatrixRow = RGBToUVMatrixRow_SSSE3;
3148
0
    }
3149
0
  }
3150
0
#endif
3151
0
#if defined(HAS_RGBTOUVMATRIXROW_AVX2)
3152
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3153
0
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX2;
3154
0
    if (IS_ALIGNED(width, 32)) {
3155
0
      RGBToUVMatrixRow = RGBToUVMatrixRow_AVX2;
3156
0
    }
3157
0
  }
3158
0
#endif
3159
0
#if defined(HAS_RGBTOUVMATRIXROW_AVX512BW)
3160
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
3161
0
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX512BW;
3162
0
    if (IS_ALIGNED(width, 64)) {
3163
0
      RGBToUVMatrixRow = RGBToUVMatrixRow_AVX512BW;
3164
0
    }
3165
0
  }
3166
0
#endif
3167
#if defined(HAS_RGBTOUVMATRIXROW_NEON)
3168
  if (TestCpuFlag(kCpuHasNEON)) {
3169
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_NEON;
3170
    if (IS_ALIGNED(width, 16)) {
3171
      RGBToUVMatrixRow = RGBToUVMatrixRow_NEON;
3172
    }
3173
  }
3174
#endif
3175
#if defined(HAS_RGBTOYMATRIXROW_NEON)
3176
  if (TestCpuFlag(kCpuHasNEON)) {
3177
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3178
    if (IS_ALIGNED(width, 16)) {
3179
      RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3180
    }
3181
  }
3182
#endif
3183
#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3184
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
3185
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3186
    if (IS_ALIGNED(width, 16)) {
3187
      RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3188
    }
3189
  }
3190
#endif
3191
3192
0
  if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0 ||
3193
0
      height == INT_MIN) {
3194
0
    return -1;
3195
0
  }
3196
  // Negative height means invert the image.
3197
0
  if (height < 0) {
3198
0
    height = -height;
3199
0
    src_raw = src_raw + (ptrdiff_t)(height - 1) * src_stride_raw;
3200
0
    src_stride_raw = -src_stride_raw;
3201
0
  }
3202
3203
0
  for (y = 0; y < height - 1; y += 2) {
3204
0
    RGBToUVMatrixRow(src_raw, src_stride_raw, dst_u, dst_v, width,
3205
0
                     &kAbgrI601Constants);
3206
0
    RGBToYMatrixRow(src_raw, dst_y, width, &kAbgrI601Constants);
3207
0
    RGBToYMatrixRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width,
3208
0
                    &kAbgrI601Constants);
3209
0
    src_raw += src_stride_raw * 2;
3210
0
    dst_y += dst_stride_y * 2;
3211
0
    dst_u += dst_stride_u;
3212
0
    dst_v += dst_stride_v;
3213
0
  }
3214
0
  if (height & 1) {
3215
0
    RGBToYMatrixRow(src_raw, dst_y, width, &kAbgrI601Constants);
3216
0
    RGBToUVMatrixRow(src_raw, 0, dst_u, dst_v, width, &kAbgrI601Constants);
3217
0
  }
3218
0
  return 0;
3219
0
}
3220
#undef HAS_RAWTOYROW
3221
3222
// Convert RAW to J420.
3223
LIBYUV_API
3224
int RAWToJ420(const uint8_t* src_raw,
3225
              int src_stride_raw,
3226
              uint8_t* dst_y,
3227
              int dst_stride_y,
3228
              uint8_t* dst_u,
3229
              int dst_stride_u,
3230
              uint8_t* dst_v,
3231
              int dst_stride_v,
3232
              int width,
3233
96
              int height) {
3234
96
  int y;
3235
96
  void (*RGBToUVMatrixRow)(const uint8_t* src_rgb, int src_stride_rgb,
3236
96
                           uint8_t* dst_u, uint8_t* dst_v, int width,
3237
96
                           const struct ArgbConstants* c) = RGBToUVMatrixRow_C;
3238
96
  void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
3239
96
                          const struct ArgbConstants* c) = RGBToYMatrixRow_C;
3240
3241
96
#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
3242
96
  if (TestCpuFlag(kCpuHasSSSE3)) {
3243
96
    RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
3244
96
    if (IS_ALIGNED(width, 16)) {
3245
9
      RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
3246
9
    }
3247
96
  }
3248
96
#endif
3249
96
#if defined(HAS_RGBTOYMATRIXROW_AVX2)
3250
96
  if (TestCpuFlag(kCpuHasAVX2)) {
3251
96
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
3252
96
    if (IS_ALIGNED(width, 32)) {
3253
7
      RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
3254
7
    }
3255
96
  }
3256
96
#endif
3257
96
#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
3258
96
  if (TestCpuFlag(kCpuHasAVX512BW)) {
3259
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3260
0
    if (IS_ALIGNED(width, 64)) {
3261
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3262
0
    }
3263
0
  }
3264
96
#endif
3265
96
#if defined(HAS_RGBTOUVMATRIXROW_SSSE3)
3266
96
  if (TestCpuFlag(kCpuHasSSSE3)) {
3267
96
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_SSSE3;
3268
96
    if (IS_ALIGNED(width, 16)) {
3269
9
      RGBToUVMatrixRow = RGBToUVMatrixRow_SSSE3;
3270
9
    }
3271
96
  }
3272
96
#endif
3273
96
#if defined(HAS_RGBTOUVMATRIXROW_AVX2)
3274
96
  if (TestCpuFlag(kCpuHasAVX2)) {
3275
96
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX2;
3276
96
    if (IS_ALIGNED(width, 32)) {
3277
7
      RGBToUVMatrixRow = RGBToUVMatrixRow_AVX2;
3278
7
    }
3279
96
  }
3280
96
#endif
3281
96
#if defined(HAS_RGBTOUVMATRIXROW_AVX512BW)
3282
96
  if (TestCpuFlag(kCpuHasAVX512BW)) {
3283
0
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX512BW;
3284
0
    if (IS_ALIGNED(width, 64)) {
3285
0
      RGBToUVMatrixRow = RGBToUVMatrixRow_AVX512BW;
3286
0
    }
3287
0
  }
3288
96
#endif
3289
#if defined(HAS_RGBTOUVMATRIXROW_NEON)
3290
  if (TestCpuFlag(kCpuHasNEON)) {
3291
    RGBToUVMatrixRow = RGBToUVMatrixRow_Any_NEON;
3292
    if (IS_ALIGNED(width, 16)) {
3293
      RGBToUVMatrixRow = RGBToUVMatrixRow_NEON;
3294
    }
3295
  }
3296
#endif
3297
#if defined(HAS_RGBTOYMATRIXROW_NEON)
3298
  if (TestCpuFlag(kCpuHasNEON)) {
3299
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3300
    if (IS_ALIGNED(width, 16)) {
3301
      RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3302
    }
3303
  }
3304
#endif
3305
#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3306
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
3307
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3308
    if (IS_ALIGNED(width, 16)) {
3309
      RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3310
    }
3311
  }
3312
#endif
3313
3314
96
  if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0 ||
3315
96
      height == INT_MIN) {
3316
0
    return -1;
3317
0
  }
3318
  // Negative height means invert the image.
3319
96
  if (height < 0) {
3320
0
    height = -height;
3321
0
    src_raw = src_raw + (ptrdiff_t)(height - 1) * src_stride_raw;
3322
0
    src_stride_raw = -src_stride_raw;
3323
0
  }
3324
3325
495k
  for (y = 0; y < height - 1; y += 2) {
3326
495k
    RGBToUVMatrixRow(src_raw, src_stride_raw, dst_u, dst_v, width,
3327
495k
                     &kAbgrJPEGConstants);
3328
495k
    RGBToYMatrixRow(src_raw, dst_y, width, &kAbgrJPEGConstants);
3329
495k
    RGBToYMatrixRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width,
3330
495k
                    &kAbgrJPEGConstants);
3331
495k
    src_raw += src_stride_raw * 2;
3332
495k
    dst_y += dst_stride_y * 2;
3333
495k
    dst_u += dst_stride_u;
3334
495k
    dst_v += dst_stride_v;
3335
495k
  }
3336
96
  if (height & 1) {
3337
46
    RGBToYMatrixRow(src_raw, dst_y, width, &kAbgrJPEGConstants);
3338
46
    RGBToUVMatrixRow(src_raw, 0, dst_u, dst_v, width, &kAbgrJPEGConstants);
3339
46
  }
3340
96
  return 0;
3341
96
}
3342
3343
// Convert RAW to I444 with matrix.
3344
static int RAWToI444Matrix(const uint8_t* src_raw,
3345
                    int src_stride_raw,
3346
                    uint8_t* dst_y,
3347
                    int dst_stride_y,
3348
                    uint8_t* dst_u,
3349
                    int dst_stride_u,
3350
                    uint8_t* dst_v,
3351
                    int dst_stride_v,
3352
                    const struct ArgbConstants* argbconstants,
3353
                    int width,
3354
87
                    int height) {
3355
87
  int y;
3356
87
  void (*RGBToUV444MatrixRow)(const uint8_t* src_rgb, uint8_t* dst_u,
3357
87
                              uint8_t* dst_v, int width,
3358
87
                              const struct ArgbConstants* c) =
3359
87
      RGBToUV444MatrixRow_C;
3360
87
  void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
3361
87
                          const struct ArgbConstants* c) = RGBToYMatrixRow_C;
3362
3363
87
#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
3364
87
  if (TestCpuFlag(kCpuHasSSSE3)) {
3365
87
    RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
3366
87
    if (IS_ALIGNED(width, 16)) {
3367
3
      RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
3368
3
    }
3369
87
  }
3370
87
#endif
3371
87
#if defined(HAS_RGBTOYMATRIXROW_AVX2)
3372
87
  if (TestCpuFlag(kCpuHasAVX2)) {
3373
87
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
3374
87
    if (IS_ALIGNED(width, 32)) {
3375
2
      RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
3376
2
    }
3377
87
  }
3378
87
#endif
3379
87
#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
3380
87
  if (TestCpuFlag(kCpuHasAVX512BW)) {
3381
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3382
0
    if (IS_ALIGNED(width, 64)) {
3383
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3384
0
    }
3385
0
  }
3386
87
#endif
3387
#if defined(HAS_RGBTOYMATRIXROW_NEON)
3388
  if (TestCpuFlag(kCpuHasNEON)) {
3389
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3390
    if (IS_ALIGNED(width, 16)) {
3391
      RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3392
    }
3393
  }
3394
#endif
3395
#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3396
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
3397
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3398
    if (IS_ALIGNED(width, 16)) {
3399
      RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3400
    }
3401
  }
3402
#endif
3403
#if defined(HAS_RGBTOYMATRIXROW_LASX)
3404
  if (TestCpuFlag(kCpuHasLASX)) {
3405
    RGBToYMatrixRow = RGBToYMatrixRow_Any_LASX;
3406
    if (IS_ALIGNED(width, 32)) {
3407
      RGBToYMatrixRow = RGBToYMatrixRow_LASX;
3408
    }
3409
  }
3410
#endif
3411
#if defined(HAS_RGBTOYMATRIXROW_RVV)
3412
  if (TestCpuFlag(kCpuHasRVV)) {
3413
    RGBToYMatrixRow = RGBToYMatrixRow_RVV;
3414
  }
3415
#endif
3416
3417
87
#if defined(HAS_RGBTOUV444MATRIXROW_SSSE3)
3418
87
  if (TestCpuFlag(kCpuHasSSSE3)) {
3419
87
    RGBToUV444MatrixRow = RGBToUV444MatrixRow_Any_SSSE3;
3420
87
    if (IS_ALIGNED(width, 16)) {
3421
3
      RGBToUV444MatrixRow = RGBToUV444MatrixRow_SSSE3;
3422
3
    }
3423
87
  }
3424
87
#endif
3425
87
#if defined(HAS_RGBTOUV444MATRIXROW_AVX2)
3426
87
  if (TestCpuFlag(kCpuHasAVX2)) {
3427
87
    RGBToUV444MatrixRow = RGBToUV444MatrixRow_Any_AVX2;
3428
87
    if (IS_ALIGNED(width, 32)) {
3429
2
      RGBToUV444MatrixRow = RGBToUV444MatrixRow_AVX2;
3430
2
    }
3431
87
  }
3432
87
#endif
3433
87
#if defined(HAS_RGBTOUV444MATRIXROW_AVX512BW)
3434
87
  if (TestCpuFlag(kCpuHasAVX512BW)) {
3435
0
    RGBToUV444MatrixRow = RGBToUV444MatrixRow_Any_AVX512BW;
3436
0
    if (IS_ALIGNED(width, 64)) {
3437
0
      RGBToUV444MatrixRow = RGBToUV444MatrixRow_AVX512BW;
3438
0
    }
3439
0
  }
3440
87
#endif
3441
#if defined(HAS_RGBTOUV444MATRIXROW_NEON)
3442
  if (TestCpuFlag(kCpuHasNEON)) {
3443
    RGBToUV444MatrixRow = RGBToUV444MatrixRow_Any_NEON;
3444
    if (IS_ALIGNED(width, 8)) {
3445
      RGBToUV444MatrixRow = RGBToUV444MatrixRow_NEON;
3446
    }
3447
  }
3448
#endif
3449
#if defined(HAS_RGBTOUV444MATRIXROW_RVV)
3450
  if (TestCpuFlag(kCpuHasRVV)) {
3451
    RGBToUV444MatrixRow = RGBToUV444MatrixRow_RVV;
3452
  }
3453
#endif
3454
3455
87
  if (!src_raw || !dst_y || !dst_u || !dst_v || !argbconstants || width <= 0 ||
3456
87
      height == 0 || height == INT_MIN) {
3457
0
    return -1;
3458
0
  }
3459
87
  if (height < 0) {
3460
0
    height = -height;
3461
0
    src_raw = src_raw + (ptrdiff_t)(height - 1) * src_stride_raw;
3462
0
    src_stride_raw = -src_stride_raw;
3463
0
  }
3464
3465
981k
  for (y = 0; y < height; ++y) {
3466
981k
    RGBToYMatrixRow(src_raw, dst_y, width, argbconstants);
3467
981k
    RGBToUV444MatrixRow(src_raw, dst_u, dst_v, width, argbconstants);
3468
981k
    src_raw += src_stride_raw;
3469
981k
    dst_y += dst_stride_y;
3470
981k
    dst_u += dst_stride_u;
3471
981k
    dst_v += dst_stride_v;
3472
981k
  }
3473
87
  return 0;
3474
87
}
3475
3476
// Convert RAW to I444.
3477
LIBYUV_API
3478
int RAWToI444(const uint8_t* src_raw,
3479
              int src_stride_raw,
3480
              uint8_t* dst_y,
3481
              int dst_stride_y,
3482
              uint8_t* dst_u,
3483
              int dst_stride_u,
3484
              uint8_t* dst_v,
3485
              int dst_stride_v,
3486
              int width,
3487
0
              int height) {
3488
0
  return RAWToI444Matrix(src_raw, src_stride_raw, dst_y, dst_stride_y, dst_u,
3489
0
                         dst_stride_u, dst_v, dst_stride_v,
3490
0
                         &kAbgrI601Constants, width, height);
3491
0
}
3492
3493
// Convert RAW to J444.
3494
LIBYUV_API
3495
int RAWToJ444(const uint8_t* src_raw,
3496
              int src_stride_raw,
3497
              uint8_t* dst_y,
3498
              int dst_stride_y,
3499
              uint8_t* dst_u,
3500
              int dst_stride_u,
3501
              uint8_t* dst_v,
3502
              int dst_stride_v,
3503
              int width,
3504
87
              int height) {
3505
87
  return RAWToI444Matrix(src_raw, src_stride_raw, dst_y, dst_stride_y, dst_u,
3506
87
                         dst_stride_u, dst_v, dst_stride_v,
3507
87
                          &kAbgrJPEGConstants, width, height);
3508
87
}
3509
3510
// Convert RGB565 to I420.
3511
LIBYUV_API
3512
int RGB565ToI420(const uint8_t* src_rgb565,
3513
                 int src_stride_rgb565,
3514
                 uint8_t* dst_y,
3515
                 int dst_stride_y,
3516
                 uint8_t* dst_u,
3517
                 int dst_stride_u,
3518
                 uint8_t* dst_v,
3519
                 int dst_stride_v,
3520
                 int width,
3521
0
                 int height) {
3522
0
  int y;
3523
0
  void (*RGB565ToUVMatrixRow)(const uint8_t* src_rgb565, int src_stride_rgb565,
3524
0
                              uint8_t* dst_u, uint8_t* dst_v, int width,
3525
0
                              const struct ArgbConstants* c) =
3526
0
      RGB565ToUVMatrixRow_C;
3527
0
  void (*RGB565ToYMatrixRow)(const uint8_t* src_rgb565, uint8_t* dst_y,
3528
0
                             int width, const struct ArgbConstants* c) =
3529
0
      RGB565ToYMatrixRow_C;
3530
3531
0
#if defined(HAS_RGB565TOYMATRIXROW_AVX2)
3532
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3533
0
    RGB565ToYMatrixRow = RGB565ToYMatrixRow_Any_AVX2;
3534
0
    if (IS_ALIGNED(width, 32)) {
3535
0
      RGB565ToYMatrixRow = RGB565ToYMatrixRow_AVX2;
3536
0
    }
3537
0
  }
3538
0
#endif
3539
0
#if defined(HAS_RGB565TOUVMATRIXROW_AVX2)
3540
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3541
0
    RGB565ToUVMatrixRow = RGB565ToUVMatrixRow_Any_AVX2;
3542
0
    if (IS_ALIGNED(width, 16)) {
3543
0
      RGB565ToUVMatrixRow = RGB565ToUVMatrixRow_AVX2;
3544
0
    }
3545
0
  }
3546
0
#endif
3547
#if defined(HAS_RGB565TOUVMATRIXROW_NEON)
3548
  if (TestCpuFlag(kCpuHasNEON)) {
3549
    RGB565ToUVMatrixRow = RGB565ToUVMatrixRow_Any_NEON;
3550
    if (IS_ALIGNED(width, 16)) {
3551
      RGB565ToUVMatrixRow = RGB565ToUVMatrixRow_NEON;
3552
    }
3553
  }
3554
#endif
3555
#if defined(HAS_RGB565TOYMATRIXROW_NEON)
3556
  if (TestCpuFlag(kCpuHasNEON)) {
3557
    RGB565ToYMatrixRow = RGB565ToYMatrixRow_Any_NEON;
3558
    if (IS_ALIGNED(width, 16)) {
3559
      RGB565ToYMatrixRow = RGB565ToYMatrixRow_NEON;
3560
    }
3561
  }
3562
#endif
3563
3564
0
  if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0 ||
3565
0
      height == INT_MIN) {
3566
0
    return -1;
3567
0
  }
3568
  // Negative height means invert the image.
3569
0
  if (height < 0) {
3570
0
    height = -height;
3571
0
    src_rgb565 = src_rgb565 + (ptrdiff_t)(height - 1) * src_stride_rgb565;
3572
0
    src_stride_rgb565 = -src_stride_rgb565;
3573
0
  }
3574
3575
0
  for (y = 0; y < height - 1; y += 2) {
3576
0
    RGB565ToUVMatrixRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width,
3577
0
                        &kArgbI601Constants);
3578
0
    RGB565ToYMatrixRow(src_rgb565, dst_y, width, &kArgbI601Constants);
3579
0
    RGB565ToYMatrixRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y,
3580
0
                       width, &kArgbI601Constants);
3581
0
    src_rgb565 += src_stride_rgb565 * 2;
3582
0
    dst_y += dst_stride_y * 2;
3583
0
    dst_u += dst_stride_u;
3584
0
    dst_v += dst_stride_v;
3585
0
  }
3586
0
  if (height & 1) {
3587
0
    RGB565ToYMatrixRow(src_rgb565, dst_y, width, &kArgbI601Constants);
3588
0
    RGB565ToUVMatrixRow(src_rgb565, 0, dst_u, dst_v, width,
3589
0
                        &kArgbI601Constants);
3590
0
  }
3591
0
  return 0;
3592
0
}
3593
// Convert ARGB1555 to I420.
3594
LIBYUV_API
3595
int ARGB1555ToI420(const uint8_t* src_argb1555,
3596
                   int src_stride_argb1555,
3597
                   uint8_t* dst_y,
3598
                   int dst_stride_y,
3599
                   uint8_t* dst_u,
3600
                   int dst_stride_u,
3601
                   uint8_t* dst_v,
3602
                   int dst_stride_v,
3603
                   int width,
3604
0
                   int height) {
3605
0
  int y;
3606
0
  void (*ARGB1555ToUVMatrixRow)(
3607
0
      const uint8_t* src_argb1555, int src_stride_argb1555, uint8_t* dst_u,
3608
0
      uint8_t* dst_v, int width, const struct ArgbConstants* c) =
3609
0
      ARGB1555ToUVMatrixRow_C;
3610
0
  void (*ARGB1555ToYMatrixRow)(const uint8_t* src_argb1555, uint8_t* dst_y,
3611
0
                               int width, const struct ArgbConstants* c) =
3612
0
      ARGB1555ToYMatrixRow_C;
3613
3614
0
#if defined(HAS_ARGB1555TOYMATRIXROW_AVX2)
3615
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3616
0
    ARGB1555ToYMatrixRow = ARGB1555ToYMatrixRow_Any_AVX2;
3617
0
    if (IS_ALIGNED(width, 32)) {
3618
0
      ARGB1555ToYMatrixRow = ARGB1555ToYMatrixRow_AVX2;
3619
0
    }
3620
0
  }
3621
0
#endif
3622
0
#if defined(HAS_ARGB1555TOUVMATRIXROW_AVX2)
3623
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3624
0
    ARGB1555ToUVMatrixRow = ARGB1555ToUVMatrixRow_Any_AVX2;
3625
0
    if (IS_ALIGNED(width, 16)) {
3626
0
      ARGB1555ToUVMatrixRow = ARGB1555ToUVMatrixRow_AVX2;
3627
0
    }
3628
0
  }
3629
0
#endif
3630
#if defined(HAS_ARGB1555TOUVMATRIXROW_NEON)
3631
  if (TestCpuFlag(kCpuHasNEON)) {
3632
    ARGB1555ToUVMatrixRow = ARGB1555ToUVMatrixRow_Any_NEON;
3633
    if (IS_ALIGNED(width, 16)) {
3634
      ARGB1555ToUVMatrixRow = ARGB1555ToUVMatrixRow_NEON;
3635
    }
3636
  }
3637
#endif
3638
#if defined(HAS_ARGB1555TOYMATRIXROW_NEON)
3639
  if (TestCpuFlag(kCpuHasNEON)) {
3640
    ARGB1555ToYMatrixRow = ARGB1555ToYMatrixRow_Any_NEON;
3641
    if (IS_ALIGNED(width, 16)) {
3642
      ARGB1555ToYMatrixRow = ARGB1555ToYMatrixRow_NEON;
3643
    }
3644
  }
3645
#endif
3646
3647
0
  if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
3648
0
      height == 0 || height == INT_MIN) {
3649
0
    return -1;
3650
0
  }
3651
  // Negative height means invert the image.
3652
0
  if (height < 0) {
3653
0
    height = -height;
3654
0
    src_argb1555 = src_argb1555 + (ptrdiff_t)(height - 1) * src_stride_argb1555;
3655
0
    src_stride_argb1555 = -src_stride_argb1555;
3656
0
  }
3657
3658
0
  for (y = 0; y < height - 1; y += 2) {
3659
0
    ARGB1555ToUVMatrixRow(src_argb1555, src_stride_argb1555, dst_u, dst_v,
3660
0
                          width, &kArgbI601Constants);
3661
0
    ARGB1555ToYMatrixRow(src_argb1555, dst_y, width, &kArgbI601Constants);
3662
0
    ARGB1555ToYMatrixRow(src_argb1555 + src_stride_argb1555,
3663
0
                         dst_y + dst_stride_y, width, &kArgbI601Constants);
3664
0
    src_argb1555 += src_stride_argb1555 * 2;
3665
0
    dst_y += dst_stride_y * 2;
3666
0
    dst_u += dst_stride_u;
3667
0
    dst_v += dst_stride_v;
3668
0
  }
3669
0
  if (height & 1) {
3670
0
    ARGB1555ToYMatrixRow(src_argb1555, dst_y, width, &kArgbI601Constants);
3671
0
    ARGB1555ToUVMatrixRow(src_argb1555, 0, dst_u, dst_v, width,
3672
0
                          &kArgbI601Constants);
3673
0
  }
3674
0
  return 0;
3675
0
}
3676
// Convert ARGB4444 to I420.
3677
LIBYUV_API
3678
int ARGB4444ToI420(const uint8_t* src_argb4444,
3679
                   int src_stride_argb4444,
3680
                   uint8_t* dst_y,
3681
                   int dst_stride_y,
3682
                   uint8_t* dst_u,
3683
                   int dst_stride_u,
3684
                   uint8_t* dst_v,
3685
                   int dst_stride_v,
3686
                   int width,
3687
0
                   int height) {
3688
0
  int y;
3689
0
  void (*ARGB4444ToUVMatrixRow)(
3690
0
      const uint8_t* src_argb4444, int src_stride_argb4444, uint8_t* dst_u,
3691
0
      uint8_t* dst_v, int width, const struct ArgbConstants* c) =
3692
0
      ARGB4444ToUVMatrixRow_C;
3693
0
  void (*ARGB4444ToYMatrixRow)(const uint8_t* src_argb4444, uint8_t* dst_y,
3694
0
                               int width, const struct ArgbConstants* c) =
3695
0
      ARGB4444ToYMatrixRow_C;
3696
3697
0
#if defined(HAS_ARGB4444TOYMATRIXROW_AVX2)
3698
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3699
0
    ARGB4444ToYMatrixRow = ARGB4444ToYMatrixRow_Any_AVX2;
3700
0
    if (IS_ALIGNED(width, 32)) {
3701
0
      ARGB4444ToYMatrixRow = ARGB4444ToYMatrixRow_AVX2;
3702
0
    }
3703
0
  }
3704
0
#endif
3705
0
#if defined(HAS_ARGB4444TOUVMATRIXROW_AVX2)
3706
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3707
0
    ARGB4444ToUVMatrixRow = ARGB4444ToUVMatrixRow_Any_AVX2;
3708
0
    if (IS_ALIGNED(width, 16)) {
3709
0
      ARGB4444ToUVMatrixRow = ARGB4444ToUVMatrixRow_AVX2;
3710
0
    }
3711
0
  }
3712
0
#endif
3713
#if defined(HAS_ARGB4444TOUVMATRIXROW_NEON)
3714
  if (TestCpuFlag(kCpuHasNEON)) {
3715
    ARGB4444ToUVMatrixRow = ARGB4444ToUVMatrixRow_Any_NEON;
3716
    if (IS_ALIGNED(width, 16)) {
3717
      ARGB4444ToUVMatrixRow = ARGB4444ToUVMatrixRow_NEON;
3718
    }
3719
  }
3720
#endif
3721
#if defined(HAS_ARGB4444TOYMATRIXROW_NEON)
3722
  if (TestCpuFlag(kCpuHasNEON)) {
3723
    ARGB4444ToYMatrixRow = ARGB4444ToYMatrixRow_Any_NEON;
3724
    if (IS_ALIGNED(width, 16)) {
3725
      ARGB4444ToYMatrixRow = ARGB4444ToYMatrixRow_NEON;
3726
    }
3727
  }
3728
#endif
3729
3730
0
  if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
3731
0
      height == 0 || height == INT_MIN) {
3732
0
    return -1;
3733
0
  }
3734
  // Negative height means invert the image.
3735
0
  if (height < 0) {
3736
0
    height = -height;
3737
0
    src_argb4444 = src_argb4444 + (ptrdiff_t)(height - 1) * src_stride_argb4444;
3738
0
    src_stride_argb4444 = -src_stride_argb4444;
3739
0
  }
3740
3741
0
  for (y = 0; y < height - 1; y += 2) {
3742
0
    ARGB4444ToUVMatrixRow(src_argb4444, src_stride_argb4444, dst_u, dst_v,
3743
0
                          width, &kArgbI601Constants);
3744
0
    ARGB4444ToYMatrixRow(src_argb4444, dst_y, width, &kArgbI601Constants);
3745
0
    ARGB4444ToYMatrixRow(src_argb4444 + src_stride_argb4444,
3746
0
                         dst_y + dst_stride_y, width, &kArgbI601Constants);
3747
0
    src_argb4444 += src_stride_argb4444 * 2;
3748
0
    dst_y += dst_stride_y * 2;
3749
0
    dst_u += dst_stride_u;
3750
0
    dst_v += dst_stride_v;
3751
0
  }
3752
0
  if (height & 1) {
3753
0
    ARGB4444ToYMatrixRow(src_argb4444, dst_y, width, &kArgbI601Constants);
3754
0
    ARGB4444ToUVMatrixRow(src_argb4444, 0, dst_u, dst_v, width,
3755
0
                          &kArgbI601Constants);
3756
0
  }
3757
0
  return 0;
3758
0
}
3759
// Convert RGB24 to J400.
3760
LIBYUV_API
3761
int RGB24ToJ400(const uint8_t* src_rgb24,
3762
                int src_stride_rgb24,
3763
                uint8_t* dst_yj,
3764
                int dst_stride_yj,
3765
                int width,
3766
0
                int height) {
3767
0
  int y;
3768
0
  void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
3769
0
                          const struct ArgbConstants* c) = RGBToYMatrixRow_C;
3770
0
  if (!src_rgb24 || !dst_yj || width <= 0 || height == 0 || height == INT_MIN) {
3771
0
    return -1;
3772
0
  }
3773
0
  if (height < 0) {
3774
0
    height = -height;
3775
0
    src_rgb24 = src_rgb24 + (ptrdiff_t)(height - 1) * src_stride_rgb24;
3776
0
    src_stride_rgb24 = -src_stride_rgb24;
3777
0
  }
3778
  // Coalesce rows.
3779
0
  if (src_stride_rgb24 == width * 3 && dst_stride_yj == width &&
3780
0
      (ptrdiff_t)width * height <= INT_MAX) {
3781
0
    width *= height;
3782
0
    height = 1;
3783
0
    src_stride_rgb24 = dst_stride_yj = 0;
3784
0
  }
3785
3786
0
#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
3787
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
3788
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
3789
0
    if (IS_ALIGNED(width, 16)) {
3790
0
      RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
3791
0
    }
3792
0
  }
3793
0
#endif
3794
0
#if defined(HAS_RGBTOYMATRIXROW_AVX2)
3795
0
  if (TestCpuFlag(kCpuHasAVX2)) {
3796
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
3797
0
    if (IS_ALIGNED(width, 32)) {
3798
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
3799
0
    }
3800
0
  }
3801
0
#endif
3802
0
#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
3803
0
  if (TestCpuFlag(kCpuHasAVX512BW)) {
3804
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3805
0
    if (IS_ALIGNED(width, 64)) {
3806
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3807
0
    }
3808
0
  }
3809
0
#endif
3810
#if defined(HAS_RGBTOYMATRIXROW_NEON)
3811
  if (TestCpuFlag(kCpuHasNEON)) {
3812
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3813
    if (IS_ALIGNED(width, 16)) {
3814
      RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3815
    }
3816
  }
3817
#endif
3818
#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3819
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
3820
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3821
    if (IS_ALIGNED(width, 16)) {
3822
      RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3823
    }
3824
  }
3825
#endif
3826
#if defined(HAS_RGBTOYMATRIXROW_LASX)
3827
  if (TestCpuFlag(kCpuHasLASX)) {
3828
    RGBToYMatrixRow = RGBToYMatrixRow_Any_LASX;
3829
    if (IS_ALIGNED(width, 32)) {
3830
      RGBToYMatrixRow = RGBToYMatrixRow_LASX;
3831
    }
3832
  }
3833
#endif
3834
#if defined(HAS_RGBTOYMATRIXROW_RVV)
3835
  if (TestCpuFlag(kCpuHasRVV)) {
3836
    RGBToYMatrixRow = RGBToYMatrixRow_RVV;
3837
  }
3838
#endif
3839
3840
0
  for (y = 0; y < height; ++y) {
3841
0
    RGBToYMatrixRow(src_rgb24, dst_yj, width, &kArgbJPEGConstants);
3842
0
    src_rgb24 += src_stride_rgb24;
3843
0
    dst_yj += dst_stride_yj;
3844
0
  }
3845
0
  return 0;
3846
0
}
3847
3848
// Convert RAW to J400.
3849
LIBYUV_API
3850
int RAWToJ400(const uint8_t* src_raw,
3851
              int src_stride_raw,
3852
              uint8_t* dst_yj,
3853
              int dst_stride_yj,
3854
              int width,
3855
44
              int height) {
3856
44
  int y;
3857
44
  void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
3858
44
                          const struct ArgbConstants* c) = RGBToYMatrixRow_C;
3859
44
  if (!src_raw || !dst_yj || width <= 0 || height == 0 || height == INT_MIN) {
3860
0
    return -1;
3861
0
  }
3862
44
  if (height < 0) {
3863
0
    height = -height;
3864
0
    src_raw = src_raw + (ptrdiff_t)(height - 1) * src_stride_raw;
3865
0
    src_stride_raw = -src_stride_raw;
3866
0
  }
3867
  // Coalesce rows.
3868
44
  if (src_stride_raw == width * 3 && dst_stride_yj == width &&
3869
44
      (ptrdiff_t)width * height <= INT_MAX) {
3870
44
    width *= height;
3871
44
    height = 1;
3872
44
    src_stride_raw = dst_stride_yj = 0;
3873
44
  }
3874
3875
44
#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
3876
44
  if (TestCpuFlag(kCpuHasSSSE3)) {
3877
44
    RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
3878
44
    if (IS_ALIGNED(width, 16)) {
3879
10
      RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
3880
10
    }
3881
44
  }
3882
44
#endif
3883
44
#if defined(HAS_RGBTOYMATRIXROW_AVX2)
3884
44
  if (TestCpuFlag(kCpuHasAVX2)) {
3885
44
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
3886
44
    if (IS_ALIGNED(width, 32)) {
3887
5
      RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
3888
5
    }
3889
44
  }
3890
44
#endif
3891
44
#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
3892
44
  if (TestCpuFlag(kCpuHasAVX512BW)) {
3893
0
    RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3894
0
    if (IS_ALIGNED(width, 64)) {
3895
0
      RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3896
0
    }
3897
0
  }
3898
44
#endif
3899
#if defined(HAS_RGBTOYMATRIXROW_NEON)
3900
  if (TestCpuFlag(kCpuHasNEON)) {
3901
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3902
    if (IS_ALIGNED(width, 16)) {
3903
      RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3904
    }
3905
  }
3906
#endif
3907
#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3908
  if (TestCpuFlag(kCpuHasNeonDotProd)) {
3909
    RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3910
    if (IS_ALIGNED(width, 16)) {
3911
      RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3912
    }
3913
  }
3914
#endif
3915
#if defined(HAS_RGBTOYMATRIXROW_LASX)
3916
  if (TestCpuFlag(kCpuHasLASX)) {
3917
    RGBToYMatrixRow = RGBToYMatrixRow_Any_LASX;
3918
    if (IS_ALIGNED(width, 32)) {
3919
      RGBToYMatrixRow = RGBToYMatrixRow_LASX;
3920
    }
3921
  }
3922
#endif
3923
#if defined(HAS_RGBTOYMATRIXROW_RVV)
3924
  if (TestCpuFlag(kCpuHasRVV)) {
3925
    RGBToYMatrixRow = RGBToYMatrixRow_RVV;
3926
  }
3927
#endif
3928
3929
88
  for (y = 0; y < height; ++y) {
3930
44
    RGBToYMatrixRow(src_raw, dst_yj, width, &kAbgrJPEGConstants);
3931
44
    src_raw += src_stride_raw;
3932
44
    dst_yj += dst_stride_yj;
3933
44
  }
3934
44
  return 0;
3935
44
}
3936
3937
// Convert Android420 to I420.
3938
LIBYUV_API
3939
int Android420ToI420(const uint8_t* src_y,
3940
                     int src_stride_y,
3941
                     const uint8_t* src_u,
3942
                     int src_stride_u,
3943
                     const uint8_t* src_v,
3944
                     int src_stride_v,
3945
                     int src_pixel_stride_uv,
3946
                     uint8_t* dst_y,
3947
                     int dst_stride_y,
3948
                     uint8_t* dst_u,
3949
                     int dst_stride_u,
3950
                     uint8_t* dst_v,
3951
                     int dst_stride_v,
3952
                     int width,
3953
0
                     int height) {
3954
0
  return Android420ToI420Rotate(src_y, src_stride_y, src_u, src_stride_u, src_v,
3955
0
                                src_stride_v, src_pixel_stride_uv, dst_y,
3956
0
                                dst_stride_y, dst_u, dst_stride_u, dst_v,
3957
0
                                dst_stride_v, width, height, kRotate0);
3958
0
}
3959
3960
// depth is source bits measured from lsb; For msb use 16
3961
static int Biplanar16bitTo8bit(const uint16_t* src_y,
3962
                               int src_stride_y,
3963
                               const uint16_t* src_uv,
3964
                               int src_stride_uv,
3965
                               uint8_t* dst_y,
3966
                               int dst_stride_y,
3967
                               uint8_t* dst_uv,
3968
                               int dst_stride_uv,
3969
                               int width,
3970
                               int height,
3971
                               int subsample_x,
3972
                               int subsample_y,
3973
0
                               int depth) {
3974
0
  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0 ||
3975
0
      height == INT_MIN) {
3976
0
    return -1;
3977
0
  }
3978
0
  int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
3979
0
  int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
3980
0
  int scale = 1 << (24 - depth);
3981
  // Negative height means invert the image.
3982
0
  if (height < 0) {
3983
0
    height = -height;
3984
0
    uv_height = -uv_height;
3985
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
3986
0
    src_uv = src_uv + (ptrdiff_t)(uv_height - 1) * src_stride_uv;
3987
0
    src_stride_y = -src_stride_y;
3988
0
    src_stride_uv = -src_stride_uv;
3989
0
  }
3990
3991
  // Convert Y plane.
3992
0
  if (dst_y) {
3993
0
    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
3994
0
                      height);
3995
0
  }
3996
  // Convert UV planes.
3997
0
  Convert16To8Plane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, scale,
3998
0
                    uv_width * 2, uv_height);
3999
0
  return 0;
4000
0
}
4001
4002
// Convert 10 bit P010 to 8 bit NV12.
4003
// Depth set to 16 because P010 uses 10 msb and this function keeps the upper 8
4004
// bits of the specified number of bits.
4005
LIBYUV_API
4006
int P010ToNV12(const uint16_t* src_y,
4007
               int src_stride_y,
4008
               const uint16_t* src_uv,
4009
               int src_stride_uv,
4010
               uint8_t* dst_y,
4011
               int dst_stride_y,
4012
               uint8_t* dst_uv,
4013
               int dst_stride_uv,
4014
               int width,
4015
0
               int height) {
4016
0
  return Biplanar16bitTo8bit(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
4017
0
                             dst_stride_y, dst_uv, dst_stride_uv, width, height,
4018
0
                             1, 1, 16);
4019
0
}
4020
4021
static int Planar8bitTo8bit(const uint8_t* src_y,
4022
                            int src_stride_y,
4023
                            const uint8_t* src_u,
4024
                            int src_stride_u,
4025
                            const uint8_t* src_v,
4026
                            int src_stride_v,
4027
                            uint8_t* dst_y,
4028
                            int dst_stride_y,
4029
                            uint8_t* dst_u,
4030
                            int dst_stride_u,
4031
                            uint8_t* dst_v,
4032
                            int dst_stride_v,
4033
                            int width,
4034
                            int height,
4035
                            int subsample_x,
4036
                            int subsample_y,
4037
                            int scale_y,
4038
                            int bias_y,
4039
                            int scale_uv,
4040
0
                            int bias_uv) {
4041
0
  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
4042
0
      height == 0 || height == INT_MIN) {
4043
0
    return -1;
4044
0
  }
4045
0
  int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
4046
0
  int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
4047
  // Negative height means invert the image.
4048
0
  if (height < 0) {
4049
0
    height = -height;
4050
0
    uv_height = -uv_height;
4051
0
    src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
4052
0
    src_u = src_u + (ptrdiff_t)(uv_height - 1) * src_stride_u;
4053
0
    src_v = src_v + (ptrdiff_t)(uv_height - 1) * src_stride_v;
4054
0
    src_stride_y = -src_stride_y;
4055
0
    src_stride_u = -src_stride_u;
4056
0
    src_stride_v = -src_stride_v;
4057
0
  }
4058
4059
  // Convert Y plane.
4060
0
  if (dst_y) {
4061
0
    Convert8To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale_y, bias_y,
4062
0
                     width, height);
4063
0
  }
4064
  // Convert UV planes.
4065
0
  Convert8To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, scale_uv, bias_uv,
4066
0
                   uv_width, uv_height);
4067
0
  Convert8To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, scale_uv, bias_uv,
4068
0
                   uv_width, uv_height);
4069
0
  return 0;
4070
0
}
4071
4072
LIBYUV_API
4073
int J420ToI420(const uint8_t* src_y,
4074
               int src_stride_y,
4075
               const uint8_t* src_u,
4076
               int src_stride_u,
4077
               const uint8_t* src_v,
4078
               int src_stride_v,
4079
               uint8_t* dst_y,
4080
               int dst_stride_y,
4081
               uint8_t* dst_u,
4082
               int dst_stride_u,
4083
               uint8_t* dst_v,
4084
               int dst_stride_v,
4085
               int width,
4086
0
               int height) {
4087
0
  return Planar8bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
4088
0
                          src_stride_v, dst_y, dst_stride_y, dst_u,
4089
0
                          dst_stride_u, dst_v, dst_stride_v, width, height, 1,
4090
0
                          1, 220, 16, 225, 16);
4091
0
}
4092
4093
#ifdef __cplusplus
4094
}  // extern "C"
4095
}  // namespace libyuv
4096
#endif