convert_from.cc 36.7 KB
Newer Older
1
/*
2
 *  Copyright 2012 The LibYuv Project Authors. All rights reserved.
3 4 5 6
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
7
 *  in the file PATENTS. All contributing project authors may
8 9 10 11 12 13 14 15 16 17
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "libyuv/convert_from.h"

#include "libyuv/basic_types.h"
#include "libyuv/convert.h"  // For I420Copy
#include "libyuv/cpu_id.h"
#include "libyuv/planar_functions.h"
#include "libyuv/rotate.h"
18
#include "libyuv/scale.h"  // For ScalePlane()
19
#include "libyuv/video_common.h"
20
#include "libyuv/row.h"
21 22 23 24 25 26

#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif

27 28 29 30 31 32
#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
static __inline int Abs(int v) {
  return v >= 0 ? v : -v;
}

// I420 To any I4xx YUV format with mirroring.
Frank Barchard's avatar
Frank Barchard committed
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
static int I420ToI4xx(const uint8* src_y,
                      int src_stride_y,
                      const uint8* src_u,
                      int src_stride_u,
                      const uint8* src_v,
                      int src_stride_v,
                      uint8* dst_y,
                      int dst_stride_y,
                      uint8* dst_u,
                      int dst_stride_u,
                      uint8* dst_v,
                      int dst_stride_v,
                      int src_y_width,
                      int src_y_height,
                      int dst_uv_width,
                      int dst_uv_height) {
49 50 51 52
  const int dst_y_width = Abs(src_y_width);
  const int dst_y_height = Abs(src_y_height);
  const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
  const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
Frank Barchard's avatar
Frank Barchard committed
53 54
  if (src_y_width == 0 || src_y_height == 0 || dst_uv_width <= 0 ||
      dst_uv_height <= 0) {
55 56
    return -1;
  }
57
  if (dst_y) {
Frank Barchard's avatar
Frank Barchard committed
58 59 60 61 62 63 64
    ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
               dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
  }
  ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
             dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
  ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
             dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
65 66 67
  return 0;
}

68 69
// 420 chroma is 1/2 width, 1/2 height
// 422 chroma is 1/2 width, 1x height
70
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84
int I420ToI422(const uint8* src_y,
               int src_stride_y,
               const uint8* src_u,
               int src_stride_u,
               const uint8* src_v,
               int src_stride_v,
               uint8* dst_y,
               int dst_stride_y,
               uint8* dst_u,
               int dst_stride_u,
               uint8* dst_v,
               int dst_stride_v,
               int width,
               int height) {
85 86
  const int dst_uv_width = (Abs(width) + 1) >> 1;
  const int dst_uv_height = Abs(height);
Frank Barchard's avatar
Frank Barchard committed
87 88 89 90
  return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
                    dst_v, dst_stride_v, width, height, dst_uv_width,
                    dst_uv_height);
91 92
}

93 94
// 420 chroma is 1/2 width, 1/2 height
// 444 chroma is 1x width, 1x height
95
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
96 97 98 99 100 101 102 103 104 105 106 107 108 109
int I420ToI444(const uint8* src_y,
               int src_stride_y,
               const uint8* src_u,
               int src_stride_u,
               const uint8* src_v,
               int src_stride_v,
               uint8* dst_y,
               int dst_stride_y,
               uint8* dst_u,
               int dst_stride_u,
               uint8* dst_v,
               int dst_stride_v,
               int width,
               int height) {
110 111
  const int dst_uv_width = Abs(width);
  const int dst_uv_height = Abs(height);
Frank Barchard's avatar
Frank Barchard committed
112 113 114 115
  return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
                    src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
                    dst_v, dst_stride_v, width, height, dst_uv_width,
                    dst_uv_height);
116 117
}

118
// Copy to I400. Source can be I420,422,444,400,NV12,NV21
119
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
120 121 122 123 124 125 126
int I400Copy(const uint8* src_y,
             int src_stride_y,
             uint8* dst_y,
             int dst_stride_y,
             int width,
             int height) {
  if (!src_y || !dst_y || width <= 0 || height == 0) {
127 128
    return -1;
  }
129 130 131 132 133 134 135 136 137 138
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
    src_y = src_y + (height - 1) * src_stride_y;
    src_stride_y = -src_stride_y;
  }
  CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  return 0;
}

139
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
140 141 142 143 144 145 146 147 148 149
int I422ToYUY2(const uint8* src_y,
               int src_stride_y,
               const uint8* src_u,
               int src_stride_u,
               const uint8* src_v,
               int src_stride_v,
               uint8* dst_yuy2,
               int dst_stride_yuy2,
               int width,
               int height) {
150 151 152 153
  int y;
  void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
                        const uint8* src_v, uint8* dst_yuy2, int width) =
      I422ToYUY2Row_C;
Frank Barchard's avatar
Frank Barchard committed
154
  if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
155 156 157 158 159
    return -1;
  }
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
160 161
    dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
    dst_stride_yuy2 = -dst_stride_yuy2;
162
  }
163
  // Coalesce rows.
Frank Barchard's avatar
Frank Barchard committed
164 165
  if (src_stride_y == width && src_stride_u * 2 == width &&
      src_stride_v * 2 == width && dst_stride_yuy2 == width * 2) {
166 167 168
    width *= height;
    height = 1;
    src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
169
  }
170
#if defined(HAS_I422TOYUY2ROW_SSE2)
171
  if (TestCpuFlag(kCpuHasSSE2)) {
172 173 174 175
    I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
    if (IS_ALIGNED(width, 16)) {
      I422ToYUY2Row = I422ToYUY2Row_SSE2;
    }
176
  }
177 178
#endif
#if defined(HAS_I422TOYUY2ROW_NEON)
179
  if (TestCpuFlag(kCpuHasNEON)) {
180 181 182 183
    I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
    if (IS_ALIGNED(width, 16)) {
      I422ToYUY2Row = I422ToYUY2Row_NEON;
    }
fbarchard@google.com's avatar
fbarchard@google.com committed
184
  }
185 186
#endif

187
  for (y = 0; y < height; ++y) {
188
    I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
189 190 191
    src_y += src_stride_y;
    src_u += src_stride_u;
    src_v += src_stride_v;
192
    dst_yuy2 += dst_stride_yuy2;
193 194 195 196
  }
  return 0;
}

197
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
198 199 200 201 202 203 204 205 206 207
int I420ToYUY2(const uint8* src_y,
               int src_stride_y,
               const uint8* src_u,
               int src_stride_u,
               const uint8* src_v,
               int src_stride_v,
               uint8* dst_yuy2,
               int dst_stride_yuy2,
               int width,
               int height) {
208 209 210 211
  int y;
  void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
                        const uint8* src_v, uint8* dst_yuy2, int width) =
      I422ToYUY2Row_C;
Frank Barchard's avatar
Frank Barchard committed
212
  if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
213 214 215 216 217
    return -1;
  }
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
218 219
    dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
    dst_stride_yuy2 = -dst_stride_yuy2;
220
  }
221
#if defined(HAS_I422TOYUY2ROW_SSE2)
222
  if (TestCpuFlag(kCpuHasSSE2)) {
223 224 225 226
    I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
    if (IS_ALIGNED(width, 16)) {
      I422ToYUY2Row = I422ToYUY2Row_SSE2;
    }
227
  }
228 229
#endif
#if defined(HAS_I422TOYUY2ROW_NEON)
230
  if (TestCpuFlag(kCpuHasNEON)) {
231 232 233 234
    I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
    if (IS_ALIGNED(width, 16)) {
      I422ToYUY2Row = I422ToYUY2Row_NEON;
    }
fbarchard@google.com's avatar
fbarchard@google.com committed
235
  }
236
#endif
237 238 239 240 241 242 243 244
#if defined(HAS_I422TOYUY2ROW_MSA)
  if (TestCpuFlag(kCpuHasMSA)) {
    I422ToYUY2Row = I422ToYUY2Row_Any_MSA;
    if (IS_ALIGNED(width, 32)) {
      I422ToYUY2Row = I422ToYUY2Row_MSA;
    }
  }
#endif
245

246
  for (y = 0; y < height - 1; y += 2) {
247
    I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
248
    I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
249
                  dst_yuy2 + dst_stride_yuy2, width);
250 251 252
    src_y += src_stride_y * 2;
    src_u += src_stride_u;
    src_v += src_stride_v;
253
    dst_yuy2 += dst_stride_yuy2 * 2;
254 255
  }
  if (height & 1) {
256
    I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
257 258 259 260
  }
  return 0;
}

261
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
262 263 264 265 266 267 268 269 270 271
int I422ToUYVY(const uint8* src_y,
               int src_stride_y,
               const uint8* src_u,
               int src_stride_u,
               const uint8* src_v,
               int src_stride_v,
               uint8* dst_uyvy,
               int dst_stride_uyvy,
               int width,
               int height) {
272 273 274 275
  int y;
  void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
                        const uint8* src_v, uint8* dst_uyvy, int width) =
      I422ToUYVYRow_C;
Frank Barchard's avatar
Frank Barchard committed
276
  if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
277 278 279 280 281
    return -1;
  }
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
282 283
    dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
    dst_stride_uyvy = -dst_stride_uyvy;
284
  }
285
  // Coalesce rows.
Frank Barchard's avatar
Frank Barchard committed
286 287
  if (src_stride_y == width && src_stride_u * 2 == width &&
      src_stride_v * 2 == width && dst_stride_uyvy == width * 2) {
288 289 290
    width *= height;
    height = 1;
    src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
291
  }
292
#if defined(HAS_I422TOUYVYROW_SSE2)
293
  if (TestCpuFlag(kCpuHasSSE2)) {
294 295 296 297
    I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
    if (IS_ALIGNED(width, 16)) {
      I422ToUYVYRow = I422ToUYVYRow_SSE2;
    }
298
  }
299 300
#endif
#if defined(HAS_I422TOUYVYROW_NEON)
301
  if (TestCpuFlag(kCpuHasNEON)) {
302 303 304 305
    I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
    if (IS_ALIGNED(width, 16)) {
      I422ToUYVYRow = I422ToUYVYRow_NEON;
    }
fbarchard@google.com's avatar
fbarchard@google.com committed
306
  }
307
#endif
308 309 310 311 312 313 314 315
#if defined(HAS_I422TOUYVYROW_MSA)
  if (TestCpuFlag(kCpuHasMSA)) {
    I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
    if (IS_ALIGNED(width, 32)) {
      I422ToUYVYRow = I422ToUYVYRow_MSA;
    }
  }
#endif
316

317
  for (y = 0; y < height; ++y) {
318
    I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
319 320 321
    src_y += src_stride_y;
    src_u += src_stride_u;
    src_v += src_stride_v;
322
    dst_uyvy += dst_stride_uyvy;
323 324 325 326
  }
  return 0;
}

327
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
328 329 330 331 332 333 334 335 336 337
int I420ToUYVY(const uint8* src_y,
               int src_stride_y,
               const uint8* src_u,
               int src_stride_u,
               const uint8* src_v,
               int src_stride_v,
               uint8* dst_uyvy,
               int dst_stride_uyvy,
               int width,
               int height) {
338 339 340 341
  int y;
  void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
                        const uint8* src_v, uint8* dst_uyvy, int width) =
      I422ToUYVYRow_C;
Frank Barchard's avatar
Frank Barchard committed
342
  if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
343 344 345 346 347
    return -1;
  }
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
348 349
    dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
    dst_stride_uyvy = -dst_stride_uyvy;
350
  }
351
#if defined(HAS_I422TOUYVYROW_SSE2)
352
  if (TestCpuFlag(kCpuHasSSE2)) {
353 354 355 356
    I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
    if (IS_ALIGNED(width, 16)) {
      I422ToUYVYRow = I422ToUYVYRow_SSE2;
    }
357
  }
358 359
#endif
#if defined(HAS_I422TOUYVYROW_NEON)
360
  if (TestCpuFlag(kCpuHasNEON)) {
361 362 363 364
    I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
    if (IS_ALIGNED(width, 16)) {
      I422ToUYVYRow = I422ToUYVYRow_NEON;
    }
fbarchard@google.com's avatar
fbarchard@google.com committed
365
  }
366
#endif
367 368 369 370 371 372 373 374
#if defined(HAS_I422TOUYVYROW_MSA)
  if (TestCpuFlag(kCpuHasMSA)) {
    I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
    if (IS_ALIGNED(width, 32)) {
      I422ToUYVYRow = I422ToUYVYRow_MSA;
    }
  }
#endif
375

376
  for (y = 0; y < height - 1; y += 2) {
377
    I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
378
    I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
379
                  dst_uyvy + dst_stride_uyvy, width);
380 381 382
    src_y += src_stride_y * 2;
    src_u += src_stride_u;
    src_v += src_stride_v;
383
    dst_uyvy += dst_stride_uyvy * 2;
384 385
  }
  if (height & 1) {
386
    I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
387 388 389 390
  }
  return 0;
}

391
// TODO(fbarchard): test negative height for invert.
392
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
393 394 395 396 397 398 399 400 401 402 403 404 405 406
int I420ToNV12(const uint8* src_y,
               int src_stride_y,
               const uint8* src_u,
               int src_stride_u,
               const uint8* src_v,
               int src_stride_v,
               uint8* dst_y,
               int dst_stride_y,
               uint8* dst_uv,
               int dst_stride_uv,
               int width,
               int height) {
  if (!src_y || !src_u || !src_v || !dst_y || !dst_uv || width <= 0 ||
      height == 0) {
407 408
    return -1;
  }
409 410
  int halfwidth = (width + 1) / 2;
  int halfheight = height > 0 ? (height + 1) / 2 : (height - 1) / 2;
411 412 413
  if (dst_y) {
    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  }
Frank Barchard's avatar
Frank Barchard committed
414
  MergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv, dst_stride_uv,
415
               halfwidth, halfheight);
416 417 418 419
  return 0;
}

LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
420 421 422 423 424 425 426 427 428 429 430 431 432 433
int I420ToNV21(const uint8* src_y,
               int src_stride_y,
               const uint8* src_u,
               int src_stride_u,
               const uint8* src_v,
               int src_stride_v,
               uint8* dst_y,
               int dst_stride_y,
               uint8* dst_vu,
               int dst_stride_vu,
               int width,
               int height) {
  return I420ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
                    src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
434 435 436
                    width, height);
}

437
// Convert I422 to RGBA with matrix
Frank Barchard's avatar
Frank Barchard committed
438 439 440 441 442 443 444 445
static int I420ToRGBAMatrix(const uint8* src_y,
                            int src_stride_y,
                            const uint8* src_u,
                            int src_stride_u,
                            const uint8* src_v,
                            int src_stride_v,
                            uint8* dst_rgba,
                            int dst_stride_rgba,
446
                            const struct YuvConstants* yuvconstants,
Frank Barchard's avatar
Frank Barchard committed
447 448
                            int width,
                            int height) {
449
  int y;
Frank Barchard's avatar
Frank Barchard committed
450 451 452 453 454
  void (*I422ToRGBARow)(const uint8* y_buf, const uint8* u_buf,
                        const uint8* v_buf, uint8* rgb_buf,
                        const struct YuvConstants* yuvconstants, int width) =
      I422ToRGBARow_C;
  if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) {
455 456 457 458 459 460 461 462
    return -1;
  }
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
    dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
    dst_stride_rgba = -dst_stride_rgba;
  }
463
#if defined(HAS_I422TORGBAROW_SSSE3)
464
  if (TestCpuFlag(kCpuHasSSSE3)) {
465 466
    I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
    if (IS_ALIGNED(width, 8)) {
467
      I422ToRGBARow = I422ToRGBARow_SSSE3;
468 469
    }
  }
470
#endif
471
#if defined(HAS_I422TORGBAROW_AVX2)
472
  if (TestCpuFlag(kCpuHasAVX2)) {
473 474 475 476 477 478
    I422ToRGBARow = I422ToRGBARow_Any_AVX2;
    if (IS_ALIGNED(width, 16)) {
      I422ToRGBARow = I422ToRGBARow_AVX2;
    }
  }
#endif
479
#if defined(HAS_I422TORGBAROW_NEON)
480
  if (TestCpuFlag(kCpuHasNEON)) {
481 482 483 484 485
    I422ToRGBARow = I422ToRGBARow_Any_NEON;
    if (IS_ALIGNED(width, 8)) {
      I422ToRGBARow = I422ToRGBARow_NEON;
    }
  }
486
#endif
487 488
#if defined(HAS_I422TORGBAROW_DSPR2)
  if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
489 490 491 492
      IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
      IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
      IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
      IS_ALIGNED(dst_rgba, 4) && IS_ALIGNED(dst_stride_rgba, 4)) {
493
    I422ToRGBARow = I422ToRGBARow_DSPR2;
494 495
  }
#endif
496 497 498 499 500 501 502 503
#if defined(HAS_I422TORGBAROW_MSA)
  if (TestCpuFlag(kCpuHasMSA)) {
    I422ToRGBARow = I422ToRGBARow_Any_MSA;
    if (IS_ALIGNED(width, 8)) {
      I422ToRGBARow = I422ToRGBARow_MSA;
    }
  }
#endif
504

505
  for (y = 0; y < height; ++y) {
506
    I422ToRGBARow(src_y, src_u, src_v, dst_rgba, yuvconstants, width);
507 508 509 510 511 512 513 514 515 516
    dst_rgba += dst_stride_rgba;
    src_y += src_stride_y;
    if (y & 1) {
      src_u += src_stride_u;
      src_v += src_stride_v;
    }
  }
  return 0;
}

517
// Convert I420 to RGBA.
518
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
519 520 521 522 523 524 525 526 527 528 529 530 531
int I420ToRGBA(const uint8* src_y,
               int src_stride_y,
               const uint8* src_u,
               int src_stride_u,
               const uint8* src_v,
               int src_stride_v,
               uint8* dst_rgba,
               int dst_stride_rgba,
               int width,
               int height) {
  return I420ToRGBAMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
                          src_stride_v, dst_rgba, dst_stride_rgba,
                          &kYuvI601Constants, width, height);
532 533 534 535
}

// Convert I420 to BGRA.
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
536 537 538 539 540 541 542 543 544 545 546 547 548
int I420ToBGRA(const uint8* src_y,
               int src_stride_y,
               const uint8* src_u,
               int src_stride_u,
               const uint8* src_v,
               int src_stride_v,
               uint8* dst_bgra,
               int dst_stride_bgra,
               int width,
               int height) {
  return I420ToRGBAMatrix(src_y, src_stride_y, src_v,
                          src_stride_v,  // Swap U and V
                          src_u, src_stride_u, dst_bgra, dst_stride_bgra,
549
                          &kYvuI601Constants,  // Use Yvu matrix
550 551 552 553
                          width, height);
}

// Convert I420 to RGB24 with matrix
Frank Barchard's avatar
Frank Barchard committed
554 555 556 557 558 559 560 561
static int I420ToRGB24Matrix(const uint8* src_y,
                             int src_stride_y,
                             const uint8* src_u,
                             int src_stride_u,
                             const uint8* src_v,
                             int src_stride_v,
                             uint8* dst_rgb24,
                             int dst_stride_rgb24,
562
                             const struct YuvConstants* yuvconstants,
Frank Barchard's avatar
Frank Barchard committed
563 564
                             int width,
                             int height) {
565
  int y;
Frank Barchard's avatar
Frank Barchard committed
566 567 568 569 570
  void (*I422ToRGB24Row)(const uint8* y_buf, const uint8* u_buf,
                         const uint8* v_buf, uint8* rgb_buf,
                         const struct YuvConstants* yuvconstants, int width) =
      I422ToRGB24Row_C;
  if (!src_y || !src_u || !src_v || !dst_rgb24 || width <= 0 || height == 0) {
571 572
    return -1;
  }
573 574 575
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
576 577 578
    dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
    dst_stride_rgb24 = -dst_stride_rgb24;
  }
579
#if defined(HAS_I422TORGB24ROW_SSSE3)
580
  if (TestCpuFlag(kCpuHasSSSE3)) {
581
    I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
582
    if (IS_ALIGNED(width, 8)) {
583
      I422ToRGB24Row = I422ToRGB24Row_SSSE3;
584 585
    }
  }
586
#endif
587 588 589 590 591 592 593 594
#if defined(HAS_I422TORGB24ROW_AVX2)
  if (TestCpuFlag(kCpuHasAVX2)) {
    I422ToRGB24Row = I422ToRGB24Row_Any_AVX2;
    if (IS_ALIGNED(width, 16)) {
      I422ToRGB24Row = I422ToRGB24Row_AVX2;
    }
  }
#endif
595
#if defined(HAS_I422TORGB24ROW_NEON)
596
  if (TestCpuFlag(kCpuHasNEON)) {
597 598 599 600 601
    I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
    if (IS_ALIGNED(width, 8)) {
      I422ToRGB24Row = I422ToRGB24Row_NEON;
    }
  }
602
#endif
603 604 605 606 607 608 609 610
#if defined(HAS_I422TORGB24ROW_MSA)
  if (TestCpuFlag(kCpuHasMSA)) {
    I422ToRGB24Row = I422ToRGB24Row_Any_MSA;
    if (IS_ALIGNED(width, 16)) {
      I422ToRGB24Row = I422ToRGB24Row_MSA;
    }
  }
#endif
611

612
  for (y = 0; y < height; ++y) {
613
    I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, yuvconstants, width);
614
    dst_rgb24 += dst_stride_rgb24;
615 616 617 618 619 620 621 622 623
    src_y += src_stride_y;
    if (y & 1) {
      src_u += src_stride_u;
      src_v += src_stride_v;
    }
  }
  return 0;
}

624
// Convert I420 to RGB24.
625
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
626 627 628 629 630 631 632 633 634 635 636 637 638
int I420ToRGB24(const uint8* src_y,
                int src_stride_y,
                const uint8* src_u,
                int src_stride_u,
                const uint8* src_v,
                int src_stride_v,
                uint8* dst_rgb24,
                int dst_stride_rgb24,
                int width,
                int height) {
  return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
                           src_stride_v, dst_rgb24, dst_stride_rgb24,
                           &kYuvI601Constants, width, height);
639
}
640

641 642
// Convert I420 to RAW.
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
643 644 645 646 647 648 649 650 651 652 653 654 655
int I420ToRAW(const uint8* src_y,
              int src_stride_y,
              const uint8* src_u,
              int src_stride_u,
              const uint8* src_v,
              int src_stride_v,
              uint8* dst_raw,
              int dst_stride_raw,
              int width,
              int height) {
  return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
                           src_stride_v,  // Swap U and V
                           src_u, src_stride_u, dst_raw, dst_stride_raw,
656
                           &kYvuI601Constants,  // Use Yvu matrix
657
                           width, height);
658 659
}

660
// Convert I420 to ARGB1555.
661
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
662 663 664 665 666 667 668 669 670 671
int I420ToARGB1555(const uint8* src_y,
                   int src_stride_y,
                   const uint8* src_u,
                   int src_stride_u,
                   const uint8* src_v,
                   int src_stride_v,
                   uint8* dst_argb1555,
                   int dst_stride_argb1555,
                   int width,
                   int height) {
672
  int y;
Frank Barchard's avatar
Frank Barchard committed
673 674
  void (*I422ToARGB1555Row)(const uint8* y_buf, const uint8* u_buf,
                            const uint8* v_buf, uint8* rgb_buf,
675
                            const struct YuvConstants* yuvconstants,
676
                            int width) = I422ToARGB1555Row_C;
Frank Barchard's avatar
Frank Barchard committed
677 678
  if (!src_y || !src_u || !src_v || !dst_argb1555 || width <= 0 ||
      height == 0) {
679 680
    return -1;
  }
681 682 683
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
684 685
    dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
    dst_stride_argb1555 = -dst_stride_argb1555;
686
  }
687
#if defined(HAS_I422TOARGB1555ROW_SSSE3)
688
  if (TestCpuFlag(kCpuHasSSSE3)) {
689
    I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
690
    if (IS_ALIGNED(width, 8)) {
691
      I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
692
    }
693
  }
694
#endif
695 696 697 698 699 700 701 702
#if defined(HAS_I422TOARGB1555ROW_AVX2)
  if (TestCpuFlag(kCpuHasAVX2)) {
    I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2;
    if (IS_ALIGNED(width, 16)) {
      I422ToARGB1555Row = I422ToARGB1555Row_AVX2;
    }
  }
#endif
703
#if defined(HAS_I422TOARGB1555ROW_NEON)
704
  if (TestCpuFlag(kCpuHasNEON)) {
705
    I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
706
    if (IS_ALIGNED(width, 8)) {
707
      I422ToARGB1555Row = I422ToARGB1555Row_NEON;
708 709
    }
  }
710
#endif
711 712 713 714 715 716 717 718
#if defined(HAS_I422TOARGB1555ROW_MSA)
  if (TestCpuFlag(kCpuHasMSA)) {
    I422ToARGB1555Row = I422ToARGB1555Row_Any_MSA;
    if (IS_ALIGNED(width, 8)) {
      I422ToARGB1555Row = I422ToARGB1555Row_MSA;
    }
  }
#endif
719

720
  for (y = 0; y < height; ++y) {
721
    I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, &kYuvI601Constants,
722
                      width);
723
    dst_argb1555 += dst_stride_argb1555;
724 725 726 727 728 729 730 731 732
    src_y += src_stride_y;
    if (y & 1) {
      src_u += src_stride_u;
      src_v += src_stride_v;
    }
  }
  return 0;
}

733
// Convert I420 to ARGB4444.
734
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
735 736 737 738 739 740 741 742 743 744
int I420ToARGB4444(const uint8* src_y,
                   int src_stride_y,
                   const uint8* src_u,
                   int src_stride_u,
                   const uint8* src_v,
                   int src_stride_v,
                   uint8* dst_argb4444,
                   int dst_stride_argb4444,
                   int width,
                   int height) {
745
  int y;
Frank Barchard's avatar
Frank Barchard committed
746 747
  void (*I422ToARGB4444Row)(const uint8* y_buf, const uint8* u_buf,
                            const uint8* v_buf, uint8* rgb_buf,
748
                            const struct YuvConstants* yuvconstants,
749
                            int width) = I422ToARGB4444Row_C;
Frank Barchard's avatar
Frank Barchard committed
750 751
  if (!src_y || !src_u || !src_v || !dst_argb4444 || width <= 0 ||
      height == 0) {
752 753
    return -1;
  }
754 755 756
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
757 758
    dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
    dst_stride_argb4444 = -dst_stride_argb4444;
759
  }
760
#if defined(HAS_I422TOARGB4444ROW_SSSE3)
761
  if (TestCpuFlag(kCpuHasSSSE3)) {
762
    I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
763
    if (IS_ALIGNED(width, 8)) {
764
      I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
765
    }
766
  }
767
#endif
768 769 770 771 772 773 774 775
#if defined(HAS_I422TOARGB4444ROW_AVX2)
  if (TestCpuFlag(kCpuHasAVX2)) {
    I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2;
    if (IS_ALIGNED(width, 16)) {
      I422ToARGB4444Row = I422ToARGB4444Row_AVX2;
    }
  }
#endif
776
#if defined(HAS_I422TOARGB4444ROW_NEON)
777
  if (TestCpuFlag(kCpuHasNEON)) {
778 779 780
    I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
    if (IS_ALIGNED(width, 8)) {
      I422ToARGB4444Row = I422ToARGB4444Row_NEON;
781 782
    }
  }
783
#endif
784 785 786 787 788 789 790 791
#if defined(HAS_I422TOARGB4444ROW_MSA)
  if (TestCpuFlag(kCpuHasMSA)) {
    I422ToARGB4444Row = I422ToARGB4444Row_Any_MSA;
    if (IS_ALIGNED(width, 8)) {
      I422ToARGB4444Row = I422ToARGB4444Row_MSA;
    }
  }
#endif
792

793
  for (y = 0; y < height; ++y) {
794
    I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, &kYuvI601Constants,
795
                      width);
796
    dst_argb4444 += dst_stride_argb4444;
797 798 799 800 801 802 803 804 805
    src_y += src_stride_y;
    if (y & 1) {
      src_u += src_stride_u;
      src_v += src_stride_v;
    }
  }
  return 0;
}

806
// Convert I420 to RGB565.
807
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
808 809 810 811 812 813 814 815 816 817
int I420ToRGB565(const uint8* src_y,
                 int src_stride_y,
                 const uint8* src_u,
                 int src_stride_u,
                 const uint8* src_v,
                 int src_stride_v,
                 uint8* dst_rgb565,
                 int dst_stride_rgb565,
                 int width,
                 int height) {
818
  int y;
Frank Barchard's avatar
Frank Barchard committed
819 820 821 822 823
  void (*I422ToRGB565Row)(const uint8* y_buf, const uint8* u_buf,
                          const uint8* v_buf, uint8* rgb_buf,
                          const struct YuvConstants* yuvconstants, int width) =
      I422ToRGB565Row_C;
  if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
824 825
    return -1;
  }
826 827 828
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
829 830
    dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
    dst_stride_rgb565 = -dst_stride_rgb565;
831
  }
832
#if defined(HAS_I422TORGB565ROW_SSSE3)
833
  if (TestCpuFlag(kCpuHasSSSE3)) {
834
    I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
835
    if (IS_ALIGNED(width, 8)) {
836
      I422ToRGB565Row = I422ToRGB565Row_SSSE3;
837
    }
838
  }
839
#endif
840 841 842 843 844 845 846 847
#if defined(HAS_I422TORGB565ROW_AVX2)
  if (TestCpuFlag(kCpuHasAVX2)) {
    I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
    if (IS_ALIGNED(width, 16)) {
      I422ToRGB565Row = I422ToRGB565Row_AVX2;
    }
  }
#endif
848
#if defined(HAS_I422TORGB565ROW_NEON)
849
  if (TestCpuFlag(kCpuHasNEON)) {
850 851 852
    I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
    if (IS_ALIGNED(width, 8)) {
      I422ToRGB565Row = I422ToRGB565Row_NEON;
853 854
    }
  }
855
#endif
856 857 858 859 860 861 862 863
#if defined(HAS_I422TORGB565ROW_MSA)
  if (TestCpuFlag(kCpuHasMSA)) {
    I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
    if (IS_ALIGNED(width, 8)) {
      I422ToRGB565Row = I422ToRGB565Row_MSA;
    }
  }
#endif
864

865
  for (y = 0; y < height; ++y) {
866
    I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
867
    dst_rgb565 += dst_stride_rgb565;
868 869 870 871 872 873 874 875 876
    src_y += src_stride_y;
    if (y & 1) {
      src_u += src_stride_u;
      src_v += src_stride_v;
    }
  }
  return 0;
}

877 878
// Ordered 8x8 dither for 888 to 565.  Values from 0 to 7.
static const uint8 kDither565_4x4[16] = {
Frank Barchard's avatar
Frank Barchard committed
879
    0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
880 881 882 883
};

// Convert I420 to RGB565 with dithering.
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
884 885 886 887 888 889 890 891 892 893 894
int I420ToRGB565Dither(const uint8* src_y,
                       int src_stride_y,
                       const uint8* src_u,
                       int src_stride_u,
                       const uint8* src_v,
                       int src_stride_v,
                       uint8* dst_rgb565,
                       int dst_stride_rgb565,
                       const uint8* dither4x4,
                       int width,
                       int height) {
895
  int y;
Frank Barchard's avatar
Frank Barchard committed
896 897 898 899
  void (*I422ToARGBRow)(const uint8* y_buf, const uint8* u_buf,
                        const uint8* v_buf, uint8* rgb_buf,
                        const struct YuvConstants* yuvconstants, int width) =
      I422ToARGBRow_C;
900
  void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb,
Frank Barchard's avatar
Frank Barchard committed
901 902 903
                                const uint32 dither4, int width) =
      ARGBToRGB565DitherRow_C;
  if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938
    return -1;
  }
  // Negative height means invert the image.
  if (height < 0) {
    height = -height;
    dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
    dst_stride_rgb565 = -dst_stride_rgb565;
  }
  if (!dither4x4) {
    dither4x4 = kDither565_4x4;
  }
#if defined(HAS_I422TOARGBROW_SSSE3)
  if (TestCpuFlag(kCpuHasSSSE3)) {
    I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
    if (IS_ALIGNED(width, 8)) {
      I422ToARGBRow = I422ToARGBRow_SSSE3;
    }
  }
#endif
#if defined(HAS_I422TOARGBROW_AVX2)
  if (TestCpuFlag(kCpuHasAVX2)) {
    I422ToARGBRow = I422ToARGBRow_Any_AVX2;
    if (IS_ALIGNED(width, 16)) {
      I422ToARGBRow = I422ToARGBRow_AVX2;
    }
  }
#endif
#if defined(HAS_I422TOARGBROW_NEON)
  if (TestCpuFlag(kCpuHasNEON)) {
    I422ToARGBRow = I422ToARGBRow_Any_NEON;
    if (IS_ALIGNED(width, 8)) {
      I422ToARGBRow = I422ToARGBRow_NEON;
    }
  }
#endif
939 940
#if defined(HAS_I422TOARGBROW_DSPR2)
  if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
941 942 943
      IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
      IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
      IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2)) {
944
    I422ToARGBRow = I422ToARGBRow_DSPR2;
945 946
  }
#endif
947 948 949 950 951 952 953 954
#if defined(HAS_I422TOARGBROW_MSA)
  if (TestCpuFlag(kCpuHasMSA)) {
    I422ToARGBRow = I422ToARGBRow_Any_MSA;
    if (IS_ALIGNED(width, 8)) {
      I422ToARGBRow = I422ToARGBRow_MSA;
    }
  }
#endif
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
#if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
  if (TestCpuFlag(kCpuHasSSE2)) {
    ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
    if (IS_ALIGNED(width, 4)) {
      ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
    }
  }
#endif
#if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
  if (TestCpuFlag(kCpuHasAVX2)) {
    ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
    if (IS_ALIGNED(width, 8)) {
      ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
    }
  }
970 971 972 973 974 975 976 977
#endif
#if defined(HAS_ARGBTORGB565DITHERROW_NEON)
  if (TestCpuFlag(kCpuHasNEON)) {
    ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
    if (IS_ALIGNED(width, 8)) {
      ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
    }
  }
978 979 980 981 982 983 984 985
#endif
#if defined(HAS_ARGBTORGB565DITHERROW_MSA)
  if (TestCpuFlag(kCpuHasMSA)) {
    ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
    if (IS_ALIGNED(width, 8)) {
      ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_MSA;
    }
  }
986 987 988 989 990
#endif
  {
    // Allocate a row of argb.
    align_buffer_64(row_argb, width * 4);
    for (y = 0; y < height; ++y) {
991
      I422ToARGBRow(src_y, src_u, src_v, row_argb, &kYuvI601Constants, width);
992
      ARGBToRGB565DitherRow(row_argb, dst_rgb565,
Frank Barchard's avatar
Frank Barchard committed
993 994
                            *(uint32*)(dither4x4 + ((y & 3) << 2)),
                            width);  // NOLINT
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
      dst_rgb565 += dst_stride_rgb565;
      src_y += src_stride_y;
      if (y & 1) {
        src_u += src_stride_u;
        src_v += src_stride_v;
      }
    }
    free_aligned_buffer_64(row_argb);
  }
  return 0;
}

1007
// Convert I420 to specified format
1008
LIBYUV_API
Frank Barchard's avatar
Frank Barchard committed
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
int ConvertFromI420(const uint8* y,
                    int y_stride,
                    const uint8* u,
                    int u_stride,
                    const uint8* v,
                    int v_stride,
                    uint8* dst_sample,
                    int dst_sample_stride,
                    int width,
                    int height,
1019 1020
                    uint32 fourcc) {
  uint32 format = CanonicalFourCC(fourcc);
1021
  int r = 0;
Frank Barchard's avatar
Frank Barchard committed
1022
  if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
1023 1024 1025 1026 1027
    return -1;
  }
  switch (format) {
    // Single plane formats
    case FOURCC_YUY2:
Frank Barchard's avatar
Frank Barchard committed
1028 1029 1030
      r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                     dst_sample_stride ? dst_sample_stride : width * 2, width,
                     height);
1031 1032
      break;
    case FOURCC_UYVY:
Frank Barchard's avatar
Frank Barchard committed
1033 1034 1035
      r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                     dst_sample_stride ? dst_sample_stride : width * 2, width,
                     height);
1036
      break;
1037
    case FOURCC_RGBP:
Frank Barchard's avatar
Frank Barchard committed
1038 1039 1040
      r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                       dst_sample_stride ? dst_sample_stride : width * 2, width,
                       height);
1041 1042
      break;
    case FOURCC_RGBO:
Frank Barchard's avatar
Frank Barchard committed
1043
      r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1044 1045 1046 1047
                         dst_sample_stride ? dst_sample_stride : width * 2,
                         width, height);
      break;
    case FOURCC_R444:
Frank Barchard's avatar
Frank Barchard committed
1048
      r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1049 1050 1051
                         dst_sample_stride ? dst_sample_stride : width * 2,
                         width, height);
      break;
1052
    case FOURCC_24BG:
Frank Barchard's avatar
Frank Barchard committed
1053 1054 1055
      r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                      dst_sample_stride ? dst_sample_stride : width * 3, width,
                      height);
1056 1057
      break;
    case FOURCC_RAW:
Frank Barchard's avatar
Frank Barchard committed
1058 1059 1060
      r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                    dst_sample_stride ? dst_sample_stride : width * 3, width,
                    height);
1061 1062
      break;
    case FOURCC_ARGB:
Frank Barchard's avatar
Frank Barchard committed
1063 1064 1065
      r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                     dst_sample_stride ? dst_sample_stride : width * 4, width,
                     height);
1066 1067
      break;
    case FOURCC_BGRA:
Frank Barchard's avatar
Frank Barchard committed
1068 1069 1070
      r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                     dst_sample_stride ? dst_sample_stride : width * 4, width,
                     height);
1071 1072
      break;
    case FOURCC_ABGR:
Frank Barchard's avatar
Frank Barchard committed
1073 1074 1075
      r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                     dst_sample_stride ? dst_sample_stride : width * 4, width,
                     height);
1076 1077
      break;
    case FOURCC_RGBA:
Frank Barchard's avatar
Frank Barchard committed
1078 1079 1080
      r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                     dst_sample_stride ? dst_sample_stride : width * 4, width,
                     height);
1081 1082
      break;
    case FOURCC_I400:
Frank Barchard's avatar
Frank Barchard committed
1083 1084 1085
      r = I400Copy(y, y_stride, dst_sample,
                   dst_sample_stride ? dst_sample_stride : width, width,
                   height);
1086
      break;
1087 1088
    case FOURCC_NV12: {
      uint8* dst_uv = dst_sample + width * height;
Frank Barchard's avatar
Frank Barchard committed
1089 1090 1091 1092
      r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                     dst_sample_stride ? dst_sample_stride : width, dst_uv,
                     dst_sample_stride ? dst_sample_stride : width, width,
                     height);
1093 1094 1095 1096
      break;
    }
    case FOURCC_NV21: {
      uint8* dst_vu = dst_sample + width * height;
Frank Barchard's avatar
Frank Barchard committed
1097 1098 1099 1100
      r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                     dst_sample_stride ? dst_sample_stride : width, dst_vu,
                     dst_sample_stride ? dst_sample_stride : width, width,
                     height);
1101 1102
      break;
    }
1103
    // TODO(fbarchard): Add M420.
1104 1105 1106
    // Triplanar formats
    case FOURCC_I420:
    case FOURCC_YV12: {
1107 1108
      dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
      int halfstride = (dst_sample_stride + 1) / 2;
1109 1110 1111
      int halfheight = (height + 1) / 2;
      uint8* dst_u;
      uint8* dst_v;
1112
      if (format == FOURCC_YV12) {
1113 1114
        dst_v = dst_sample + dst_sample_stride * height;
        dst_u = dst_v + halfstride * halfheight;
1115
      } else {
1116 1117
        dst_u = dst_sample + dst_sample_stride * height;
        dst_v = dst_u + halfstride * halfheight;
1118
      }
1119 1120 1121
      r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                   dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
                   width, height);
1122 1123 1124 1125
      break;
    }
    case FOURCC_I422:
    case FOURCC_YV16: {
1126 1127
      dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
      int halfstride = (dst_sample_stride + 1) / 2;
1128 1129
      uint8* dst_u;
      uint8* dst_v;
1130
      if (format == FOURCC_YV16) {
1131 1132
        dst_v = dst_sample + dst_sample_stride * height;
        dst_u = dst_v + halfstride * height;
1133
      } else {
1134 1135
        dst_u = dst_sample + dst_sample_stride * height;
        dst_v = dst_u + halfstride * height;
1136
      }
1137 1138 1139
      r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                     dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
                     width, height);
1140 1141 1142 1143
      break;
    }
    case FOURCC_I444:
    case FOURCC_YV24: {
1144
      dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1145 1146
      uint8* dst_u;
      uint8* dst_v;
1147
      if (format == FOURCC_YV24) {
1148 1149
        dst_v = dst_sample + dst_sample_stride * height;
        dst_u = dst_v + dst_sample_stride * height;
1150
      } else {
1151 1152
        dst_u = dst_sample + dst_sample_stride * height;
        dst_v = dst_u + dst_sample_stride * height;
1153
      }
1154 1155 1156
      r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
                     dst_sample_stride, dst_u, dst_sample_stride, dst_v,
                     dst_sample_stride, width, height);
1157 1158 1159 1160 1161 1162
      break;
    }
    // Formats not supported - MJPG, biplanar, some rgb formats.
    default:
      return -1;  // unknown fourcc - return failure code.
  }
1163
  return r;
1164 1165 1166 1167 1168 1169
}

#ifdef __cplusplus
}  // extern "C"
}  // namespace libyuv
#endif