Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/media/libyuv/libyuv/source/convert_from.cc
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright 2012 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_from.h"
12
13
#include "libyuv/basic_types.h"
14
#include "libyuv/convert.h"  // For I420Copy
15
#include "libyuv/cpu_id.h"
16
#include "libyuv/planar_functions.h"
17
#include "libyuv/rotate.h"
18
#include "libyuv/row.h"
19
#include "libyuv/scale.h"  // For ScalePlane()
20
#include "libyuv/video_common.h"
21
22
#ifdef __cplusplus
23
namespace libyuv {
24
extern "C" {
25
#endif
26
27
0
#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
28
0
static __inline int Abs(int v) {
29
0
  return v >= 0 ? v : -v;
30
0
}
31
32
// I420 To any I4xx YUV format with mirroring.
33
static int I420ToI4xx(const uint8_t* src_y,
34
                      int src_stride_y,
35
                      const uint8_t* src_u,
36
                      int src_stride_u,
37
                      const uint8_t* src_v,
38
                      int src_stride_v,
39
                      uint8_t* dst_y,
40
                      int dst_stride_y,
41
                      uint8_t* dst_u,
42
                      int dst_stride_u,
43
                      uint8_t* dst_v,
44
                      int dst_stride_v,
45
                      int src_y_width,
46
                      int src_y_height,
47
                      int dst_uv_width,
48
0
                      int dst_uv_height) {
49
0
  const int dst_y_width = Abs(src_y_width);
50
0
  const int dst_y_height = Abs(src_y_height);
51
0
  const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
52
0
  const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
53
0
  if (src_y_width == 0 || src_y_height == 0 || dst_uv_width <= 0 ||
54
0
      dst_uv_height <= 0) {
55
0
    return -1;
56
0
  }
57
0
  if (dst_y) {
58
0
    ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
59
0
               dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
60
0
  }
61
0
  ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
62
0
             dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
63
0
  ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
64
0
             dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
65
0
  return 0;
66
0
}
67
68
// Convert 8 bit YUV to 10 bit.
69
LIBYUV_API
70
int I420ToI010(const uint8_t* src_y,
71
               int src_stride_y,
72
               const uint8_t* src_u,
73
               int src_stride_u,
74
               const uint8_t* src_v,
75
               int src_stride_v,
76
               uint16_t* dst_y,
77
               int dst_stride_y,
78
               uint16_t* dst_u,
79
               int dst_stride_u,
80
               uint16_t* dst_v,
81
               int dst_stride_v,
82
               int width,
83
0
               int height) {
84
0
  int halfwidth = (width + 1) >> 1;
85
0
  int halfheight = (height + 1) >> 1;
86
0
  if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
87
0
    return -1;
88
0
  }
89
0
  // Negative height means invert the image.
90
0
  if (height < 0) {
91
0
    height = -height;
92
0
    halfheight = (height + 1) >> 1;
93
0
    src_y = src_y + (height - 1) * src_stride_y;
94
0
    src_u = src_u + (halfheight - 1) * src_stride_u;
95
0
    src_v = src_v + (halfheight - 1) * src_stride_v;
96
0
    src_stride_y = -src_stride_y;
97
0
    src_stride_u = -src_stride_u;
98
0
    src_stride_v = -src_stride_v;
99
0
  }
100
0
101
0
  // Convert Y plane.
102
0
  Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width,
103
0
                    height);
104
0
  // Convert UV planes.
105
0
  Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth,
106
0
                    halfheight);
107
0
  Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth,
108
0
                    halfheight);
109
0
  return 0;
110
0
}
111
112
// 420 chroma is 1/2 width, 1/2 height
113
// 422 chroma is 1/2 width, 1x height
114
LIBYUV_API
115
int I420ToI422(const uint8_t* src_y,
116
               int src_stride_y,
117
               const uint8_t* src_u,
118
               int src_stride_u,
119
               const uint8_t* src_v,
120
               int src_stride_v,
121
               uint8_t* dst_y,
122
               int dst_stride_y,
123
               uint8_t* dst_u,
124
               int dst_stride_u,
125
               uint8_t* dst_v,
126
               int dst_stride_v,
127
               int width,
128
0
               int height) {
129
0
  const int dst_uv_width = (Abs(width) + 1) >> 1;
130
0
  const int dst_uv_height = Abs(height);
131
0
  return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
132
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
133
0
                    dst_v, dst_stride_v, width, height, dst_uv_width,
134
0
                    dst_uv_height);
135
0
}
136
137
// 420 chroma is 1/2 width, 1/2 height
138
// 444 chroma is 1x width, 1x height
139
LIBYUV_API
140
int I420ToI444(const uint8_t* src_y,
141
               int src_stride_y,
142
               const uint8_t* src_u,
143
               int src_stride_u,
144
               const uint8_t* src_v,
145
               int src_stride_v,
146
               uint8_t* dst_y,
147
               int dst_stride_y,
148
               uint8_t* dst_u,
149
               int dst_stride_u,
150
               uint8_t* dst_v,
151
               int dst_stride_v,
152
               int width,
153
0
               int height) {
154
0
  const int dst_uv_width = Abs(width);
155
0
  const int dst_uv_height = Abs(height);
156
0
  return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
157
0
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
158
0
                    dst_v, dst_stride_v, width, height, dst_uv_width,
159
0
                    dst_uv_height);
160
0
}
161
162
// Copy to I400. Source can be I420,422,444,400,NV12,NV21
163
LIBYUV_API
164
int I400Copy(const uint8_t* src_y,
165
             int src_stride_y,
166
             uint8_t* dst_y,
167
             int dst_stride_y,
168
             int width,
169
0
             int height) {
170
0
  if (!src_y || !dst_y || width <= 0 || height == 0) {
171
0
    return -1;
172
0
  }
173
0
  // Negative height means invert the image.
174
0
  if (height < 0) {
175
0
    height = -height;
176
0
    src_y = src_y + (height - 1) * src_stride_y;
177
0
    src_stride_y = -src_stride_y;
178
0
  }
179
0
  CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
180
0
  return 0;
181
0
}
182
183
LIBYUV_API
184
int I422ToYUY2(const uint8_t* src_y,
185
               int src_stride_y,
186
               const uint8_t* src_u,
187
               int src_stride_u,
188
               const uint8_t* src_v,
189
               int src_stride_v,
190
               uint8_t* dst_yuy2,
191
               int dst_stride_yuy2,
192
               int width,
193
0
               int height) {
194
0
  int y;
195
0
  void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u,
196
0
                        const uint8_t* src_v, uint8_t* dst_yuy2, int width) =
197
0
      I422ToYUY2Row_C;
198
0
  if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
199
0
    return -1;
200
0
  }
201
0
  // Negative height means invert the image.
202
0
  if (height < 0) {
203
0
    height = -height;
204
0
    dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
205
0
    dst_stride_yuy2 = -dst_stride_yuy2;
206
0
  }
207
0
  // Coalesce rows.
208
0
  if (src_stride_y == width && src_stride_u * 2 == width &&
209
0
      src_stride_v * 2 == width && dst_stride_yuy2 == width * 2) {
210
0
    width *= height;
211
0
    height = 1;
212
0
    src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
213
0
  }
214
0
#if defined(HAS_I422TOYUY2ROW_SSE2)
215
0
  if (TestCpuFlag(kCpuHasSSE2)) {
216
0
    I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
217
0
    if (IS_ALIGNED(width, 16)) {
218
0
      I422ToYUY2Row = I422ToYUY2Row_SSE2;
219
0
    }
220
0
  }
221
0
#endif
222
0
#if defined(HAS_I422TOYUY2ROW_AVX2)
223
0
  if (TestCpuFlag(kCpuHasAVX2)) {
224
0
    I422ToYUY2Row = I422ToYUY2Row_Any_AVX2;
225
0
    if (IS_ALIGNED(width, 32)) {
226
0
      I422ToYUY2Row = I422ToYUY2Row_AVX2;
227
0
    }
228
0
  }
229
0
#endif
230
#if defined(HAS_I422TOYUY2ROW_NEON)
231
  if (TestCpuFlag(kCpuHasNEON)) {
232
    I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
233
    if (IS_ALIGNED(width, 16)) {
234
      I422ToYUY2Row = I422ToYUY2Row_NEON;
235
    }
236
  }
237
#endif
238
239
0
  for (y = 0; y < height; ++y) {
240
0
    I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
241
0
    src_y += src_stride_y;
242
0
    src_u += src_stride_u;
243
0
    src_v += src_stride_v;
244
0
    dst_yuy2 += dst_stride_yuy2;
245
0
  }
246
0
  return 0;
247
0
}
248
249
LIBYUV_API
250
int I420ToYUY2(const uint8_t* src_y,
251
               int src_stride_y,
252
               const uint8_t* src_u,
253
               int src_stride_u,
254
               const uint8_t* src_v,
255
               int src_stride_v,
256
               uint8_t* dst_yuy2,
257
               int dst_stride_yuy2,
258
               int width,
259
0
               int height) {
260
0
  int y;
261
0
  void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u,
262
0
                        const uint8_t* src_v, uint8_t* dst_yuy2, int width) =
263
0
      I422ToYUY2Row_C;
264
0
  if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
265
0
    return -1;
266
0
  }
267
0
  // Negative height means invert the image.
268
0
  if (height < 0) {
269
0
    height = -height;
270
0
    dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
271
0
    dst_stride_yuy2 = -dst_stride_yuy2;
272
0
  }
273
0
#if defined(HAS_I422TOYUY2ROW_SSE2)
274
0
  if (TestCpuFlag(kCpuHasSSE2)) {
275
0
    I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
276
0
    if (IS_ALIGNED(width, 16)) {
277
0
      I422ToYUY2Row = I422ToYUY2Row_SSE2;
278
0
    }
279
0
  }
280
0
#endif
281
0
#if defined(HAS_I422TOYUY2ROW_AVX2)
282
0
  if (TestCpuFlag(kCpuHasAVX2)) {
283
0
    I422ToYUY2Row = I422ToYUY2Row_Any_AVX2;
284
0
    if (IS_ALIGNED(width, 32)) {
285
0
      I422ToYUY2Row = I422ToYUY2Row_AVX2;
286
0
    }
287
0
  }
288
0
#endif
289
#if defined(HAS_I422TOYUY2ROW_NEON)
290
  if (TestCpuFlag(kCpuHasNEON)) {
291
    I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
292
    if (IS_ALIGNED(width, 16)) {
293
      I422ToYUY2Row = I422ToYUY2Row_NEON;
294
    }
295
  }
296
#endif
297
#if defined(HAS_I422TOYUY2ROW_MSA)
298
  if (TestCpuFlag(kCpuHasMSA)) {
299
    I422ToYUY2Row = I422ToYUY2Row_Any_MSA;
300
    if (IS_ALIGNED(width, 32)) {
301
      I422ToYUY2Row = I422ToYUY2Row_MSA;
302
    }
303
  }
304
#endif
305
306
0
  for (y = 0; y < height - 1; y += 2) {
307
0
    I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
308
0
    I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
309
0
                  dst_yuy2 + dst_stride_yuy2, width);
310
0
    src_y += src_stride_y * 2;
311
0
    src_u += src_stride_u;
312
0
    src_v += src_stride_v;
313
0
    dst_yuy2 += dst_stride_yuy2 * 2;
314
0
  }
315
0
  if (height & 1) {
316
0
    I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
317
0
  }
318
0
  return 0;
319
0
}
320
321
LIBYUV_API
322
int I422ToUYVY(const uint8_t* src_y,
323
               int src_stride_y,
324
               const uint8_t* src_u,
325
               int src_stride_u,
326
               const uint8_t* src_v,
327
               int src_stride_v,
328
               uint8_t* dst_uyvy,
329
               int dst_stride_uyvy,
330
               int width,
331
0
               int height) {
332
0
  int y;
333
0
  void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
334
0
                        const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
335
0
      I422ToUYVYRow_C;
336
0
  if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
337
0
    return -1;
338
0
  }
339
0
  // Negative height means invert the image.
340
0
  if (height < 0) {
341
0
    height = -height;
342
0
    dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
343
0
    dst_stride_uyvy = -dst_stride_uyvy;
344
0
  }
345
0
  // Coalesce rows.
346
0
  if (src_stride_y == width && src_stride_u * 2 == width &&
347
0
      src_stride_v * 2 == width && dst_stride_uyvy == width * 2) {
348
0
    width *= height;
349
0
    height = 1;
350
0
    src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
351
0
  }
352
0
#if defined(HAS_I422TOUYVYROW_SSE2)
353
0
  if (TestCpuFlag(kCpuHasSSE2)) {
354
0
    I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
355
0
    if (IS_ALIGNED(width, 16)) {
356
0
      I422ToUYVYRow = I422ToUYVYRow_SSE2;
357
0
    }
358
0
  }
359
0
#endif
360
0
#if defined(HAS_I422TOUYVYROW_AVX2)
361
0
  if (TestCpuFlag(kCpuHasAVX2)) {
362
0
    I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
363
0
    if (IS_ALIGNED(width, 32)) {
364
0
      I422ToUYVYRow = I422ToUYVYRow_AVX2;
365
0
    }
366
0
  }
367
0
#endif
368
#if defined(HAS_I422TOUYVYROW_NEON)
369
  if (TestCpuFlag(kCpuHasNEON)) {
370
    I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
371
    if (IS_ALIGNED(width, 16)) {
372
      I422ToUYVYRow = I422ToUYVYRow_NEON;
373
    }
374
  }
375
#endif
376
#if defined(HAS_I422TOUYVYROW_MSA)
377
  if (TestCpuFlag(kCpuHasMSA)) {
378
    I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
379
    if (IS_ALIGNED(width, 32)) {
380
      I422ToUYVYRow = I422ToUYVYRow_MSA;
381
    }
382
  }
383
#endif
384
385
0
  for (y = 0; y < height; ++y) {
386
0
    I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
387
0
    src_y += src_stride_y;
388
0
    src_u += src_stride_u;
389
0
    src_v += src_stride_v;
390
0
    dst_uyvy += dst_stride_uyvy;
391
0
  }
392
0
  return 0;
393
0
}
394
395
LIBYUV_API
396
int I420ToUYVY(const uint8_t* src_y,
397
               int src_stride_y,
398
               const uint8_t* src_u,
399
               int src_stride_u,
400
               const uint8_t* src_v,
401
               int src_stride_v,
402
               uint8_t* dst_uyvy,
403
               int dst_stride_uyvy,
404
               int width,
405
0
               int height) {
406
0
  int y;
407
0
  void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
408
0
                        const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
409
0
      I422ToUYVYRow_C;
410
0
  if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
411
0
    return -1;
412
0
  }
413
0
  // Negative height means invert the image.
414
0
  if (height < 0) {
415
0
    height = -height;
416
0
    dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
417
0
    dst_stride_uyvy = -dst_stride_uyvy;
418
0
  }
419
0
#if defined(HAS_I422TOUYVYROW_SSE2)
420
0
  if (TestCpuFlag(kCpuHasSSE2)) {
421
0
    I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
422
0
    if (IS_ALIGNED(width, 16)) {
423
0
      I422ToUYVYRow = I422ToUYVYRow_SSE2;
424
0
    }
425
0
  }
426
0
#endif
427
0
#if defined(HAS_I422TOUYVYROW_AVX2)
428
0
  if (TestCpuFlag(kCpuHasAVX2)) {
429
0
    I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
430
0
    if (IS_ALIGNED(width, 32)) {
431
0
      I422ToUYVYRow = I422ToUYVYRow_AVX2;
432
0
    }
433
0
  }
434
0
#endif
435
#if defined(HAS_I422TOUYVYROW_NEON)
436
  if (TestCpuFlag(kCpuHasNEON)) {
437
    I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
438
    if (IS_ALIGNED(width, 16)) {
439
      I422ToUYVYRow = I422ToUYVYRow_NEON;
440
    }
441
  }
442
#endif
443
#if defined(HAS_I422TOUYVYROW_MSA)
444
  if (TestCpuFlag(kCpuHasMSA)) {
445
    I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
446
    if (IS_ALIGNED(width, 32)) {
447
      I422ToUYVYRow = I422ToUYVYRow_MSA;
448
    }
449
  }
450
#endif
451
452
0
  for (y = 0; y < height - 1; y += 2) {
453
0
    I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
454
0
    I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
455
0
                  dst_uyvy + dst_stride_uyvy, width);
456
0
    src_y += src_stride_y * 2;
457
0
    src_u += src_stride_u;
458
0
    src_v += src_stride_v;
459
0
    dst_uyvy += dst_stride_uyvy * 2;
460
0
  }
461
0
  if (height & 1) {
462
0
    I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
463
0
  }
464
0
  return 0;
465
0
}
466
467
// TODO(fbarchard): test negative height for invert.
468
LIBYUV_API
469
int I420ToNV12(const uint8_t* src_y,
470
               int src_stride_y,
471
               const uint8_t* src_u,
472
               int src_stride_u,
473
               const uint8_t* src_v,
474
               int src_stride_v,
475
               uint8_t* dst_y,
476
               int dst_stride_y,
477
               uint8_t* dst_uv,
478
               int dst_stride_uv,
479
               int width,
480
0
               int height) {
481
0
  if (!src_y || !src_u || !src_v || !dst_y || !dst_uv || width <= 0 ||
482
0
      height == 0) {
483
0
    return -1;
484
0
  }
485
0
  int halfwidth = (width + 1) / 2;
486
0
  int halfheight = height > 0 ? (height + 1) / 2 : (height - 1) / 2;
487
0
  if (dst_y) {
488
0
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
489
0
  }
490
0
  MergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv, dst_stride_uv,
491
0
               halfwidth, halfheight);
492
0
  return 0;
493
0
}
494
495
LIBYUV_API
496
int I420ToNV21(const uint8_t* src_y,
497
               int src_stride_y,
498
               const uint8_t* src_u,
499
               int src_stride_u,
500
               const uint8_t* src_v,
501
               int src_stride_v,
502
               uint8_t* dst_y,
503
               int dst_stride_y,
504
               uint8_t* dst_vu,
505
               int dst_stride_vu,
506
               int width,
507
0
               int height) {
508
0
  return I420ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
509
0
                    src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
510
0
                    width, height);
511
0
}
512
513
// Convert I422 to RGBA with matrix
514
static int I420ToRGBAMatrix(const uint8_t* src_y,
515
                            int src_stride_y,
516
                            const uint8_t* src_u,
517
                            int src_stride_u,
518
                            const uint8_t* src_v,
519
                            int src_stride_v,
520
                            uint8_t* dst_rgba,
521
                            int dst_stride_rgba,
522
                            const struct YuvConstants* yuvconstants,
523
                            int width,
524
0
                            int height) {
525
0
  int y;
526
0
  void (*I422ToRGBARow)(const uint8_t* y_buf, const uint8_t* u_buf,
527
0
                        const uint8_t* v_buf, uint8_t* rgb_buf,
528
0
                        const struct YuvConstants* yuvconstants, int width) =
529
0
      I422ToRGBARow_C;
530
0
  if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) {
531
0
    return -1;
532
0
  }
533
0
  // Negative height means invert the image.
534
0
  if (height < 0) {
535
0
    height = -height;
536
0
    dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
537
0
    dst_stride_rgba = -dst_stride_rgba;
538
0
  }
539
0
#if defined(HAS_I422TORGBAROW_SSSE3)
540
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
541
0
    I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
542
0
    if (IS_ALIGNED(width, 8)) {
543
0
      I422ToRGBARow = I422ToRGBARow_SSSE3;
544
0
    }
545
0
  }
546
0
#endif
547
0
#if defined(HAS_I422TORGBAROW_AVX2)
548
0
  if (TestCpuFlag(kCpuHasAVX2)) {
549
0
    I422ToRGBARow = I422ToRGBARow_Any_AVX2;
550
0
    if (IS_ALIGNED(width, 16)) {
551
0
      I422ToRGBARow = I422ToRGBARow_AVX2;
552
0
    }
553
0
  }
554
0
#endif
555
#if defined(HAS_I422TORGBAROW_NEON)
556
  if (TestCpuFlag(kCpuHasNEON)) {
557
    I422ToRGBARow = I422ToRGBARow_Any_NEON;
558
    if (IS_ALIGNED(width, 8)) {
559
      I422ToRGBARow = I422ToRGBARow_NEON;
560
    }
561
  }
562
#endif
563
#if defined(HAS_I422TORGBAROW_MSA)
564
  if (TestCpuFlag(kCpuHasMSA)) {
565
    I422ToRGBARow = I422ToRGBARow_Any_MSA;
566
    if (IS_ALIGNED(width, 8)) {
567
      I422ToRGBARow = I422ToRGBARow_MSA;
568
    }
569
  }
570
#endif
571
572
0
  for (y = 0; y < height; ++y) {
573
0
    I422ToRGBARow(src_y, src_u, src_v, dst_rgba, yuvconstants, width);
574
0
    dst_rgba += dst_stride_rgba;
575
0
    src_y += src_stride_y;
576
0
    if (y & 1) {
577
0
      src_u += src_stride_u;
578
0
      src_v += src_stride_v;
579
0
    }
580
0
  }
581
0
  return 0;
582
0
}
583
584
// Convert I420 to RGBA.
585
LIBYUV_API
586
int I420ToRGBA(const uint8_t* src_y,
587
               int src_stride_y,
588
               const uint8_t* src_u,
589
               int src_stride_u,
590
               const uint8_t* src_v,
591
               int src_stride_v,
592
               uint8_t* dst_rgba,
593
               int dst_stride_rgba,
594
               int width,
595
0
               int height) {
596
0
  return I420ToRGBAMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
597
0
                          src_stride_v, dst_rgba, dst_stride_rgba,
598
0
                          &kYuvI601Constants, width, height);
599
0
}
600
601
// Convert I420 to BGRA.
602
LIBYUV_API
603
int I420ToBGRA(const uint8_t* src_y,
604
               int src_stride_y,
605
               const uint8_t* src_u,
606
               int src_stride_u,
607
               const uint8_t* src_v,
608
               int src_stride_v,
609
               uint8_t* dst_bgra,
610
               int dst_stride_bgra,
611
               int width,
612
0
               int height) {
613
0
  return I420ToRGBAMatrix(src_y, src_stride_y, src_v,
614
0
                          src_stride_v,  // Swap U and V
615
0
                          src_u, src_stride_u, dst_bgra, dst_stride_bgra,
616
0
                          &kYvuI601Constants,  // Use Yvu matrix
617
0
                          width, height);
618
0
}
619
620
// Convert I420 to RGB24 with matrix
621
static int I420ToRGB24Matrix(const uint8_t* src_y,
622
                             int src_stride_y,
623
                             const uint8_t* src_u,
624
                             int src_stride_u,
625
                             const uint8_t* src_v,
626
                             int src_stride_v,
627
                             uint8_t* dst_rgb24,
628
                             int dst_stride_rgb24,
629
                             const struct YuvConstants* yuvconstants,
630
                             int width,
631
0
                             int height) {
632
0
  int y;
633
0
  void (*I422ToRGB24Row)(const uint8_t* y_buf, const uint8_t* u_buf,
634
0
                         const uint8_t* v_buf, uint8_t* rgb_buf,
635
0
                         const struct YuvConstants* yuvconstants, int width) =
636
0
      I422ToRGB24Row_C;
637
0
  if (!src_y || !src_u || !src_v || !dst_rgb24 || width <= 0 || height == 0) {
638
0
    return -1;
639
0
  }
640
0
  // Negative height means invert the image.
641
0
  if (height < 0) {
642
0
    height = -height;
643
0
    dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
644
0
    dst_stride_rgb24 = -dst_stride_rgb24;
645
0
  }
646
0
#if defined(HAS_I422TORGB24ROW_SSSE3)
647
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
648
0
    I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
649
0
    if (IS_ALIGNED(width, 8)) {
650
0
      I422ToRGB24Row = I422ToRGB24Row_SSSE3;
651
0
    }
652
0
  }
653
0
#endif
654
0
#if defined(HAS_I422TORGB24ROW_AVX2)
655
0
  if (TestCpuFlag(kCpuHasAVX2)) {
656
0
    I422ToRGB24Row = I422ToRGB24Row_Any_AVX2;
657
0
    if (IS_ALIGNED(width, 16)) {
658
0
      I422ToRGB24Row = I422ToRGB24Row_AVX2;
659
0
    }
660
0
  }
661
0
#endif
662
#if defined(HAS_I422TORGB24ROW_NEON)
663
  if (TestCpuFlag(kCpuHasNEON)) {
664
    I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
665
    if (IS_ALIGNED(width, 8)) {
666
      I422ToRGB24Row = I422ToRGB24Row_NEON;
667
    }
668
  }
669
#endif
670
#if defined(HAS_I422TORGB24ROW_MSA)
671
  if (TestCpuFlag(kCpuHasMSA)) {
672
    I422ToRGB24Row = I422ToRGB24Row_Any_MSA;
673
    if (IS_ALIGNED(width, 16)) {
674
      I422ToRGB24Row = I422ToRGB24Row_MSA;
675
    }
676
  }
677
#endif
678
679
0
  for (y = 0; y < height; ++y) {
680
0
    I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, yuvconstants, width);
681
0
    dst_rgb24 += dst_stride_rgb24;
682
0
    src_y += src_stride_y;
683
0
    if (y & 1) {
684
0
      src_u += src_stride_u;
685
0
      src_v += src_stride_v;
686
0
    }
687
0
  }
688
0
  return 0;
689
0
}
690
691
// Convert I420 to RGB24.
692
LIBYUV_API
693
int I420ToRGB24(const uint8_t* src_y,
694
                int src_stride_y,
695
                const uint8_t* src_u,
696
                int src_stride_u,
697
                const uint8_t* src_v,
698
                int src_stride_v,
699
                uint8_t* dst_rgb24,
700
                int dst_stride_rgb24,
701
                int width,
702
0
                int height) {
703
0
  return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
704
0
                           src_stride_v, dst_rgb24, dst_stride_rgb24,
705
0
                           &kYuvI601Constants, width, height);
706
0
}
707
708
// Convert I420 to RAW.
709
LIBYUV_API
710
int I420ToRAW(const uint8_t* src_y,
711
              int src_stride_y,
712
              const uint8_t* src_u,
713
              int src_stride_u,
714
              const uint8_t* src_v,
715
              int src_stride_v,
716
              uint8_t* dst_raw,
717
              int dst_stride_raw,
718
              int width,
719
0
              int height) {
720
0
  return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
721
0
                           src_stride_v,  // Swap U and V
722
0
                           src_u, src_stride_u, dst_raw, dst_stride_raw,
723
0
                           &kYvuI601Constants,  // Use Yvu matrix
724
0
                           width, height);
725
0
}
726
727
// Convert H420 to RGB24.
728
LIBYUV_API
729
int H420ToRGB24(const uint8_t* src_y,
730
                int src_stride_y,
731
                const uint8_t* src_u,
732
                int src_stride_u,
733
                const uint8_t* src_v,
734
                int src_stride_v,
735
                uint8_t* dst_rgb24,
736
                int dst_stride_rgb24,
737
                int width,
738
0
                int height) {
739
0
  return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
740
0
                           src_stride_v, dst_rgb24, dst_stride_rgb24,
741
0
                           &kYuvH709Constants, width, height);
742
0
}
743
744
// Convert H420 to RAW.
745
LIBYUV_API
746
int H420ToRAW(const uint8_t* src_y,
747
              int src_stride_y,
748
              const uint8_t* src_u,
749
              int src_stride_u,
750
              const uint8_t* src_v,
751
              int src_stride_v,
752
              uint8_t* dst_raw,
753
              int dst_stride_raw,
754
              int width,
755
0
              int height) {
756
0
  return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
757
0
                           src_stride_v,  // Swap U and V
758
0
                           src_u, src_stride_u, dst_raw, dst_stride_raw,
759
0
                           &kYvuH709Constants,  // Use Yvu matrix
760
0
                           width, height);
761
0
}
762
763
// Convert I420 to ARGB1555.
764
LIBYUV_API
765
int I420ToARGB1555(const uint8_t* src_y,
766
                   int src_stride_y,
767
                   const uint8_t* src_u,
768
                   int src_stride_u,
769
                   const uint8_t* src_v,
770
                   int src_stride_v,
771
                   uint8_t* dst_argb1555,
772
                   int dst_stride_argb1555,
773
                   int width,
774
0
                   int height) {
775
0
  int y;
776
0
  void (*I422ToARGB1555Row)(const uint8_t* y_buf, const uint8_t* u_buf,
777
0
                            const uint8_t* v_buf, uint8_t* rgb_buf,
778
0
                            const struct YuvConstants* yuvconstants,
779
0
                            int width) = I422ToARGB1555Row_C;
780
0
  if (!src_y || !src_u || !src_v || !dst_argb1555 || width <= 0 ||
781
0
      height == 0) {
782
0
    return -1;
783
0
  }
784
0
  // Negative height means invert the image.
785
0
  if (height < 0) {
786
0
    height = -height;
787
0
    dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
788
0
    dst_stride_argb1555 = -dst_stride_argb1555;
789
0
  }
790
0
#if defined(HAS_I422TOARGB1555ROW_SSSE3)
791
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
792
0
    I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
793
0
    if (IS_ALIGNED(width, 8)) {
794
0
      I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
795
0
    }
796
0
  }
797
0
#endif
798
0
#if defined(HAS_I422TOARGB1555ROW_AVX2)
799
0
  if (TestCpuFlag(kCpuHasAVX2)) {
800
0
    I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2;
801
0
    if (IS_ALIGNED(width, 16)) {
802
0
      I422ToARGB1555Row = I422ToARGB1555Row_AVX2;
803
0
    }
804
0
  }
805
0
#endif
806
#if defined(HAS_I422TOARGB1555ROW_NEON)
807
  if (TestCpuFlag(kCpuHasNEON)) {
808
    I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
809
    if (IS_ALIGNED(width, 8)) {
810
      I422ToARGB1555Row = I422ToARGB1555Row_NEON;
811
    }
812
  }
813
#endif
814
#if defined(HAS_I422TOARGB1555ROW_MSA)
815
  if (TestCpuFlag(kCpuHasMSA)) {
816
    I422ToARGB1555Row = I422ToARGB1555Row_Any_MSA;
817
    if (IS_ALIGNED(width, 8)) {
818
      I422ToARGB1555Row = I422ToARGB1555Row_MSA;
819
    }
820
  }
821
#endif
822
823
0
  for (y = 0; y < height; ++y) {
824
0
    I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, &kYuvI601Constants,
825
0
                      width);
826
0
    dst_argb1555 += dst_stride_argb1555;
827
0
    src_y += src_stride_y;
828
0
    if (y & 1) {
829
0
      src_u += src_stride_u;
830
0
      src_v += src_stride_v;
831
0
    }
832
0
  }
833
0
  return 0;
834
0
}
835
836
// Convert I420 to ARGB4444.
837
LIBYUV_API
838
int I420ToARGB4444(const uint8_t* src_y,
839
                   int src_stride_y,
840
                   const uint8_t* src_u,
841
                   int src_stride_u,
842
                   const uint8_t* src_v,
843
                   int src_stride_v,
844
                   uint8_t* dst_argb4444,
845
                   int dst_stride_argb4444,
846
                   int width,
847
0
                   int height) {
848
0
  int y;
849
0
  void (*I422ToARGB4444Row)(const uint8_t* y_buf, const uint8_t* u_buf,
850
0
                            const uint8_t* v_buf, uint8_t* rgb_buf,
851
0
                            const struct YuvConstants* yuvconstants,
852
0
                            int width) = I422ToARGB4444Row_C;
853
0
  if (!src_y || !src_u || !src_v || !dst_argb4444 || width <= 0 ||
854
0
      height == 0) {
855
0
    return -1;
856
0
  }
857
0
  // Negative height means invert the image.
858
0
  if (height < 0) {
859
0
    height = -height;
860
0
    dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
861
0
    dst_stride_argb4444 = -dst_stride_argb4444;
862
0
  }
863
0
#if defined(HAS_I422TOARGB4444ROW_SSSE3)
864
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
865
0
    I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
866
0
    if (IS_ALIGNED(width, 8)) {
867
0
      I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
868
0
    }
869
0
  }
870
0
#endif
871
0
#if defined(HAS_I422TOARGB4444ROW_AVX2)
872
0
  if (TestCpuFlag(kCpuHasAVX2)) {
873
0
    I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2;
874
0
    if (IS_ALIGNED(width, 16)) {
875
0
      I422ToARGB4444Row = I422ToARGB4444Row_AVX2;
876
0
    }
877
0
  }
878
0
#endif
879
#if defined(HAS_I422TOARGB4444ROW_NEON)
880
  if (TestCpuFlag(kCpuHasNEON)) {
881
    I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
882
    if (IS_ALIGNED(width, 8)) {
883
      I422ToARGB4444Row = I422ToARGB4444Row_NEON;
884
    }
885
  }
886
#endif
887
#if defined(HAS_I422TOARGB4444ROW_MSA)
888
  if (TestCpuFlag(kCpuHasMSA)) {
889
    I422ToARGB4444Row = I422ToARGB4444Row_Any_MSA;
890
    if (IS_ALIGNED(width, 8)) {
891
      I422ToARGB4444Row = I422ToARGB4444Row_MSA;
892
    }
893
  }
894
#endif
895
896
0
  for (y = 0; y < height; ++y) {
897
0
    I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, &kYuvI601Constants,
898
0
                      width);
899
0
    dst_argb4444 += dst_stride_argb4444;
900
0
    src_y += src_stride_y;
901
0
    if (y & 1) {
902
0
      src_u += src_stride_u;
903
0
      src_v += src_stride_v;
904
0
    }
905
0
  }
906
0
  return 0;
907
0
}
908
909
// Convert I420 to RGB565.
910
LIBYUV_API
911
int I420ToRGB565(const uint8_t* src_y,
912
                 int src_stride_y,
913
                 const uint8_t* src_u,
914
                 int src_stride_u,
915
                 const uint8_t* src_v,
916
                 int src_stride_v,
917
                 uint8_t* dst_rgb565,
918
                 int dst_stride_rgb565,
919
                 int width,
920
0
                 int height) {
921
0
  int y;
922
0
  void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf,
923
0
                          const uint8_t* v_buf, uint8_t* rgb_buf,
924
0
                          const struct YuvConstants* yuvconstants, int width) =
925
0
      I422ToRGB565Row_C;
926
0
  if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
927
0
    return -1;
928
0
  }
929
0
  // Negative height means invert the image.
930
0
  if (height < 0) {
931
0
    height = -height;
932
0
    dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
933
0
    dst_stride_rgb565 = -dst_stride_rgb565;
934
0
  }
935
0
#if defined(HAS_I422TORGB565ROW_SSSE3)
936
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
937
0
    I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
938
0
    if (IS_ALIGNED(width, 8)) {
939
0
      I422ToRGB565Row = I422ToRGB565Row_SSSE3;
940
0
    }
941
0
  }
942
0
#endif
943
0
#if defined(HAS_I422TORGB565ROW_AVX2)
944
0
  if (TestCpuFlag(kCpuHasAVX2)) {
945
0
    I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
946
0
    if (IS_ALIGNED(width, 16)) {
947
0
      I422ToRGB565Row = I422ToRGB565Row_AVX2;
948
0
    }
949
0
  }
950
0
#endif
951
#if defined(HAS_I422TORGB565ROW_NEON)
952
  if (TestCpuFlag(kCpuHasNEON)) {
953
    I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
954
    if (IS_ALIGNED(width, 8)) {
955
      I422ToRGB565Row = I422ToRGB565Row_NEON;
956
    }
957
  }
958
#endif
959
#if defined(HAS_I422TORGB565ROW_MSA)
960
  if (TestCpuFlag(kCpuHasMSA)) {
961
    I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
962
    if (IS_ALIGNED(width, 8)) {
963
      I422ToRGB565Row = I422ToRGB565Row_MSA;
964
    }
965
  }
966
#endif
967
968
0
  for (y = 0; y < height; ++y) {
969
0
    I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
970
0
    dst_rgb565 += dst_stride_rgb565;
971
0
    src_y += src_stride_y;
972
0
    if (y & 1) {
973
0
      src_u += src_stride_u;
974
0
      src_v += src_stride_v;
975
0
    }
976
0
  }
977
0
  return 0;
978
0
}
979
980
// Convert I422 to RGB565.
981
LIBYUV_API
982
int I422ToRGB565(const uint8_t* src_y,
983
                 int src_stride_y,
984
                 const uint8_t* src_u,
985
                 int src_stride_u,
986
                 const uint8_t* src_v,
987
                 int src_stride_v,
988
                 uint8_t* dst_rgb565,
989
                 int dst_stride_rgb565,
990
                 int width,
991
0
                 int height) {
992
0
  int y;
993
0
  void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf,
994
0
                          const uint8_t* v_buf, uint8_t* rgb_buf,
995
0
                          const struct YuvConstants* yuvconstants, int width) =
996
0
      I422ToRGB565Row_C;
997
0
  if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
998
0
    return -1;
999
0
  }
1000
0
  // Negative height means invert the image.
1001
0
  if (height < 0) {
1002
0
    height = -height;
1003
0
    dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
1004
0
    dst_stride_rgb565 = -dst_stride_rgb565;
1005
0
  }
1006
0
#if defined(HAS_I422TORGB565ROW_SSSE3)
1007
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
1008
0
    I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
1009
0
    if (IS_ALIGNED(width, 8)) {
1010
0
      I422ToRGB565Row = I422ToRGB565Row_SSSE3;
1011
0
    }
1012
0
  }
1013
0
#endif
1014
0
#if defined(HAS_I422TORGB565ROW_AVX2)
1015
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1016
0
    I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
1017
0
    if (IS_ALIGNED(width, 16)) {
1018
0
      I422ToRGB565Row = I422ToRGB565Row_AVX2;
1019
0
    }
1020
0
  }
1021
0
#endif
1022
#if defined(HAS_I422TORGB565ROW_NEON)
1023
  if (TestCpuFlag(kCpuHasNEON)) {
1024
    I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
1025
    if (IS_ALIGNED(width, 8)) {
1026
      I422ToRGB565Row = I422ToRGB565Row_NEON;
1027
    }
1028
  }
1029
#endif
1030
#if defined(HAS_I422TORGB565ROW_MSA)
1031
  if (TestCpuFlag(kCpuHasMSA)) {
1032
    I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
1033
    if (IS_ALIGNED(width, 8)) {
1034
      I422ToRGB565Row = I422ToRGB565Row_MSA;
1035
    }
1036
  }
1037
#endif
1038
1039
0
  for (y = 0; y < height; ++y) {
1040
0
    I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
1041
0
    dst_rgb565 += dst_stride_rgb565;
1042
0
    src_y += src_stride_y;
1043
0
    src_u += src_stride_u;
1044
0
    src_v += src_stride_v;
1045
0
  }
1046
0
  return 0;
1047
0
}
1048
1049
// Ordered 8x8 dither for 888 to 565.  Values from 0 to 7.
1050
static const uint8_t kDither565_4x4[16] = {
1051
    0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
1052
};
1053
1054
// Convert I420 to RGB565 with dithering.
1055
LIBYUV_API
1056
int I420ToRGB565Dither(const uint8_t* src_y,
1057
                       int src_stride_y,
1058
                       const uint8_t* src_u,
1059
                       int src_stride_u,
1060
                       const uint8_t* src_v,
1061
                       int src_stride_v,
1062
                       uint8_t* dst_rgb565,
1063
                       int dst_stride_rgb565,
1064
                       const uint8_t* dither4x4,
1065
                       int width,
1066
0
                       int height) {
1067
0
  int y;
1068
0
  void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
1069
0
                        const uint8_t* v_buf, uint8_t* rgb_buf,
1070
0
                        const struct YuvConstants* yuvconstants, int width) =
1071
0
      I422ToARGBRow_C;
1072
0
  void (*ARGBToRGB565DitherRow)(const uint8_t* src_argb, uint8_t* dst_rgb,
1073
0
                                const uint32_t dither4, int width) =
1074
0
      ARGBToRGB565DitherRow_C;
1075
0
  if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
1076
0
    return -1;
1077
0
  }
1078
0
  // Negative height means invert the image.
1079
0
  if (height < 0) {
1080
0
    height = -height;
1081
0
    dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
1082
0
    dst_stride_rgb565 = -dst_stride_rgb565;
1083
0
  }
1084
0
  if (!dither4x4) {
1085
0
    dither4x4 = kDither565_4x4;
1086
0
  }
1087
0
#if defined(HAS_I422TOARGBROW_SSSE3)
1088
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
1089
0
    I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
1090
0
    if (IS_ALIGNED(width, 8)) {
1091
0
      I422ToARGBRow = I422ToARGBRow_SSSE3;
1092
0
    }
1093
0
  }
1094
0
#endif
1095
0
#if defined(HAS_I422TOARGBROW_AVX2)
1096
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1097
0
    I422ToARGBRow = I422ToARGBRow_Any_AVX2;
1098
0
    if (IS_ALIGNED(width, 16)) {
1099
0
      I422ToARGBRow = I422ToARGBRow_AVX2;
1100
0
    }
1101
0
  }
1102
0
#endif
1103
#if defined(HAS_I422TOARGBROW_NEON)
1104
  if (TestCpuFlag(kCpuHasNEON)) {
1105
    I422ToARGBRow = I422ToARGBRow_Any_NEON;
1106
    if (IS_ALIGNED(width, 8)) {
1107
      I422ToARGBRow = I422ToARGBRow_NEON;
1108
    }
1109
  }
1110
#endif
1111
#if defined(HAS_I422TOARGBROW_MSA)
1112
  if (TestCpuFlag(kCpuHasMSA)) {
1113
    I422ToARGBRow = I422ToARGBRow_Any_MSA;
1114
    if (IS_ALIGNED(width, 8)) {
1115
      I422ToARGBRow = I422ToARGBRow_MSA;
1116
    }
1117
  }
1118
#endif
1119
#if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
1120
0
  if (TestCpuFlag(kCpuHasSSE2)) {
1121
0
    ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
1122
0
    if (IS_ALIGNED(width, 4)) {
1123
0
      ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
1124
0
    }
1125
0
  }
1126
0
#endif
1127
0
#if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
1128
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1129
0
    ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
1130
0
    if (IS_ALIGNED(width, 8)) {
1131
0
      ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
1132
0
    }
1133
0
  }
1134
0
#endif
1135
#if defined(HAS_ARGBTORGB565DITHERROW_NEON)
1136
  if (TestCpuFlag(kCpuHasNEON)) {
1137
    ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
1138
    if (IS_ALIGNED(width, 8)) {
1139
      ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
1140
    }
1141
  }
1142
#endif
1143
#if defined(HAS_ARGBTORGB565DITHERROW_MSA)
1144
  if (TestCpuFlag(kCpuHasMSA)) {
1145
    ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
1146
    if (IS_ALIGNED(width, 8)) {
1147
      ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_MSA;
1148
    }
1149
  }
1150
#endif
1151
  {
1152
0
    // Allocate a row of argb.
1153
0
    align_buffer_64(row_argb, width * 4);
1154
0
    for (y = 0; y < height; ++y) {
1155
0
      I422ToARGBRow(src_y, src_u, src_v, row_argb, &kYuvI601Constants, width);
1156
0
      ARGBToRGB565DitherRow(row_argb, dst_rgb565,
1157
0
                            *(uint32_t*)(dither4x4 + ((y & 3) << 2)),  // NOLINT
1158
0
                            width);                                    // NOLINT
1159
0
      dst_rgb565 += dst_stride_rgb565;
1160
0
      src_y += src_stride_y;
1161
0
      if (y & 1) {
1162
0
        src_u += src_stride_u;
1163
0
        src_v += src_stride_v;
1164
0
      }
1165
0
    }
1166
0
    free_aligned_buffer_64(row_argb);
1167
0
  }
1168
0
  return 0;
1169
0
}
1170
1171
// Convert I420 to AR30 with matrix
1172
static int I420ToAR30Matrix(const uint8_t* src_y,
1173
                            int src_stride_y,
1174
                            const uint8_t* src_u,
1175
                            int src_stride_u,
1176
                            const uint8_t* src_v,
1177
                            int src_stride_v,
1178
                            uint8_t* dst_ar30,
1179
                            int dst_stride_ar30,
1180
                            const struct YuvConstants* yuvconstants,
1181
                            int width,
1182
0
                            int height) {
1183
0
  int y;
1184
0
  void (*I422ToAR30Row)(const uint8_t* y_buf, const uint8_t* u_buf,
1185
0
                        const uint8_t* v_buf, uint8_t* rgb_buf,
1186
0
                        const struct YuvConstants* yuvconstants, int width) =
1187
0
      I422ToAR30Row_C;
1188
0
1189
0
  if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
1190
0
    return -1;
1191
0
  }
1192
0
  // Negative height means invert the image.
1193
0
  if (height < 0) {
1194
0
    height = -height;
1195
0
    dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
1196
0
    dst_stride_ar30 = -dst_stride_ar30;
1197
0
  }
1198
0
1199
0
#if defined(HAS_I422TOAR30ROW_SSSE3)
1200
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
1201
0
    I422ToAR30Row = I422ToAR30Row_Any_SSSE3;
1202
0
    if (IS_ALIGNED(width, 8)) {
1203
0
      I422ToAR30Row = I422ToAR30Row_SSSE3;
1204
0
    }
1205
0
  }
1206
0
#endif
1207
0
#if defined(HAS_I422TOAR30ROW_AVX2)
1208
0
  if (TestCpuFlag(kCpuHasAVX2)) {
1209
0
    I422ToAR30Row = I422ToAR30Row_Any_AVX2;
1210
0
    if (IS_ALIGNED(width, 16)) {
1211
0
      I422ToAR30Row = I422ToAR30Row_AVX2;
1212
0
    }
1213
0
  }
1214
0
#endif
1215
0
1216
0
  for (y = 0; y < height; ++y) {
1217
0
    I422ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
1218
0
    dst_ar30 += dst_stride_ar30;
1219
0
    src_y += src_stride_y;
1220
0
    if (y & 1) {
1221
0
      src_u += src_stride_u;
1222
0
      src_v += src_stride_v;
1223
0
    }
1224
0
  }
1225
0
  return 0;
1226
0
}
1227
1228
// Convert I420 to AR30.
1229
LIBYUV_API
1230
int I420ToAR30(const uint8_t* src_y,
1231
               int src_stride_y,
1232
               const uint8_t* src_u,
1233
               int src_stride_u,
1234
               const uint8_t* src_v,
1235
               int src_stride_v,
1236
               uint8_t* dst_ar30,
1237
               int dst_stride_ar30,
1238
               int width,
1239
0
               int height) {
1240
0
  return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1241
0
                          src_stride_v, dst_ar30, dst_stride_ar30,
1242
0
                          &kYuvI601Constants, width, height);
1243
0
}
1244
1245
// Convert H420 to AR30.
1246
LIBYUV_API
1247
int H420ToAR30(const uint8_t* src_y,
1248
               int src_stride_y,
1249
               const uint8_t* src_u,
1250
               int src_stride_u,
1251
               const uint8_t* src_v,
1252
               int src_stride_v,
1253
               uint8_t* dst_ar30,
1254
               int dst_stride_ar30,
1255
               int width,
1256
0
               int height) {
1257
0
  return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1258
0
                          src_stride_v, dst_ar30, dst_stride_ar30,
1259
0
                          &kYvuH709Constants, width, height);
1260
0
}
1261
1262
// Convert I420 to specified format
1263
LIBYUV_API
1264
int ConvertFromI420(const uint8_t* y,
1265
                    int y_stride,
1266
                    const uint8_t* u,
1267
                    int u_stride,
1268
                    const uint8_t* v,
1269
                    int v_stride,
1270
                    uint8_t* dst_sample,
1271
                    int dst_sample_stride,
1272
                    int width,
1273
                    int height,
1274
0
                    uint32_t fourcc) {
1275
0
  uint32_t format = CanonicalFourCC(fourcc);
1276
0
  int r = 0;
1277
0
  if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
1278
0
    return -1;
1279
0
  }
1280
0
  switch (format) {
1281
0
    // Single plane formats
1282
0
    case FOURCC_YUY2:
1283
0
      r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1284
0
                     dst_sample_stride ? dst_sample_stride : width * 2, width,
1285
0
                     height);
1286
0
      break;
1287
0
    case FOURCC_UYVY:
1288
0
      r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1289
0
                     dst_sample_stride ? dst_sample_stride : width * 2, width,
1290
0
                     height);
1291
0
      break;
1292
0
    case FOURCC_RGBP:
1293
0
      r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1294
0
                       dst_sample_stride ? dst_sample_stride : width * 2, width,
1295
0
                       height);
1296
0
      break;
1297
0
    case FOURCC_RGBO:
1298
0
      r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1299
0
                         dst_sample_stride ? dst_sample_stride : width * 2,
1300
0
                         width, height);
1301
0
      break;
1302
0
    case FOURCC_R444:
1303
0
      r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1304
0
                         dst_sample_stride ? dst_sample_stride : width * 2,
1305
0
                         width, height);
1306
0
      break;
1307
0
    case FOURCC_24BG:
1308
0
      r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1309
0
                      dst_sample_stride ? dst_sample_stride : width * 3, width,
1310
0
                      height);
1311
0
      break;
1312
0
    case FOURCC_RAW:
1313
0
      r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1314
0
                    dst_sample_stride ? dst_sample_stride : width * 3, width,
1315
0
                    height);
1316
0
      break;
1317
0
    case FOURCC_ARGB:
1318
0
      r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1319
0
                     dst_sample_stride ? dst_sample_stride : width * 4, width,
1320
0
                     height);
1321
0
      break;
1322
0
    case FOURCC_BGRA:
1323
0
      r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1324
0
                     dst_sample_stride ? dst_sample_stride : width * 4, width,
1325
0
                     height);
1326
0
      break;
1327
0
    case FOURCC_ABGR:
1328
0
      r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1329
0
                     dst_sample_stride ? dst_sample_stride : width * 4, width,
1330
0
                     height);
1331
0
      break;
1332
0
    case FOURCC_RGBA:
1333
0
      r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1334
0
                     dst_sample_stride ? dst_sample_stride : width * 4, width,
1335
0
                     height);
1336
0
      break;
1337
0
    case FOURCC_AR30:
1338
0
      r = I420ToAR30(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1339
0
                     dst_sample_stride ? dst_sample_stride : width * 4, width,
1340
0
                     height);
1341
0
      break;
1342
0
    case FOURCC_I400:
1343
0
      r = I400Copy(y, y_stride, dst_sample,
1344
0
                   dst_sample_stride ? dst_sample_stride : width, width,
1345
0
                   height);
1346
0
      break;
1347
0
    case FOURCC_NV12: {
1348
0
      uint8_t* dst_uv = dst_sample + width * height;
1349
0
      r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1350
0
                     dst_sample_stride ? dst_sample_stride : width, dst_uv,
1351
0
                     dst_sample_stride ? dst_sample_stride : width, width,
1352
0
                     height);
1353
0
      break;
1354
0
    }
1355
0
    case FOURCC_NV21: {
1356
0
      uint8_t* dst_vu = dst_sample + width * height;
1357
0
      r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1358
0
                     dst_sample_stride ? dst_sample_stride : width, dst_vu,
1359
0
                     dst_sample_stride ? dst_sample_stride : width, width,
1360
0
                     height);
1361
0
      break;
1362
0
    }
1363
0
    // TODO(fbarchard): Add M420.
1364
0
    // Triplanar formats
1365
0
    case FOURCC_I420:
1366
0
    case FOURCC_YV12: {
1367
0
      dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1368
0
      int halfstride = (dst_sample_stride + 1) / 2;
1369
0
      int halfheight = (height + 1) / 2;
1370
0
      uint8_t* dst_u;
1371
0
      uint8_t* dst_v;
1372
0
      if (format == FOURCC_YV12) {
1373
0
        dst_v = dst_sample + dst_sample_stride * height;
1374
0
        dst_u = dst_v + halfstride * halfheight;
1375
0
      } else {
1376
0
        dst_u = dst_sample + dst_sample_stride * height;
1377
0
        dst_v = dst_u + halfstride * halfheight;
1378
0
      }
1379
0
      r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1380
0
                   dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1381
0
                   width, height);
1382
0
      break;
1383
0
    }
1384
0
    case FOURCC_I422:
1385
0
    case FOURCC_YV16: {
1386
0
      dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1387
0
      int halfstride = (dst_sample_stride + 1) / 2;
1388
0
      uint8_t* dst_u;
1389
0
      uint8_t* dst_v;
1390
0
      if (format == FOURCC_YV16) {
1391
0
        dst_v = dst_sample + dst_sample_stride * height;
1392
0
        dst_u = dst_v + halfstride * height;
1393
0
      } else {
1394
0
        dst_u = dst_sample + dst_sample_stride * height;
1395
0
        dst_v = dst_u + halfstride * height;
1396
0
      }
1397
0
      r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1398
0
                     dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1399
0
                     width, height);
1400
0
      break;
1401
0
    }
1402
0
    case FOURCC_I444:
1403
0
    case FOURCC_YV24: {
1404
0
      dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1405
0
      uint8_t* dst_u;
1406
0
      uint8_t* dst_v;
1407
0
      if (format == FOURCC_YV24) {
1408
0
        dst_v = dst_sample + dst_sample_stride * height;
1409
0
        dst_u = dst_v + dst_sample_stride * height;
1410
0
      } else {
1411
0
        dst_u = dst_sample + dst_sample_stride * height;
1412
0
        dst_v = dst_u + dst_sample_stride * height;
1413
0
      }
1414
0
      r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1415
0
                     dst_sample_stride, dst_u, dst_sample_stride, dst_v,
1416
0
                     dst_sample_stride, width, height);
1417
0
      break;
1418
0
    }
1419
0
    // Formats not supported - MJPG, biplanar, some rgb formats.
1420
0
    default:
1421
0
      return -1;  // unknown fourcc - return failure code.
1422
0
  }
1423
0
  return r;
1424
0
}
1425
1426
#ifdef __cplusplus
1427
}  // extern "C"
1428
}  // namespace libyuv
1429
#endif