mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2025-12-06 16:56:55 +08:00
Currently, libyuv supports MIPS SIMD Arch(MSA), but libyuv does not supports MultiMedia Instruction(MMI)(such as loongson3a platform). In order to improve performance of libyuv on loongson3a platform, this provides optimize 98 functions with mmi. BUG=libyuv:804 Change-Id: I8947626009efad769b3103a867363ece25d79629 Reviewed-on: https://chromium-review.googlesource.com/1122064 Commit-Queue: Frank Barchard <fbarchard@chromium.org> Reviewed-by: Frank Barchard <fbarchard@chromium.org>
2296 lines
70 KiB
C++
Executable File
2296 lines
70 KiB
C++
Executable File
/*
|
|
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
|
|
*
|
|
* 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
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "libyuv/convert_argb.h"
|
|
|
|
#include "libyuv/cpu_id.h"
|
|
#ifdef HAVE_JPEG
|
|
#include "libyuv/mjpeg_decoder.h"
|
|
#endif
|
|
#include "libyuv/planar_functions.h" // For CopyPlane and ARGBShuffle.
|
|
#include "libyuv/rotate_argb.h"
|
|
#include "libyuv/row.h"
|
|
#include "libyuv/video_common.h"
|
|
|
|
#ifdef __cplusplus
|
|
namespace libyuv {
|
|
extern "C" {
|
|
#endif
|
|
|
|
// Copy ARGB with optional flipping
|
|
LIBYUV_API
|
|
int ARGBCopy(const uint8_t* src_argb,
|
|
int src_stride_argb,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
if (!src_argb || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_argb = src_argb + (height - 1) * src_stride_argb;
|
|
src_stride_argb = -src_stride_argb;
|
|
}
|
|
|
|
CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb, width * 4,
|
|
height);
|
|
return 0;
|
|
}
|
|
|
|
// Convert I420 to ARGB with matrix
|
|
static int I420ToARGBMatrix(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
|
|
const uint8_t* v_buf, uint8_t* rgb_buf,
|
|
const struct YuvConstants* yuvconstants, int width) =
|
|
I422ToARGBRow_C;
|
|
if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
|
dst_stride_argb = -dst_stride_argb;
|
|
}
|
|
#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
|
|
#if defined(HAS_I422TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
I422ToARGBRow = I422ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I422ToARGBRow = I422ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
|
|
dst_argb += dst_stride_argb;
|
|
src_y += src_stride_y;
|
|
if (y & 1) {
|
|
src_u += src_stride_u;
|
|
src_v += src_stride_v;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert I420 to ARGB.
|
|
LIBYUV_API
|
|
int I420ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
&kYuvI601Constants, width, height);
|
|
}
|
|
|
|
// Convert I420 to ABGR.
|
|
LIBYUV_API
|
|
int I420ToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return I420ToARGBMatrix(src_y, src_stride_y, src_v,
|
|
src_stride_v, // Swap U and V
|
|
src_u, src_stride_u, dst_abgr, dst_stride_abgr,
|
|
&kYvuI601Constants, // Use Yvu matrix
|
|
width, height);
|
|
}
|
|
|
|
// Convert J420 to ARGB.
|
|
LIBYUV_API
|
|
int J420ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
&kYuvJPEGConstants, width, height);
|
|
}
|
|
|
|
// Convert J420 to ABGR.
|
|
LIBYUV_API
|
|
int J420ToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return I420ToARGBMatrix(src_y, src_stride_y, src_v,
|
|
src_stride_v, // Swap U and V
|
|
src_u, src_stride_u, dst_abgr, dst_stride_abgr,
|
|
&kYvuJPEGConstants, // Use Yvu matrix
|
|
width, height);
|
|
}
|
|
|
|
// Convert H420 to ARGB.
|
|
LIBYUV_API
|
|
int H420ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
&kYuvH709Constants, width, height);
|
|
}
|
|
|
|
// Convert H420 to ABGR.
|
|
LIBYUV_API
|
|
int H420ToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return I420ToARGBMatrix(src_y, src_stride_y, src_v,
|
|
src_stride_v, // Swap U and V
|
|
src_u, src_stride_u, dst_abgr, dst_stride_abgr,
|
|
&kYvuH709Constants, // Use Yvu matrix
|
|
width, height);
|
|
}
|
|
|
|
// Convert I422 to ARGB with matrix
|
|
static int I422ToARGBMatrix(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
|
|
const uint8_t* v_buf, uint8_t* rgb_buf,
|
|
const struct YuvConstants* yuvconstants, int width) =
|
|
I422ToARGBRow_C;
|
|
if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
|
dst_stride_argb = -dst_stride_argb;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_y == width && src_stride_u * 2 == width &&
|
|
src_stride_v * 2 == width && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
|
|
}
|
|
#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
|
|
#if defined(HAS_I422TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
I422ToARGBRow = I422ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I422ToARGBRow = I422ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
|
|
dst_argb += dst_stride_argb;
|
|
src_y += src_stride_y;
|
|
src_u += src_stride_u;
|
|
src_v += src_stride_v;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert I422 to ARGB.
|
|
LIBYUV_API
|
|
int I422ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
&kYuvI601Constants, width, height);
|
|
}
|
|
|
|
// Convert I422 to ABGR.
|
|
LIBYUV_API
|
|
int I422ToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return I422ToARGBMatrix(src_y, src_stride_y, src_v,
|
|
src_stride_v, // Swap U and V
|
|
src_u, src_stride_u, dst_abgr, dst_stride_abgr,
|
|
&kYvuI601Constants, // Use Yvu matrix
|
|
width, height);
|
|
}
|
|
|
|
// Convert J422 to ARGB.
|
|
LIBYUV_API
|
|
int J422ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
&kYuvJPEGConstants, width, height);
|
|
}
|
|
|
|
// Convert J422 to ABGR.
|
|
LIBYUV_API
|
|
int J422ToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return I422ToARGBMatrix(src_y, src_stride_y, src_v,
|
|
src_stride_v, // Swap U and V
|
|
src_u, src_stride_u, dst_abgr, dst_stride_abgr,
|
|
&kYvuJPEGConstants, // Use Yvu matrix
|
|
width, height);
|
|
}
|
|
|
|
// Convert H422 to ARGB.
|
|
LIBYUV_API
|
|
int H422ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
&kYuvH709Constants, width, height);
|
|
}
|
|
|
|
// Convert H422 to ABGR.
|
|
LIBYUV_API
|
|
int H422ToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return I422ToARGBMatrix(src_y, src_stride_y, src_v,
|
|
src_stride_v, // Swap U and V
|
|
src_u, src_stride_u, dst_abgr, dst_stride_abgr,
|
|
&kYvuH709Constants, // Use Yvu matrix
|
|
width, height);
|
|
}
|
|
|
|
// Convert 10 bit YUV to ARGB with matrix
|
|
// TODO(fbarchard): Consider passing scale multiplier to I210ToARGB to
|
|
// multiply 10 bit yuv into high bits to allow any number of bits.
|
|
static int I010ToAR30Matrix(const uint16_t* src_y,
|
|
int src_stride_y,
|
|
const uint16_t* src_u,
|
|
int src_stride_u,
|
|
const uint16_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_ar30,
|
|
int dst_stride_ar30,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*I210ToAR30Row)(const uint16_t* y_buf, const uint16_t* u_buf,
|
|
const uint16_t* v_buf, uint8_t* rgb_buf,
|
|
const struct YuvConstants* yuvconstants, int width) =
|
|
I210ToAR30Row_C;
|
|
if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
|
|
dst_stride_ar30 = -dst_stride_ar30;
|
|
}
|
|
#if defined(HAS_I210TOAR30ROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
I210ToAR30Row = I210ToAR30Row_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I210ToAR30Row = I210ToAR30Row_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I210TOAR30ROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
I210ToAR30Row = I210ToAR30Row_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
I210ToAR30Row = I210ToAR30Row_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
for (y = 0; y < height; ++y) {
|
|
I210ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
|
|
dst_ar30 += dst_stride_ar30;
|
|
src_y += src_stride_y;
|
|
if (y & 1) {
|
|
src_u += src_stride_u;
|
|
src_v += src_stride_v;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert I010 to AR30.
|
|
LIBYUV_API
|
|
int I010ToAR30(const uint16_t* src_y,
|
|
int src_stride_y,
|
|
const uint16_t* src_u,
|
|
int src_stride_u,
|
|
const uint16_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_ar30,
|
|
int dst_stride_ar30,
|
|
int width,
|
|
int height) {
|
|
return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_ar30, dst_stride_ar30,
|
|
&kYuvI601Constants, width, height);
|
|
}
|
|
|
|
// Convert H010 to AR30.
|
|
LIBYUV_API
|
|
int H010ToAR30(const uint16_t* src_y,
|
|
int src_stride_y,
|
|
const uint16_t* src_u,
|
|
int src_stride_u,
|
|
const uint16_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_ar30,
|
|
int dst_stride_ar30,
|
|
int width,
|
|
int height) {
|
|
return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_ar30, dst_stride_ar30,
|
|
&kYuvH709Constants, width, height);
|
|
}
|
|
|
|
// Convert I010 to AB30.
|
|
LIBYUV_API
|
|
int I010ToAB30(const uint16_t* src_y,
|
|
int src_stride_y,
|
|
const uint16_t* src_u,
|
|
int src_stride_u,
|
|
const uint16_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_ab30,
|
|
int dst_stride_ab30,
|
|
int width,
|
|
int height) {
|
|
return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
|
|
src_stride_u, dst_ab30, dst_stride_ab30,
|
|
&kYvuI601Constants, width, height);
|
|
}
|
|
|
|
// Convert H010 to AB30.
|
|
LIBYUV_API
|
|
int H010ToAB30(const uint16_t* src_y,
|
|
int src_stride_y,
|
|
const uint16_t* src_u,
|
|
int src_stride_u,
|
|
const uint16_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_ab30,
|
|
int dst_stride_ab30,
|
|
int width,
|
|
int height) {
|
|
return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
|
|
src_stride_u, dst_ab30, dst_stride_ab30,
|
|
&kYvuH709Constants, width, height);
|
|
}
|
|
|
|
// Convert 10 bit YUV to ARGB with matrix
|
|
static int I010ToARGBMatrix(const uint16_t* src_y,
|
|
int src_stride_y,
|
|
const uint16_t* src_u,
|
|
int src_stride_u,
|
|
const uint16_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*I210ToARGBRow)(const uint16_t* y_buf, const uint16_t* u_buf,
|
|
const uint16_t* v_buf, uint8_t* rgb_buf,
|
|
const struct YuvConstants* yuvconstants, int width) =
|
|
I210ToARGBRow_C;
|
|
if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
|
dst_stride_argb = -dst_stride_argb;
|
|
}
|
|
#if defined(HAS_I210TOARGBROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
I210ToARGBRow = I210ToARGBRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I210ToARGBRow = I210ToARGBRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I210TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
I210ToARGBRow = I210ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
I210ToARGBRow = I210ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
for (y = 0; y < height; ++y) {
|
|
I210ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
|
|
dst_argb += dst_stride_argb;
|
|
src_y += src_stride_y;
|
|
if (y & 1) {
|
|
src_u += src_stride_u;
|
|
src_v += src_stride_v;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert I010 to ARGB.
|
|
LIBYUV_API
|
|
int I010ToARGB(const uint16_t* src_y,
|
|
int src_stride_y,
|
|
const uint16_t* src_u,
|
|
int src_stride_u,
|
|
const uint16_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
&kYuvI601Constants, width, height);
|
|
}
|
|
|
|
// Convert I010 to ABGR.
|
|
LIBYUV_API
|
|
int I010ToABGR(const uint16_t* src_y,
|
|
int src_stride_y,
|
|
const uint16_t* src_u,
|
|
int src_stride_u,
|
|
const uint16_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return I010ToARGBMatrix(src_y, src_stride_y, src_v,
|
|
src_stride_v, // Swap U and V
|
|
src_u, src_stride_u, dst_abgr, dst_stride_abgr,
|
|
&kYvuI601Constants, // Use Yvu matrix
|
|
width, height);
|
|
}
|
|
|
|
// Convert H010 to ARGB.
|
|
LIBYUV_API
|
|
int H010ToARGB(const uint16_t* src_y,
|
|
int src_stride_y,
|
|
const uint16_t* src_u,
|
|
int src_stride_u,
|
|
const uint16_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
&kYuvH709Constants, width, height);
|
|
}
|
|
|
|
// Convert H010 to ABGR.
|
|
LIBYUV_API
|
|
int H010ToABGR(const uint16_t* src_y,
|
|
int src_stride_y,
|
|
const uint16_t* src_u,
|
|
int src_stride_u,
|
|
const uint16_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return I010ToARGBMatrix(src_y, src_stride_y, src_v,
|
|
src_stride_v, // Swap U and V
|
|
src_u, src_stride_u, dst_abgr, dst_stride_abgr,
|
|
&kYvuH709Constants, // Use Yvu matrix
|
|
width, height);
|
|
}
|
|
|
|
// Convert I444 to ARGB with matrix
|
|
static int I444ToARGBMatrix(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*I444ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
|
|
const uint8_t* v_buf, uint8_t* rgb_buf,
|
|
const struct YuvConstants* yuvconstants, int width) =
|
|
I444ToARGBRow_C;
|
|
if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
|
dst_stride_argb = -dst_stride_argb;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_y == width && src_stride_u == width && src_stride_v == width &&
|
|
dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
|
|
}
|
|
#if defined(HAS_I444TOARGBROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I444ToARGBRow = I444ToARGBRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I444TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
I444ToARGBRow = I444ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
I444ToARGBRow = I444ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I444TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
I444ToARGBRow = I444ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I444ToARGBRow = I444ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I444TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
I444ToARGBRow = I444ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I444ToARGBRow = I444ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
I444ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
|
|
dst_argb += dst_stride_argb;
|
|
src_y += src_stride_y;
|
|
src_u += src_stride_u;
|
|
src_v += src_stride_v;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert I444 to ARGB.
|
|
LIBYUV_API
|
|
int I444ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
&kYuvI601Constants, width, height);
|
|
}
|
|
|
|
// Convert I444 to ABGR.
|
|
LIBYUV_API
|
|
int I444ToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return I444ToARGBMatrix(src_y, src_stride_y, src_v,
|
|
src_stride_v, // Swap U and V
|
|
src_u, src_stride_u, dst_abgr, dst_stride_abgr,
|
|
&kYvuI601Constants, // Use Yvu matrix
|
|
width, height);
|
|
}
|
|
|
|
// Convert J444 to ARGB.
|
|
LIBYUV_API
|
|
int J444ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
&kYuvJPEGConstants, width, height);
|
|
}
|
|
|
|
// Convert I420 with Alpha to preattenuated ARGB.
|
|
static int I420AlphaToARGBMatrix(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
const uint8_t* src_a,
|
|
int src_stride_a,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height,
|
|
int attenuate) {
|
|
int y;
|
|
void (*I422AlphaToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
|
|
const uint8_t* v_buf, const uint8_t* a_buf,
|
|
uint8_t* dst_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width) = I422AlphaToARGBRow_C;
|
|
void (*ARGBAttenuateRow)(const uint8_t* src_argb, uint8_t* dst_argb,
|
|
int width) = ARGBAttenuateRow_C;
|
|
if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
|
dst_stride_argb = -dst_stride_argb;
|
|
}
|
|
#if defined(HAS_I422ALPHATOARGBROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
I422AlphaToARGBRow = I422AlphaToARGBRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I422AlphaToARGBRow = I422AlphaToARGBRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I422ALPHATOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
I422AlphaToARGBRow = I422AlphaToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
I422AlphaToARGBRow = I422AlphaToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I422ALPHATOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
I422AlphaToARGBRow = I422AlphaToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I422AlphaToARGBRow = I422AlphaToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I422ALPHATOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I422AlphaToARGBRow = I422AlphaToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGBATTENUATEROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 4)) {
|
|
ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGBATTENUATEROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGBATTENUATEROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
ARGBAttenuateRow = ARGBAttenuateRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGBATTENUATEROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
ARGBAttenuateRow = ARGBAttenuateRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGBATTENUATEROW_MMI)
|
|
if (TestCpuFlag(kCpuHasMMI)) {
|
|
ARGBAttenuateRow = ARGBAttenuateRow_Any_MMI;
|
|
if (IS_ALIGNED(width, 2)) {
|
|
ARGBAttenuateRow = ARGBAttenuateRow_MMI;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
|
|
width);
|
|
if (attenuate) {
|
|
ARGBAttenuateRow(dst_argb, dst_argb, width);
|
|
}
|
|
dst_argb += dst_stride_argb;
|
|
src_a += src_stride_a;
|
|
src_y += src_stride_y;
|
|
if (y & 1) {
|
|
src_u += src_stride_u;
|
|
src_v += src_stride_v;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert I420 with Alpha to ARGB.
|
|
LIBYUV_API
|
|
int I420AlphaToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
const uint8_t* src_a,
|
|
int src_stride_a,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height,
|
|
int attenuate) {
|
|
return I420AlphaToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, src_a, src_stride_a, dst_argb,
|
|
dst_stride_argb, &kYuvI601Constants, width,
|
|
height, attenuate);
|
|
}
|
|
|
|
// Convert I420 with Alpha to ABGR.
|
|
LIBYUV_API
|
|
int I420AlphaToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
const uint8_t* src_a,
|
|
int src_stride_a,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height,
|
|
int attenuate) {
|
|
return I420AlphaToARGBMatrix(
|
|
src_y, src_stride_y, src_v, src_stride_v, // Swap U and V
|
|
src_u, src_stride_u, src_a, src_stride_a, dst_abgr, dst_stride_abgr,
|
|
&kYvuI601Constants, // Use Yvu matrix
|
|
width, height, attenuate);
|
|
}
|
|
|
|
// Convert I400 to ARGB.
|
|
LIBYUV_API
|
|
int I400ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*I400ToARGBRow)(const uint8_t* y_buf, uint8_t* rgb_buf, int width) =
|
|
I400ToARGBRow_C;
|
|
if (!src_y || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
|
dst_stride_argb = -dst_stride_argb;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_y == width && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_y = dst_stride_argb = 0;
|
|
}
|
|
#if defined(HAS_I400TOARGBROW_SSE2)
|
|
if (TestCpuFlag(kCpuHasSSE2)) {
|
|
I400ToARGBRow = I400ToARGBRow_Any_SSE2;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I400ToARGBRow = I400ToARGBRow_SSE2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I400TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
I400ToARGBRow = I400ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
I400ToARGBRow = I400ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I400TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
I400ToARGBRow = I400ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I400ToARGBRow = I400ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I400TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
I400ToARGBRow = I400ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
I400ToARGBRow = I400ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_I400TOARGBROW_MMI)
|
|
if (TestCpuFlag(kCpuHasMMI)) {
|
|
I400ToARGBRow = I400ToARGBRow_Any_MMI;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
I400ToARGBRow = I400ToARGBRow_MMI;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
I400ToARGBRow(src_y, dst_argb, width);
|
|
dst_argb += dst_stride_argb;
|
|
src_y += src_stride_y;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert J400 to ARGB.
|
|
LIBYUV_API
|
|
int J400ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*J400ToARGBRow)(const uint8_t* src_y, uint8_t* dst_argb, int width) =
|
|
J400ToARGBRow_C;
|
|
if (!src_y || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// 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;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_y == width && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_y = dst_stride_argb = 0;
|
|
}
|
|
#if defined(HAS_J400TOARGBROW_SSE2)
|
|
if (TestCpuFlag(kCpuHasSSE2)) {
|
|
J400ToARGBRow = J400ToARGBRow_Any_SSE2;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
J400ToARGBRow = J400ToARGBRow_SSE2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_J400TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
J400ToARGBRow = J400ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
J400ToARGBRow = J400ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_J400TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
J400ToARGBRow = J400ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
J400ToARGBRow = J400ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_J400TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
J400ToARGBRow = J400ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
J400ToARGBRow = J400ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_J400TOARGBROW_MMI)
|
|
if (TestCpuFlag(kCpuHasMMI)) {
|
|
J400ToARGBRow = J400ToARGBRow_Any_MMI;
|
|
if (IS_ALIGNED(width, 4)) {
|
|
J400ToARGBRow = J400ToARGBRow_MMI;
|
|
}
|
|
}
|
|
#endif
|
|
for (y = 0; y < height; ++y) {
|
|
J400ToARGBRow(src_y, dst_argb, width);
|
|
src_y += src_stride_y;
|
|
dst_argb += dst_stride_argb;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Shuffle table for converting BGRA to ARGB.
|
|
static const uvec8 kShuffleMaskBGRAToARGB = {
|
|
3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u};
|
|
|
|
// Shuffle table for converting ABGR to ARGB.
|
|
static const uvec8 kShuffleMaskABGRToARGB = {
|
|
2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u};
|
|
|
|
// Shuffle table for converting RGBA to ARGB.
|
|
static const uvec8 kShuffleMaskRGBAToARGB = {
|
|
1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u};
|
|
|
|
// Convert BGRA to ARGB.
|
|
LIBYUV_API
|
|
int BGRAToARGB(const uint8_t* src_bgra,
|
|
int src_stride_bgra,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
|
|
(const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
|
|
}
|
|
|
|
// Convert ARGB to BGRA (same as BGRAToARGB).
|
|
LIBYUV_API
|
|
int ARGBToBGRA(const uint8_t* src_bgra,
|
|
int src_stride_bgra,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
|
|
(const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
|
|
}
|
|
|
|
// Convert ABGR to ARGB.
|
|
LIBYUV_API
|
|
int ABGRToARGB(const uint8_t* src_abgr,
|
|
int src_stride_abgr,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
|
|
(const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
|
|
}
|
|
|
|
// Convert ARGB to ABGR to (same as ABGRToARGB).
|
|
LIBYUV_API
|
|
int ARGBToABGR(const uint8_t* src_abgr,
|
|
int src_stride_abgr,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
|
|
(const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
|
|
}
|
|
|
|
// Convert RGBA to ARGB.
|
|
LIBYUV_API
|
|
int RGBAToARGB(const uint8_t* src_rgba,
|
|
int src_stride_rgba,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb,
|
|
(const uint8_t*)(&kShuffleMaskRGBAToARGB), width, height);
|
|
}
|
|
|
|
// Convert RGB24 to ARGB.
|
|
LIBYUV_API
|
|
int RGB24ToARGB(const uint8_t* src_rgb24,
|
|
int src_stride_rgb24,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
|
|
RGB24ToARGBRow_C;
|
|
if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
|
|
src_stride_rgb24 = -src_stride_rgb24;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_rgb24 == width * 3 && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_rgb24 = dst_stride_argb = 0;
|
|
}
|
|
#if defined(HAS_RGB24TOARGBROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_RGB24TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
RGB24ToARGBRow = RGB24ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_RGB24TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
RGB24ToARGBRow = RGB24ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_RGB24TOARGBROW_MMI)
|
|
if (TestCpuFlag(kCpuHasMMI)) {
|
|
RGB24ToARGBRow = RGB24ToARGBRow_Any_MMI;
|
|
if (IS_ALIGNED(width, 4)) {
|
|
RGB24ToARGBRow = RGB24ToARGBRow_MMI;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
RGB24ToARGBRow(src_rgb24, dst_argb, width);
|
|
src_rgb24 += src_stride_rgb24;
|
|
dst_argb += dst_stride_argb;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert RAW to ARGB.
|
|
LIBYUV_API
|
|
int RAWToARGB(const uint8_t* src_raw,
|
|
int src_stride_raw,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
|
|
RAWToARGBRow_C;
|
|
if (!src_raw || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_raw = src_raw + (height - 1) * src_stride_raw;
|
|
src_stride_raw = -src_stride_raw;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_raw == width * 3 && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_raw = dst_stride_argb = 0;
|
|
}
|
|
#if defined(HAS_RAWTOARGBROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
RAWToARGBRow = RAWToARGBRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_RAWTOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
RAWToARGBRow = RAWToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
RAWToARGBRow = RAWToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_RAWTOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
RAWToARGBRow = RAWToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
RAWToARGBRow = RAWToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_RAWTOARGBROW_MMI)
|
|
if (TestCpuFlag(kCpuHasMMI)) {
|
|
RAWToARGBRow = RAWToARGBRow_Any_MMI;
|
|
if (IS_ALIGNED(width, 4)) {
|
|
RAWToARGBRow = RAWToARGBRow_MMI;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
RAWToARGBRow(src_raw, dst_argb, width);
|
|
src_raw += src_stride_raw;
|
|
dst_argb += dst_stride_argb;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert RGB565 to ARGB.
|
|
LIBYUV_API
|
|
int RGB565ToARGB(const uint8_t* src_rgb565,
|
|
int src_stride_rgb565,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*RGB565ToARGBRow)(const uint8_t* src_rgb565, uint8_t* dst_argb,
|
|
int width) = RGB565ToARGBRow_C;
|
|
if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
|
|
src_stride_rgb565 = -src_stride_rgb565;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_rgb565 == width * 2 && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_rgb565 = dst_stride_argb = 0;
|
|
}
|
|
#if defined(HAS_RGB565TOARGBROW_SSE2)
|
|
if (TestCpuFlag(kCpuHasSSE2)) {
|
|
RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_RGB565TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_RGB565TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
RGB565ToARGBRow = RGB565ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_RGB565TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
RGB565ToARGBRow = RGB565ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_RGB565TOARGBROW_MMI)
|
|
if (TestCpuFlag(kCpuHasMMI)) {
|
|
RGB565ToARGBRow = RGB565ToARGBRow_Any_MMI;
|
|
if (IS_ALIGNED(width, 4)) {
|
|
RGB565ToARGBRow = RGB565ToARGBRow_MMI;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
RGB565ToARGBRow(src_rgb565, dst_argb, width);
|
|
src_rgb565 += src_stride_rgb565;
|
|
dst_argb += dst_stride_argb;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert ARGB1555 to ARGB.
|
|
LIBYUV_API
|
|
int ARGB1555ToARGB(const uint8_t* src_argb1555,
|
|
int src_stride_argb1555,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*ARGB1555ToARGBRow)(const uint8_t* src_argb1555, uint8_t* dst_argb,
|
|
int width) = ARGB1555ToARGBRow_C;
|
|
if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
|
|
src_stride_argb1555 = -src_stride_argb1555;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_argb1555 == width * 2 && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_argb1555 = dst_stride_argb = 0;
|
|
}
|
|
#if defined(HAS_ARGB1555TOARGBROW_SSE2)
|
|
if (TestCpuFlag(kCpuHasSSE2)) {
|
|
ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGB1555TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGB1555TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGB1555TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
ARGB1555ToARGBRow = ARGB1555ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGB1555TOARGBROW_MMI)
|
|
if (TestCpuFlag(kCpuHasMMI)) {
|
|
ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MMI;
|
|
if (IS_ALIGNED(width, 4)) {
|
|
ARGB1555ToARGBRow = ARGB1555ToARGBRow_MMI;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
|
|
src_argb1555 += src_stride_argb1555;
|
|
dst_argb += dst_stride_argb;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert ARGB4444 to ARGB.
|
|
LIBYUV_API
|
|
int ARGB4444ToARGB(const uint8_t* src_argb4444,
|
|
int src_stride_argb4444,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*ARGB4444ToARGBRow)(const uint8_t* src_argb4444, uint8_t* dst_argb,
|
|
int width) = ARGB4444ToARGBRow_C;
|
|
if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
|
|
src_stride_argb4444 = -src_stride_argb4444;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_argb4444 == width * 2 && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_argb4444 = dst_stride_argb = 0;
|
|
}
|
|
#if defined(HAS_ARGB4444TOARGBROW_SSE2)
|
|
if (TestCpuFlag(kCpuHasSSE2)) {
|
|
ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGB4444TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGB4444TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGB4444TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_ARGB4444TOARGBROW_MMI)
|
|
if (TestCpuFlag(kCpuHasMMI)) {
|
|
ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MMI;
|
|
if (IS_ALIGNED(width, 4)) {
|
|
ARGB4444ToARGBRow = ARGB4444ToARGBRow_MMI;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
|
|
src_argb4444 += src_stride_argb4444;
|
|
dst_argb += dst_stride_argb;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert AR30 to ARGB.
|
|
LIBYUV_API
|
|
int AR30ToARGB(const uint8_t* src_ar30,
|
|
int src_stride_ar30,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
if (!src_ar30 || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
|
|
src_stride_ar30 = -src_stride_ar30;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_ar30 == width * 4 && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_ar30 = dst_stride_argb = 0;
|
|
}
|
|
for (y = 0; y < height; ++y) {
|
|
AR30ToARGBRow_C(src_ar30, dst_argb, width);
|
|
src_ar30 += src_stride_ar30;
|
|
dst_argb += dst_stride_argb;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert AR30 to ABGR.
|
|
LIBYUV_API
|
|
int AR30ToABGR(const uint8_t* src_ar30,
|
|
int src_stride_ar30,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
if (!src_ar30 || !dst_abgr || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
|
|
src_stride_ar30 = -src_stride_ar30;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_ar30 == width * 4 && dst_stride_abgr == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_ar30 = dst_stride_abgr = 0;
|
|
}
|
|
for (y = 0; y < height; ++y) {
|
|
AR30ToABGRRow_C(src_ar30, dst_abgr, width);
|
|
src_ar30 += src_stride_ar30;
|
|
dst_abgr += dst_stride_abgr;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert AR30 to AB30.
|
|
LIBYUV_API
|
|
int AR30ToAB30(const uint8_t* src_ar30,
|
|
int src_stride_ar30,
|
|
uint8_t* dst_ab30,
|
|
int dst_stride_ab30,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
if (!src_ar30 || !dst_ab30 || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
|
|
src_stride_ar30 = -src_stride_ar30;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_ar30 == width * 4 && dst_stride_ab30 == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_ar30 = dst_stride_ab30 = 0;
|
|
}
|
|
for (y = 0; y < height; ++y) {
|
|
AR30ToAB30Row_C(src_ar30, dst_ab30, width);
|
|
src_ar30 += src_stride_ar30;
|
|
dst_ab30 += dst_stride_ab30;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert NV12 to ARGB with matrix
|
|
static int NV12ToARGBMatrix(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_uv,
|
|
int src_stride_uv,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*NV12ToARGBRow)(
|
|
const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
|
|
const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
|
|
if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
|
dst_stride_argb = -dst_stride_argb;
|
|
}
|
|
#if defined(HAS_NV12TOARGBROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV12TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV12TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV12TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
NV12ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
|
|
dst_argb += dst_stride_argb;
|
|
src_y += src_stride_y;
|
|
if (y & 1) {
|
|
src_uv += src_stride_uv;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert NV21 to ARGB with matrix
|
|
static int NV21ToARGBMatrix(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_vu,
|
|
int src_stride_vu,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*NV21ToARGBRow)(
|
|
const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
|
|
const struct YuvConstants* yuvconstants, int width) = NV21ToARGBRow_C;
|
|
if (!src_y || !src_vu || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
|
dst_stride_argb = -dst_stride_argb;
|
|
}
|
|
#if defined(HAS_NV21TOARGBROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV21ToARGBRow = NV21ToARGBRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV21TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
NV21ToARGBRow = NV21ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
NV21ToARGBRow = NV21ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV21TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV21ToARGBRow = NV21ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV21TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
NV21ToARGBRow = NV21ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV21ToARGBRow = NV21ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
NV21ToARGBRow(src_y, src_vu, dst_argb, yuvconstants, width);
|
|
dst_argb += dst_stride_argb;
|
|
src_y += src_stride_y;
|
|
if (y & 1) {
|
|
src_vu += src_stride_vu;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert NV12 to ARGB.
|
|
LIBYUV_API
|
|
int NV12ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_uv,
|
|
int src_stride_uv,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return NV12ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb,
|
|
dst_stride_argb, &kYuvI601Constants, width, height);
|
|
}
|
|
|
|
// Convert NV21 to ARGB.
|
|
LIBYUV_API
|
|
int NV21ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_vu,
|
|
int src_stride_vu,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return NV21ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_argb,
|
|
dst_stride_argb, &kYuvI601Constants, width, height);
|
|
}
|
|
|
|
// Convert NV12 to ABGR.
|
|
// To output ABGR instead of ARGB swap the UV and use a mirrrored yuc matrix.
|
|
// To swap the UV use NV12 instead of NV21.LIBYUV_API
|
|
int NV12ToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_uv,
|
|
int src_stride_uv,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_abgr,
|
|
dst_stride_abgr, &kYvuI601Constants, width, height);
|
|
}
|
|
|
|
// Convert NV21 to ABGR.
|
|
LIBYUV_API
|
|
int NV21ToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_vu,
|
|
int src_stride_vu,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return NV12ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_abgr,
|
|
dst_stride_abgr, &kYvuI601Constants, width, height);
|
|
}
|
|
|
|
// TODO(fbarchard): Consider SSSE3 2 step conversion.
|
|
// Convert NV12 to RGB24 with matrix
|
|
static int NV12ToRGB24Matrix(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_uv,
|
|
int src_stride_uv,
|
|
uint8_t* dst_rgb24,
|
|
int dst_stride_rgb24,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*NV12ToRGB24Row)(
|
|
const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
|
|
const struct YuvConstants* yuvconstants, int width) = NV12ToRGB24Row_C;
|
|
if (!src_y || !src_uv || !dst_rgb24 || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
|
|
dst_stride_rgb24 = -dst_stride_rgb24;
|
|
}
|
|
#if defined(HAS_NV12TORGB24ROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
NV12ToRGB24Row = NV12ToRGB24Row_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV12ToRGB24Row = NV12ToRGB24Row_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV12TORGB24ROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
NV12ToRGB24Row = NV12ToRGB24Row_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
NV12ToRGB24Row = NV12ToRGB24Row_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV12TORGB24ROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
NV12ToRGB24Row = NV12ToRGB24Row_Any_AVX2;
|
|
if (IS_ALIGNED(width, 32)) {
|
|
NV12ToRGB24Row = NV12ToRGB24Row_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
NV12ToRGB24Row(src_y, src_uv, dst_rgb24, yuvconstants, width);
|
|
dst_rgb24 += dst_stride_rgb24;
|
|
src_y += src_stride_y;
|
|
if (y & 1) {
|
|
src_uv += src_stride_uv;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert NV21 to RGB24 with matrix
|
|
static int NV21ToRGB24Matrix(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_vu,
|
|
int src_stride_vu,
|
|
uint8_t* dst_rgb24,
|
|
int dst_stride_rgb24,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*NV21ToRGB24Row)(
|
|
const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
|
|
const struct YuvConstants* yuvconstants, int width) = NV21ToRGB24Row_C;
|
|
if (!src_y || !src_vu || !dst_rgb24 || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
|
|
dst_stride_rgb24 = -dst_stride_rgb24;
|
|
}
|
|
#if defined(HAS_NV21TORGB24ROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
NV21ToRGB24Row = NV21ToRGB24Row_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV21ToRGB24Row = NV21ToRGB24Row_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV21TORGB24ROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
NV21ToRGB24Row = NV21ToRGB24Row_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
NV21ToRGB24Row = NV21ToRGB24Row_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV21TORGB24ROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
NV21ToRGB24Row = NV21ToRGB24Row_Any_AVX2;
|
|
if (IS_ALIGNED(width, 32)) {
|
|
NV21ToRGB24Row = NV21ToRGB24Row_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
NV21ToRGB24Row(src_y, src_vu, dst_rgb24, yuvconstants, width);
|
|
dst_rgb24 += dst_stride_rgb24;
|
|
src_y += src_stride_y;
|
|
if (y & 1) {
|
|
src_vu += src_stride_vu;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// TODO(fbarchard): NV12ToRAW can be implemented by mirrored matrix.
|
|
// Convert NV12 to RGB24.
|
|
LIBYUV_API
|
|
int NV12ToRGB24(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_uv,
|
|
int src_stride_uv,
|
|
uint8_t* dst_rgb24,
|
|
int dst_stride_rgb24,
|
|
int width,
|
|
int height) {
|
|
return NV12ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv,
|
|
dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
|
|
width, height);
|
|
}
|
|
|
|
// Convert NV21 to RGB24.
|
|
LIBYUV_API
|
|
int NV21ToRGB24(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_vu,
|
|
int src_stride_vu,
|
|
uint8_t* dst_rgb24,
|
|
int dst_stride_rgb24,
|
|
int width,
|
|
int height) {
|
|
return NV21ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu,
|
|
dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
|
|
width, height);
|
|
}
|
|
|
|
// Convert M420 to ARGB.
|
|
LIBYUV_API
|
|
int M420ToARGB(const uint8_t* src_m420,
|
|
int src_stride_m420,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*NV12ToARGBRow)(
|
|
const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
|
|
const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
|
|
if (!src_m420 || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
|
dst_stride_argb = -dst_stride_argb;
|
|
}
|
|
#if defined(HAS_NV12TOARGBROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV12TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV12TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_NV12TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
NV12ToARGBRow = NV12ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (y = 0; y < height - 1; y += 2) {
|
|
NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
|
|
&kYuvI601Constants, width);
|
|
NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
|
|
dst_argb + dst_stride_argb, &kYuvI601Constants, width);
|
|
dst_argb += dst_stride_argb * 2;
|
|
src_m420 += src_stride_m420 * 3;
|
|
}
|
|
if (height & 1) {
|
|
NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
|
|
&kYuvI601Constants, width);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert YUY2 to ARGB.
|
|
LIBYUV_API
|
|
int YUY2ToARGB(const uint8_t* src_yuy2,
|
|
int src_stride_yuy2,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*YUY2ToARGBRow)(const uint8_t* src_yuy2, uint8_t* dst_argb,
|
|
const struct YuvConstants* yuvconstants, int width) =
|
|
YUY2ToARGBRow_C;
|
|
if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
|
|
src_stride_yuy2 = -src_stride_yuy2;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_yuy2 = dst_stride_argb = 0;
|
|
}
|
|
#if defined(HAS_YUY2TOARGBROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_YUY2TOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 32)) {
|
|
YUY2ToARGBRow = YUY2ToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_YUY2TOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
YUY2ToARGBRow = YUY2ToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_YUY2TOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
YUY2ToARGBRow = YUY2ToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
for (y = 0; y < height; ++y) {
|
|
YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width);
|
|
src_yuy2 += src_stride_yuy2;
|
|
dst_argb += dst_stride_argb;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Convert UYVY to ARGB.
|
|
LIBYUV_API
|
|
int UYVYToARGB(const uint8_t* src_uyvy,
|
|
int src_stride_uyvy,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
void (*UYVYToARGBRow)(const uint8_t* src_uyvy, uint8_t* dst_argb,
|
|
const struct YuvConstants* yuvconstants, int width) =
|
|
UYVYToARGBRow_C;
|
|
if (!src_uyvy || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
|
|
src_stride_uyvy = -src_stride_uyvy;
|
|
}
|
|
// Coalesce rows.
|
|
if (src_stride_uyvy == width * 2 && dst_stride_argb == width * 4) {
|
|
width *= height;
|
|
height = 1;
|
|
src_stride_uyvy = dst_stride_argb = 0;
|
|
}
|
|
#if defined(HAS_UYVYTOARGBROW_SSSE3)
|
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
|
UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
|
|
if (IS_ALIGNED(width, 16)) {
|
|
UYVYToARGBRow = UYVYToARGBRow_SSSE3;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_UYVYTOARGBROW_AVX2)
|
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
|
UYVYToARGBRow = UYVYToARGBRow_Any_AVX2;
|
|
if (IS_ALIGNED(width, 32)) {
|
|
UYVYToARGBRow = UYVYToARGBRow_AVX2;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_UYVYTOARGBROW_NEON)
|
|
if (TestCpuFlag(kCpuHasNEON)) {
|
|
UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
UYVYToARGBRow = UYVYToARGBRow_NEON;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(HAS_UYVYTOARGBROW_MSA)
|
|
if (TestCpuFlag(kCpuHasMSA)) {
|
|
UYVYToARGBRow = UYVYToARGBRow_Any_MSA;
|
|
if (IS_ALIGNED(width, 8)) {
|
|
UYVYToARGBRow = UYVYToARGBRow_MSA;
|
|
}
|
|
}
|
|
#endif
|
|
for (y = 0; y < height; ++y) {
|
|
UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width);
|
|
src_uyvy += src_stride_uyvy;
|
|
dst_argb += dst_stride_argb;
|
|
}
|
|
return 0;
|
|
}
|
|
static void WeavePixels(const uint8_t* src_u,
|
|
const uint8_t* src_v,
|
|
int src_pixel_stride_uv,
|
|
uint8_t* dst_uv,
|
|
int width) {
|
|
int i;
|
|
for (i = 0; i < width; ++i) {
|
|
dst_uv[0] = *src_u;
|
|
dst_uv[1] = *src_v;
|
|
dst_uv += 2;
|
|
src_u += src_pixel_stride_uv;
|
|
src_v += src_pixel_stride_uv;
|
|
}
|
|
}
|
|
|
|
// Convert Android420 to ARGB.
|
|
LIBYUV_API
|
|
int Android420ToARGBMatrix(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
int src_pixel_stride_uv,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
const struct YuvConstants* yuvconstants,
|
|
int width,
|
|
int height) {
|
|
int y;
|
|
uint8_t* dst_uv;
|
|
const ptrdiff_t vu_off = src_v - src_u;
|
|
int halfwidth = (width + 1) >> 1;
|
|
int halfheight = (height + 1) >> 1;
|
|
if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
|
|
return -1;
|
|
}
|
|
// Negative height means invert the image.
|
|
if (height < 0) {
|
|
height = -height;
|
|
halfheight = (height + 1) >> 1;
|
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
|
dst_stride_argb = -dst_stride_argb;
|
|
}
|
|
|
|
// I420
|
|
if (src_pixel_stride_uv == 1) {
|
|
return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, dst_argb, dst_stride_argb,
|
|
yuvconstants, width, height);
|
|
// NV21
|
|
}
|
|
if (src_pixel_stride_uv == 2 && vu_off == -1 &&
|
|
src_stride_u == src_stride_v) {
|
|
return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb,
|
|
dst_stride_argb, yuvconstants, width, height);
|
|
// NV12
|
|
}
|
|
if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
|
|
return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb,
|
|
dst_stride_argb, yuvconstants, width, height);
|
|
}
|
|
|
|
// General case fallback creates NV12
|
|
align_buffer_64(plane_uv, halfwidth * 2 * halfheight);
|
|
dst_uv = plane_uv;
|
|
for (y = 0; y < halfheight; ++y) {
|
|
WeavePixels(src_u, src_v, src_pixel_stride_uv, dst_uv, halfwidth);
|
|
src_u += src_stride_u;
|
|
src_v += src_stride_v;
|
|
dst_uv += halfwidth * 2;
|
|
}
|
|
NV12ToARGBMatrix(src_y, src_stride_y, plane_uv, halfwidth * 2, dst_argb,
|
|
dst_stride_argb, yuvconstants, width, height);
|
|
free_aligned_buffer_64(plane_uv);
|
|
return 0;
|
|
}
|
|
|
|
// Convert Android420 to ARGB.
|
|
LIBYUV_API
|
|
int Android420ToARGB(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
int src_pixel_stride_uv,
|
|
uint8_t* dst_argb,
|
|
int dst_stride_argb,
|
|
int width,
|
|
int height) {
|
|
return Android420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
|
|
src_stride_v, src_pixel_stride_uv, dst_argb,
|
|
dst_stride_argb, &kYuvI601Constants, width,
|
|
height);
|
|
}
|
|
|
|
// Convert Android420 to ABGR.
|
|
LIBYUV_API
|
|
int Android420ToABGR(const uint8_t* src_y,
|
|
int src_stride_y,
|
|
const uint8_t* src_u,
|
|
int src_stride_u,
|
|
const uint8_t* src_v,
|
|
int src_stride_v,
|
|
int src_pixel_stride_uv,
|
|
uint8_t* dst_abgr,
|
|
int dst_stride_abgr,
|
|
int width,
|
|
int height) {
|
|
return Android420ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
|
|
src_stride_u, src_pixel_stride_uv, dst_abgr,
|
|
dst_stride_abgr, &kYvuI601Constants, width,
|
|
height);
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
} // namespace libyuv
|
|
#endif
|