| /* |
| * 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/planar_functions.h" |
| |
| #include <assert.h> |
| #include <string.h> // for memset() |
| |
| #include "libyuv/cpu_id.h" |
| #include "libyuv/row.h" |
| #include "libyuv/scale_row.h" // for ScaleRowDown2 |
| |
| #ifdef __cplusplus |
| namespace libyuv { |
| extern "C" { |
| #endif |
| |
| // Copy a plane of data |
| LIBYUV_API |
| void CopyPlane(const uint8_t* src_y, |
| int src_stride_y, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height) { |
| int y; |
| void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C; |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_y = dst_y + (height - 1) * dst_stride_y; |
| dst_stride_y = -dst_stride_y; |
| } |
| // Coalesce rows. |
| if (src_stride_y == width && dst_stride_y == width) { |
| width *= height; |
| height = 1; |
| src_stride_y = dst_stride_y = 0; |
| } |
| // Nothing to do. |
| if (src_y == dst_y && src_stride_y == dst_stride_y) { |
| return; |
| } |
| |
| #if defined(HAS_COPYROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2; |
| } |
| #endif |
| #if defined(HAS_COPYROW_AVX) |
| if (TestCpuFlag(kCpuHasAVX)) { |
| CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX; |
| } |
| #endif |
| #if defined(HAS_COPYROW_AVX512BW) |
| if (TestCpuFlag(kCpuHasAVX512BW)) { |
| CopyRow = IS_ALIGNED(width, 128) ? CopyRow_AVX512BW : CopyRow_Any_AVX512BW; |
| } |
| #endif |
| #if defined(HAS_COPYROW_ERMS) |
| if (TestCpuFlag(kCpuHasERMS)) { |
| CopyRow = CopyRow_ERMS; |
| } |
| #endif |
| #if defined(HAS_COPYROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON; |
| } |
| #endif |
| #if defined(HAS_COPYROW_RVV) |
| if (TestCpuFlag(kCpuHasRVV)) { |
| CopyRow = CopyRow_RVV; |
| } |
| #endif |
| |
| // Copy plane |
| for (y = 0; y < height; ++y) { |
| CopyRow(src_y, dst_y, width); |
| src_y += src_stride_y; |
| dst_y += dst_stride_y; |
| } |
| } |
| |
| LIBYUV_API |
| void CopyPlane_16(const uint16_t* src_y, |
| int src_stride_y, |
| uint16_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height) { |
| CopyPlane((const uint8_t*)src_y, src_stride_y * 2, (uint8_t*)dst_y, |
| dst_stride_y * 2, width * 2, height); |
| } |
| |
| // Convert a plane of 16 bit data to 8 bit |
| LIBYUV_API |
| void Convert16To8Plane(const uint16_t* src_y, |
| int src_stride_y, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| int scale, // 16384 for 10 bits |
| int width, |
| int height) { |
| int y; |
| void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale, |
| int width) = Convert16To8Row_C; |
| |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_y = dst_y + (height - 1) * dst_stride_y; |
| dst_stride_y = -dst_stride_y; |
| } |
| // Coalesce rows. |
| if (src_stride_y == width && dst_stride_y == width) { |
| width *= height; |
| height = 1; |
| src_stride_y = dst_stride_y = 0; |
| } |
| #if defined(HAS_CONVERT16TO8ROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| Convert16To8Row = Convert16To8Row_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| Convert16To8Row = Convert16To8Row_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_CONVERT16TO8ROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| Convert16To8Row = Convert16To8Row_Any_SSSE3; |
| if (IS_ALIGNED(width, 16)) { |
| Convert16To8Row = Convert16To8Row_SSSE3; |
| } |
| } |
| #endif |
| #if defined(HAS_CONVERT16TO8ROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| Convert16To8Row = Convert16To8Row_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| Convert16To8Row = Convert16To8Row_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_CONVERT16TO8ROW_AVX512BW) |
| if (TestCpuFlag(kCpuHasAVX512BW)) { |
| Convert16To8Row = Convert16To8Row_Any_AVX512BW; |
| if (IS_ALIGNED(width, 64)) { |
| Convert16To8Row = Convert16To8Row_AVX512BW; |
| } |
| } |
| #endif |
| |
| // Convert plane |
| for (y = 0; y < height; ++y) { |
| Convert16To8Row(src_y, dst_y, scale, width); |
| src_y += src_stride_y; |
| dst_y += dst_stride_y; |
| } |
| } |
| |
| // Convert a plane of 8 bit data to 16 bit |
| LIBYUV_API |
| void Convert8To16Plane(const uint8_t* src_y, |
| int src_stride_y, |
| uint16_t* dst_y, |
| int dst_stride_y, |
| int scale, // 1024 for 10 bits |
| int width, |
| int height) { |
| int y; |
| void (*Convert8To16Row)(const uint8_t* src_y, uint16_t* dst_y, int scale, |
| int width) = Convert8To16Row_C; |
| |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_y = dst_y + (height - 1) * dst_stride_y; |
| dst_stride_y = -dst_stride_y; |
| } |
| // Coalesce rows. |
| if (src_stride_y == width && dst_stride_y == width) { |
| width *= height; |
| height = 1; |
| src_stride_y = dst_stride_y = 0; |
| } |
| #if defined(HAS_CONVERT8TO16ROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| Convert8To16Row = Convert8To16Row_Any_SSE2; |
| if (IS_ALIGNED(width, 16)) { |
| Convert8To16Row = Convert8To16Row_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_CONVERT8TO16ROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| Convert8To16Row = Convert8To16Row_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| Convert8To16Row = Convert8To16Row_AVX2; |
| } |
| } |
| #endif |
| |
| // Convert plane |
| for (y = 0; y < height; ++y) { |
| Convert8To16Row(src_y, dst_y, scale, width); |
| src_y += src_stride_y; |
| dst_y += dst_stride_y; |
| } |
| } |
| |
| // Copy I422. |
| LIBYUV_API |
| int I422Copy(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_y, |
| int dst_stride_y, |
| uint8_t* dst_u, |
| int dst_stride_u, |
| uint8_t* dst_v, |
| int dst_stride_v, |
| int width, |
| int height) { |
| int halfwidth = (width + 1) >> 1; |
| |
| if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || 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_u = src_u + (height - 1) * src_stride_u; |
| src_v = src_v + (height - 1) * src_stride_v; |
| src_stride_y = -src_stride_y; |
| src_stride_u = -src_stride_u; |
| src_stride_v = -src_stride_v; |
| } |
| |
| if (dst_y) { |
| CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| } |
| CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height); |
| CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height); |
| return 0; |
| } |
| |
| // Copy I444. |
| LIBYUV_API |
| int I444Copy(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_y, |
| int dst_stride_y, |
| uint8_t* dst_u, |
| int dst_stride_u, |
| uint8_t* dst_v, |
| int dst_stride_v, |
| int width, |
| int height) { |
| if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || 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_u = src_u + (height - 1) * src_stride_u; |
| src_v = src_v + (height - 1) * src_stride_v; |
| src_stride_y = -src_stride_y; |
| src_stride_u = -src_stride_u; |
| src_stride_v = -src_stride_v; |
| } |
| |
| if (dst_y) { |
| CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| } |
| CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height); |
| CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height); |
| return 0; |
| } |
| |
| // Copy I210. |
| LIBYUV_API |
| int I210Copy(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, |
| uint16_t* dst_y, |
| int dst_stride_y, |
| uint16_t* dst_u, |
| int dst_stride_u, |
| uint16_t* dst_v, |
| int dst_stride_v, |
| int width, |
| int height) { |
| int halfwidth = (width + 1) >> 1; |
| |
| if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || 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_u = src_u + (height - 1) * src_stride_u; |
| src_v = src_v + (height - 1) * src_stride_v; |
| src_stride_y = -src_stride_y; |
| src_stride_u = -src_stride_u; |
| src_stride_v = -src_stride_v; |
| } |
| |
| if (dst_y) { |
| CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| } |
| // Copy UV planes. |
| CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height); |
| CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height); |
| return 0; |
| } |
| |
| // Copy I410. |
| LIBYUV_API |
| int I410Copy(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, |
| uint16_t* dst_y, |
| int dst_stride_y, |
| uint16_t* dst_u, |
| int dst_stride_u, |
| uint16_t* dst_v, |
| int dst_stride_v, |
| int width, |
| int height) { |
| if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || 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_u = src_u + (height - 1) * src_stride_u; |
| src_v = src_v + (height - 1) * src_stride_v; |
| src_stride_y = -src_stride_y; |
| src_stride_u = -src_stride_u; |
| src_stride_v = -src_stride_v; |
| } |
| |
| if (dst_y) { |
| CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| } |
| CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, width, height); |
| CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, width, height); |
| return 0; |
| } |
| |
| // Copy I400. |
| LIBYUV_API |
| int I400ToI400(const uint8_t* src_y, |
| int src_stride_y, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height) { |
| if (!src_y || !dst_y || 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; |
| } |
| CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| return 0; |
| } |
| |
| // Convert I420 to I400. |
| LIBYUV_API |
| int I420ToI400(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_y, |
| int dst_stride_y, |
| int width, |
| int height) { |
| (void)src_u; |
| (void)src_stride_u; |
| (void)src_v; |
| (void)src_stride_v; |
| if (!src_y || !dst_y || 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; |
| } |
| |
| CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| return 0; |
| } |
| |
| // Copy NV12. Supports inverting. |
| LIBYUV_API |
| int NV12Copy(const uint8_t* src_y, |
| int src_stride_y, |
| const uint8_t* src_uv, |
| int src_stride_uv, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| uint8_t* dst_uv, |
| int dst_stride_uv, |
| int width, |
| int height) { |
| int halfwidth = (width + 1) >> 1; |
| int halfheight = (height + 1) >> 1; |
| |
| if (!src_y || !dst_y || !src_uv || !dst_uv || width <= 0 || height == 0) { |
| return -1; |
| } |
| |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| halfheight = (height + 1) >> 1; |
| src_y = src_y + (height - 1) * src_stride_y; |
| src_uv = src_uv + (halfheight - 1) * src_stride_uv; |
| src_stride_y = -src_stride_y; |
| src_stride_uv = -src_stride_uv; |
| } |
| CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| CopyPlane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, halfwidth * 2, |
| halfheight); |
| return 0; |
| } |
| |
| // Copy NV21. Supports inverting. |
| LIBYUV_API |
| int NV21Copy(const uint8_t* src_y, |
| int src_stride_y, |
| const uint8_t* src_vu, |
| int src_stride_vu, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| uint8_t* dst_vu, |
| int dst_stride_vu, |
| int width, |
| int height) { |
| return NV12Copy(src_y, src_stride_y, src_vu, src_stride_vu, dst_y, |
| dst_stride_y, dst_vu, dst_stride_vu, width, height); |
| } |
| |
| // Support function for NV12 etc UV channels. |
| // Width and height are plane sizes (typically half pixel width). |
| LIBYUV_API |
| void SplitUVPlane(const uint8_t* src_uv, |
| int src_stride_uv, |
| uint8_t* dst_u, |
| int dst_stride_u, |
| uint8_t* dst_v, |
| int dst_stride_v, |
| int width, |
| int height) { |
| int y; |
| void (*SplitUVRow)(const uint8_t* src_uv, uint8_t* dst_u, uint8_t* dst_v, |
| int width) = SplitUVRow_C; |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_u = dst_u + (height - 1) * dst_stride_u; |
| dst_v = dst_v + (height - 1) * dst_stride_v; |
| dst_stride_u = -dst_stride_u; |
| dst_stride_v = -dst_stride_v; |
| } |
| // Coalesce rows. |
| if (src_stride_uv == width * 2 && dst_stride_u == width && |
| dst_stride_v == width) { |
| width *= height; |
| height = 1; |
| src_stride_uv = dst_stride_u = dst_stride_v = 0; |
| } |
| #if defined(HAS_SPLITUVROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| SplitUVRow = SplitUVRow_Any_SSE2; |
| if (IS_ALIGNED(width, 16)) { |
| SplitUVRow = SplitUVRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITUVROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| SplitUVRow = SplitUVRow_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| SplitUVRow = SplitUVRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITUVROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| SplitUVRow = SplitUVRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| SplitUVRow = SplitUVRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITUVROW_MSA) |
| if (TestCpuFlag(kCpuHasMSA)) { |
| SplitUVRow = SplitUVRow_Any_MSA; |
| if (IS_ALIGNED(width, 32)) { |
| SplitUVRow = SplitUVRow_MSA; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITUVROW_LSX) |
| if (TestCpuFlag(kCpuHasLSX)) { |
| SplitUVRow = SplitUVRow_Any_LSX; |
| if (IS_ALIGNED(width, 32)) { |
| SplitUVRow = SplitUVRow_LSX; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITUVROW_RVV) |
| if (TestCpuFlag(kCpuHasRVV)) { |
| SplitUVRow = SplitUVRow_RVV; |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| // Copy a row of UV. |
| SplitUVRow(src_uv, dst_u, dst_v, width); |
| dst_u += dst_stride_u; |
| dst_v += dst_stride_v; |
| src_uv += src_stride_uv; |
| } |
| } |
| |
| LIBYUV_API |
| void MergeUVPlane(const uint8_t* src_u, |
| int src_stride_u, |
| const uint8_t* src_v, |
| int src_stride_v, |
| uint8_t* dst_uv, |
| int dst_stride_uv, |
| int width, |
| int height) { |
| int y; |
| void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v, |
| uint8_t* dst_uv, int width) = MergeUVRow_C; |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_uv = dst_uv + (height - 1) * dst_stride_uv; |
| dst_stride_uv = -dst_stride_uv; |
| } |
| // Coalesce rows. |
| if (src_stride_u == width && src_stride_v == width && |
| dst_stride_uv == width * 2) { |
| width *= height; |
| height = 1; |
| src_stride_u = src_stride_v = dst_stride_uv = 0; |
| } |
| #if defined(HAS_MERGEUVROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| MergeUVRow = MergeUVRow_Any_SSE2; |
| if (IS_ALIGNED(width, 16)) { |
| MergeUVRow = MergeUVRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEUVROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MergeUVRow = MergeUVRow_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| MergeUVRow = MergeUVRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEUVROW_AVX512BW) |
| if (TestCpuFlag(kCpuHasAVX512BW)) { |
| MergeUVRow = MergeUVRow_Any_AVX512BW; |
| if (IS_ALIGNED(width, 32)) { |
| MergeUVRow = MergeUVRow_AVX512BW; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEUVROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MergeUVRow = MergeUVRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| MergeUVRow = MergeUVRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEUVROW_MSA) |
| if (TestCpuFlag(kCpuHasMSA)) { |
| MergeUVRow = MergeUVRow_Any_MSA; |
| if (IS_ALIGNED(width, 16)) { |
| MergeUVRow = MergeUVRow_MSA; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEUVROW_LSX) |
| if (TestCpuFlag(kCpuHasLSX)) { |
| MergeUVRow = MergeUVRow_Any_LSX; |
| if (IS_ALIGNED(width, 16)) { |
| MergeUVRow = MergeUVRow_LSX; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEUVROW_RVV) |
| if (TestCpuFlag(kCpuHasRVV)) { |
| MergeUVRow = MergeUVRow_RVV; |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| // Merge a row of U and V into a row of UV. |
| MergeUVRow(src_u, src_v, dst_uv, width); |
| src_u += src_stride_u; |
| src_v += src_stride_v; |
| dst_uv += dst_stride_uv; |
| } |
| } |
| |
| // Support function for P010 etc UV channels. |
| // Width and height are plane sizes (typically half pixel width). |
| LIBYUV_API |
| void SplitUVPlane_16(const uint16_t* src_uv, |
| int src_stride_uv, |
| uint16_t* dst_u, |
| int dst_stride_u, |
| uint16_t* dst_v, |
| int dst_stride_v, |
| int width, |
| int height, |
| int depth) { |
| int y; |
| void (*SplitUVRow_16)(const uint16_t* src_uv, uint16_t* dst_u, |
| uint16_t* dst_v, int depth, int width) = |
| SplitUVRow_16_C; |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_u = dst_u + (height - 1) * dst_stride_u; |
| dst_v = dst_v + (height - 1) * dst_stride_v; |
| dst_stride_u = -dst_stride_u; |
| dst_stride_v = -dst_stride_v; |
| } |
| // Coalesce rows. |
| if (src_stride_uv == width * 2 && dst_stride_u == width && |
| dst_stride_v == width) { |
| width *= height; |
| height = 1; |
| src_stride_uv = dst_stride_u = dst_stride_v = 0; |
| } |
| #if defined(HAS_SPLITUVROW_16_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| SplitUVRow_16 = SplitUVRow_16_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| SplitUVRow_16 = SplitUVRow_16_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITUVROW_16_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| SplitUVRow_16 = SplitUVRow_16_Any_NEON; |
| if (IS_ALIGNED(width, 8)) { |
| SplitUVRow_16 = SplitUVRow_16_NEON; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| // Copy a row of UV. |
| SplitUVRow_16(src_uv, dst_u, dst_v, depth, width); |
| dst_u += dst_stride_u; |
| dst_v += dst_stride_v; |
| src_uv += src_stride_uv; |
| } |
| } |
| |
| LIBYUV_API |
| void MergeUVPlane_16(const uint16_t* src_u, |
| int src_stride_u, |
| const uint16_t* src_v, |
| int src_stride_v, |
| uint16_t* dst_uv, |
| int dst_stride_uv, |
| int width, |
| int height, |
| int depth) { |
| int y; |
| void (*MergeUVRow_16)(const uint16_t* src_u, const uint16_t* src_v, |
| uint16_t* dst_uv, int depth, int width) = |
| MergeUVRow_16_C; |
| assert(depth >= 8); |
| assert(depth <= 16); |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_uv = dst_uv + (height - 1) * dst_stride_uv; |
| dst_stride_uv = -dst_stride_uv; |
| } |
| // Coalesce rows. |
| if (src_stride_u == width && src_stride_v == width && |
| dst_stride_uv == width * 2) { |
| width *= height; |
| height = 1; |
| src_stride_u = src_stride_v = dst_stride_uv = 0; |
| } |
| #if defined(HAS_MERGEUVROW_16_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MergeUVRow_16 = MergeUVRow_16_Any_AVX2; |
| if (IS_ALIGNED(width, 8)) { |
| MergeUVRow_16 = MergeUVRow_16_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEUVROW_16_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MergeUVRow_16 = MergeUVRow_16_Any_NEON; |
| if (IS_ALIGNED(width, 8)) { |
| MergeUVRow_16 = MergeUVRow_16_NEON; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| // Merge a row of U and V into a row of UV. |
| MergeUVRow_16(src_u, src_v, dst_uv, depth, width); |
| src_u += src_stride_u; |
| src_v += src_stride_v; |
| dst_uv += dst_stride_uv; |
| } |
| } |
| |
| // Convert plane from lsb to msb |
| LIBYUV_API |
| void ConvertToMSBPlane_16(const uint16_t* src_y, |
| int src_stride_y, |
| uint16_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height, |
| int depth) { |
| int y; |
| int scale = 1 << (16 - depth); |
| void (*MultiplyRow_16)(const uint16_t* src_y, uint16_t* dst_y, int scale, |
| int width) = MultiplyRow_16_C; |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_y = dst_y + (height - 1) * dst_stride_y; |
| dst_stride_y = -dst_stride_y; |
| } |
| // Coalesce rows. |
| if (src_stride_y == width && dst_stride_y == width) { |
| width *= height; |
| height = 1; |
| src_stride_y = dst_stride_y = 0; |
| } |
| |
| #if defined(HAS_MULTIPLYROW_16_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MultiplyRow_16 = MultiplyRow_16_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| MultiplyRow_16 = MultiplyRow_16_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MULTIPLYROW_16_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MultiplyRow_16 = MultiplyRow_16_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| MultiplyRow_16 = MultiplyRow_16_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_MULTIPLYROW_16_SME) |
| if (TestCpuFlag(kCpuHasSME)) { |
| MultiplyRow_16 = MultiplyRow_16_SME; |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| MultiplyRow_16(src_y, dst_y, scale, width); |
| src_y += src_stride_y; |
| dst_y += dst_stride_y; |
| } |
| } |
| |
| // Convert plane from msb to lsb |
| LIBYUV_API |
| void ConvertToLSBPlane_16(const uint16_t* src_y, |
| int src_stride_y, |
| uint16_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height, |
| int depth) { |
| int y; |
| int scale = 1 << depth; |
| void (*DivideRow)(const uint16_t* src_y, uint16_t* dst_y, int scale, |
| int width) = DivideRow_16_C; |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_y = dst_y + (height - 1) * dst_stride_y; |
| dst_stride_y = -dst_stride_y; |
| } |
| // Coalesce rows. |
| if (src_stride_y == width && dst_stride_y == width) { |
| width *= height; |
| height = 1; |
| src_stride_y = dst_stride_y = 0; |
| } |
| |
| #if defined(HAS_DIVIDEROW_16_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| DivideRow = DivideRow_16_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| DivideRow = DivideRow_16_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_DIVIDEROW_16_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| DivideRow = DivideRow_16_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| DivideRow = DivideRow_16_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_DIVIDEROW_16_SVE2) |
| if (TestCpuFlag(kCpuHasSVE2)) { |
| DivideRow = DivideRow_16_SVE2; |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| DivideRow(src_y, dst_y, scale, width); |
| src_y += src_stride_y; |
| dst_y += dst_stride_y; |
| } |
| } |
| |
| // Swap U and V channels in interleaved UV plane. |
| LIBYUV_API |
| void SwapUVPlane(const uint8_t* src_uv, |
| int src_stride_uv, |
| uint8_t* dst_vu, |
| int dst_stride_vu, |
| int width, |
| int height) { |
| int y; |
| void (*SwapUVRow)(const uint8_t* src_uv, uint8_t* dst_vu, int width) = |
| SwapUVRow_C; |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| src_uv = src_uv + (height - 1) * src_stride_uv; |
| src_stride_uv = -src_stride_uv; |
| } |
| // Coalesce rows. |
| if (src_stride_uv == width * 2 && dst_stride_vu == width * 2) { |
| width *= height; |
| height = 1; |
| src_stride_uv = dst_stride_vu = 0; |
| } |
| |
| #if defined(HAS_SWAPUVROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| SwapUVRow = SwapUVRow_Any_SSSE3; |
| if (IS_ALIGNED(width, 16)) { |
| SwapUVRow = SwapUVRow_SSSE3; |
| } |
| } |
| #endif |
| #if defined(HAS_SWAPUVROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| SwapUVRow = SwapUVRow_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| SwapUVRow = SwapUVRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_SWAPUVROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| SwapUVRow = SwapUVRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| SwapUVRow = SwapUVRow_NEON; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| SwapUVRow(src_uv, dst_vu, width); |
| src_uv += src_stride_uv; |
| dst_vu += dst_stride_vu; |
| } |
| } |
| |
| // Convert NV21 to NV12. |
| LIBYUV_API |
| int NV21ToNV12(const uint8_t* src_y, |
| int src_stride_y, |
| const uint8_t* src_vu, |
| int src_stride_vu, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| uint8_t* dst_uv, |
| int dst_stride_uv, |
| int width, |
| int height) { |
| int halfwidth = (width + 1) >> 1; |
| int halfheight = (height + 1) >> 1; |
| |
| if (!src_vu || !dst_uv || width <= 0 || height == 0) { |
| return -1; |
| } |
| |
| if (dst_y) { |
| CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| } |
| |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| halfheight = (height + 1) >> 1; |
| src_vu = src_vu + (halfheight - 1) * src_stride_vu; |
| src_stride_vu = -src_stride_vu; |
| } |
| |
| SwapUVPlane(src_vu, src_stride_vu, dst_uv, dst_stride_uv, halfwidth, |
| halfheight); |
| return 0; |
| } |
| |
| // Test if tile_height is a power of 2 (16 or 32) |
| #define IS_POWEROFTWO(x) (!((x) & ((x)-1))) |
| |
| // Detile a plane of data |
| // tile width is 16 and assumed. |
| // tile_height is 16 or 32 for MM21. |
| // src_stride_y is bytes per row of source ignoring tiling. e.g. 640 |
| // TODO: More detile row functions. |
| LIBYUV_API |
| int DetilePlane(const uint8_t* src_y, |
| int src_stride_y, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height, |
| int tile_height) { |
| const ptrdiff_t src_tile_stride = 16 * tile_height; |
| int y; |
| void (*DetileRow)(const uint8_t* src, ptrdiff_t src_tile_stride, uint8_t* dst, |
| int width) = DetileRow_C; |
| if (!src_y || !dst_y || width <= 0 || height == 0 || |
| !IS_POWEROFTWO(tile_height)) { |
| return -1; |
| } |
| |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_y = dst_y + (height - 1) * dst_stride_y; |
| dst_stride_y = -dst_stride_y; |
| } |
| |
| #if defined(HAS_DETILEROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| DetileRow = DetileRow_Any_SSE2; |
| if (IS_ALIGNED(width, 16)) { |
| DetileRow = DetileRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_DETILEROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| DetileRow = DetileRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| DetileRow = DetileRow_NEON; |
| } |
| } |
| #endif |
| |
| // Detile plane |
| for (y = 0; y < height; ++y) { |
| DetileRow(src_y, src_tile_stride, dst_y, width); |
| dst_y += dst_stride_y; |
| src_y += 16; |
| // Advance to next row of tiles. |
| if ((y & (tile_height - 1)) == (tile_height - 1)) { |
| src_y = src_y - src_tile_stride + src_stride_y * tile_height; |
| } |
| } |
| return 0; |
| } |
| |
| // Convert a plane of 16 bit tiles of 16 x H to linear. |
| // tile width is 16 and assumed. |
| // tile_height is 16 or 32 for MT2T. |
| LIBYUV_API |
| int DetilePlane_16(const uint16_t* src_y, |
| int src_stride_y, |
| uint16_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height, |
| int tile_height) { |
| const ptrdiff_t src_tile_stride = 16 * tile_height; |
| int y; |
| void (*DetileRow_16)(const uint16_t* src, ptrdiff_t src_tile_stride, |
| uint16_t* dst, int width) = DetileRow_16_C; |
| if (!src_y || !dst_y || width <= 0 || height == 0 || |
| !IS_POWEROFTWO(tile_height)) { |
| return -1; |
| } |
| |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_y = dst_y + (height - 1) * dst_stride_y; |
| dst_stride_y = -dst_stride_y; |
| } |
| |
| #if defined(HAS_DETILEROW_16_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| DetileRow_16 = DetileRow_16_Any_SSE2; |
| if (IS_ALIGNED(width, 16)) { |
| DetileRow_16 = DetileRow_16_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_DETILEROW_16_AVX) |
| if (TestCpuFlag(kCpuHasAVX)) { |
| DetileRow_16 = DetileRow_16_Any_AVX; |
| if (IS_ALIGNED(width, 16)) { |
| DetileRow_16 = DetileRow_16_AVX; |
| } |
| } |
| #endif |
| #if defined(HAS_DETILEROW_16_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| DetileRow_16 = DetileRow_16_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| DetileRow_16 = DetileRow_16_NEON; |
| } |
| } |
| #endif |
| |
| // Detile plane |
| for (y = 0; y < height; ++y) { |
| DetileRow_16(src_y, src_tile_stride, dst_y, width); |
| dst_y += dst_stride_y; |
| src_y += 16; |
| // Advance to next row of tiles. |
| if ((y & (tile_height - 1)) == (tile_height - 1)) { |
| src_y = src_y - src_tile_stride + src_stride_y * tile_height; |
| } |
| } |
| return 0; |
| } |
| |
| LIBYUV_API |
| void DetileSplitUVPlane(const uint8_t* src_uv, |
| int src_stride_uv, |
| uint8_t* dst_u, |
| int dst_stride_u, |
| uint8_t* dst_v, |
| int dst_stride_v, |
| int width, |
| int height, |
| int tile_height) { |
| const ptrdiff_t src_tile_stride = 16 * tile_height; |
| int y; |
| void (*DetileSplitUVRow)(const uint8_t* src, ptrdiff_t src_tile_stride, |
| uint8_t* dst_u, uint8_t* dst_v, int width) = |
| DetileSplitUVRow_C; |
| assert(src_stride_uv >= 0); |
| assert(tile_height > 0); |
| assert(src_stride_uv > 0); |
| |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_u = dst_u + (height - 1) * dst_stride_u; |
| dst_stride_u = -dst_stride_u; |
| dst_v = dst_v + (height - 1) * dst_stride_v; |
| dst_stride_v = -dst_stride_v; |
| } |
| |
| #if defined(HAS_DETILESPLITUVROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| DetileSplitUVRow = DetileSplitUVRow_Any_SSSE3; |
| if (IS_ALIGNED(width, 16)) { |
| DetileSplitUVRow = DetileSplitUVRow_SSSE3; |
| } |
| } |
| #endif |
| #if defined(HAS_DETILESPLITUVROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| DetileSplitUVRow = DetileSplitUVRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| DetileSplitUVRow = DetileSplitUVRow_NEON; |
| } |
| } |
| #endif |
| |
| // Detile plane |
| for (y = 0; y < height; ++y) { |
| DetileSplitUVRow(src_uv, src_tile_stride, dst_u, dst_v, width); |
| dst_u += dst_stride_u; |
| dst_v += dst_stride_v; |
| src_uv += 16; |
| // Advance to next row of tiles. |
| if ((y & (tile_height - 1)) == (tile_height - 1)) { |
| src_uv = src_uv - src_tile_stride + src_stride_uv * tile_height; |
| } |
| } |
| } |
| |
| LIBYUV_API |
| void DetileToYUY2(const uint8_t* src_y, |
| int src_stride_y, |
| const uint8_t* src_uv, |
| int src_stride_uv, |
| uint8_t* dst_yuy2, |
| int dst_stride_yuy2, |
| int width, |
| int height, |
| int tile_height) { |
| const ptrdiff_t src_y_tile_stride = 16 * tile_height; |
| const ptrdiff_t src_uv_tile_stride = src_y_tile_stride / 2; |
| int y; |
| void (*DetileToYUY2)(const uint8_t* src_y, ptrdiff_t src_y_tile_stride, |
| const uint8_t* src_uv, ptrdiff_t src_uv_tile_stride, |
| uint8_t* dst_yuy2, int width) = DetileToYUY2_C; |
| assert(src_stride_y >= 0); |
| assert(src_stride_y > 0); |
| assert(src_stride_uv >= 0); |
| assert(src_stride_uv > 0); |
| assert(tile_height > 0); |
| |
| if (width <= 0 || height == 0 || tile_height <= 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2; |
| dst_stride_yuy2 = -dst_stride_yuy2; |
| } |
| |
| #if defined(HAS_DETILETOYUY2_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| DetileToYUY2 = DetileToYUY2_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| DetileToYUY2 = DetileToYUY2_NEON; |
| } |
| } |
| #endif |
| |
| #if defined(HAS_DETILETOYUY2_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| DetileToYUY2 = DetileToYUY2_Any_SSE2; |
| if (IS_ALIGNED(width, 16)) { |
| DetileToYUY2 = DetileToYUY2_SSE2; |
| } |
| } |
| #endif |
| |
| // Detile plane |
| for (y = 0; y < height; ++y) { |
| DetileToYUY2(src_y, src_y_tile_stride, src_uv, src_uv_tile_stride, dst_yuy2, |
| width); |
| dst_yuy2 += dst_stride_yuy2; |
| src_y += 16; |
| |
| if (y & 0x1) |
| src_uv += 16; |
| |
| // Advance to next row of tiles. |
| if ((y & (tile_height - 1)) == (tile_height - 1)) { |
| src_y = src_y - src_y_tile_stride + src_stride_y * tile_height; |
| src_uv = src_uv - src_uv_tile_stride + src_stride_uv * (tile_height / 2); |
| } |
| } |
| } |
| |
| // Support function for NV12 etc RGB channels. |
| // Width and height are plane sizes (typically half pixel width). |
| LIBYUV_API |
| void SplitRGBPlane(const uint8_t* src_rgb, |
| int src_stride_rgb, |
| uint8_t* dst_r, |
| int dst_stride_r, |
| uint8_t* dst_g, |
| int dst_stride_g, |
| uint8_t* dst_b, |
| int dst_stride_b, |
| int width, |
| int height) { |
| int y; |
| void (*SplitRGBRow)(const uint8_t* src_rgb, uint8_t* dst_r, uint8_t* dst_g, |
| uint8_t* dst_b, int width) = SplitRGBRow_C; |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_r = dst_r + (height - 1) * dst_stride_r; |
| dst_g = dst_g + (height - 1) * dst_stride_g; |
| dst_b = dst_b + (height - 1) * dst_stride_b; |
| dst_stride_r = -dst_stride_r; |
| dst_stride_g = -dst_stride_g; |
| dst_stride_b = -dst_stride_b; |
| } |
| // Coalesce rows. |
| if (src_stride_rgb == width * 3 && dst_stride_r == width && |
| dst_stride_g == width && dst_stride_b == width) { |
| width *= height; |
| height = 1; |
| src_stride_rgb = dst_stride_r = dst_stride_g = dst_stride_b = 0; |
| } |
| #if defined(HAS_SPLITRGBROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| SplitRGBRow = SplitRGBRow_Any_SSSE3; |
| if (IS_ALIGNED(width, 16)) { |
| SplitRGBRow = SplitRGBRow_SSSE3; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITRGBROW_SSE41) |
| if (TestCpuFlag(kCpuHasSSE41)) { |
| SplitRGBRow = SplitRGBRow_Any_SSE41; |
| if (IS_ALIGNED(width, 16)) { |
| SplitRGBRow = SplitRGBRow_SSE41; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITRGBROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| SplitRGBRow = SplitRGBRow_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| SplitRGBRow = SplitRGBRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITRGBROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| SplitRGBRow = SplitRGBRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| SplitRGBRow = SplitRGBRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITRGBROW_RVV) |
| if (TestCpuFlag(kCpuHasRVV)) { |
| SplitRGBRow = SplitRGBRow_RVV; |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| // Copy a row of RGB. |
| SplitRGBRow(src_rgb, dst_r, dst_g, dst_b, width); |
| dst_r += dst_stride_r; |
| dst_g += dst_stride_g; |
| dst_b += dst_stride_b; |
| src_rgb += src_stride_rgb; |
| } |
| } |
| |
| LIBYUV_API |
| void MergeRGBPlane(const uint8_t* src_r, |
| int src_stride_r, |
| const uint8_t* src_g, |
| int src_stride_g, |
| const uint8_t* src_b, |
| int src_stride_b, |
| uint8_t* dst_rgb, |
| int dst_stride_rgb, |
| int width, |
| int height) { |
| int y; |
| void (*MergeRGBRow)(const uint8_t* src_r, const uint8_t* src_g, |
| const uint8_t* src_b, uint8_t* dst_rgb, int width) = |
| MergeRGBRow_C; |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| // Coalesce rows. |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_rgb = dst_rgb + (height - 1) * dst_stride_rgb; |
| dst_stride_rgb = -dst_stride_rgb; |
| } |
| // Coalesce rows. |
| if (src_stride_r == width && src_stride_g == width && src_stride_b == width && |
| dst_stride_rgb == width * 3) { |
| width *= height; |
| height = 1; |
| src_stride_r = src_stride_g = src_stride_b = dst_stride_rgb = 0; |
| } |
| #if defined(HAS_MERGERGBROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| MergeRGBRow = MergeRGBRow_Any_SSSE3; |
| if (IS_ALIGNED(width, 16)) { |
| MergeRGBRow = MergeRGBRow_SSSE3; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGERGBROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MergeRGBRow = MergeRGBRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| MergeRGBRow = MergeRGBRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGERGBROW_RVV) |
| if (TestCpuFlag(kCpuHasRVV)) { |
| MergeRGBRow = MergeRGBRow_RVV; |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| // Merge a row of U and V into a row of RGB. |
| MergeRGBRow(src_r, src_g, src_b, dst_rgb, width); |
| src_r += src_stride_r; |
| src_g += src_stride_g; |
| src_b += src_stride_b; |
| dst_rgb += dst_stride_rgb; |
| } |
| } |
| |
| LIBYUV_NOINLINE |
| static void SplitARGBPlaneAlpha(const uint8_t* src_argb, |
| int src_stride_argb, |
| uint8_t* dst_r, |
| int dst_stride_r, |
| uint8_t* dst_g, |
| int dst_stride_g, |
| uint8_t* dst_b, |
| int dst_stride_b, |
| uint8_t* dst_a, |
| int dst_stride_a, |
| int width, |
| int height) { |
| int y; |
| void (*SplitARGBRow)(const uint8_t* src_rgb, uint8_t* dst_r, uint8_t* dst_g, |
| uint8_t* dst_b, uint8_t* dst_a, int width) = |
| SplitARGBRow_C; |
| |
| assert(height > 0); |
| |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| if (src_stride_argb == width * 4 && dst_stride_r == width && |
| dst_stride_g == width && dst_stride_b == width && dst_stride_a == width) { |
| width *= height; |
| height = 1; |
| src_stride_argb = dst_stride_r = dst_stride_g = dst_stride_b = |
| dst_stride_a = 0; |
| } |
| |
| #if defined(HAS_SPLITARGBROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| SplitARGBRow = SplitARGBRow_Any_SSE2; |
| if (IS_ALIGNED(width, 8)) { |
| SplitARGBRow = SplitARGBRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITARGBROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| SplitARGBRow = SplitARGBRow_Any_SSSE3; |
| if (IS_ALIGNED(width, 8)) { |
| SplitARGBRow = SplitARGBRow_SSSE3; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITARGBROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| SplitARGBRow = SplitARGBRow_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| SplitARGBRow = SplitARGBRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITARGBROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| SplitARGBRow = SplitARGBRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| SplitARGBRow = SplitARGBRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITARGBROW_RVV) |
| if (TestCpuFlag(kCpuHasRVV)) { |
| SplitARGBRow = SplitARGBRow_RVV; |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| SplitARGBRow(src_argb, dst_r, dst_g, dst_b, dst_a, width); |
| dst_r += dst_stride_r; |
| dst_g += dst_stride_g; |
| dst_b += dst_stride_b; |
| dst_a += dst_stride_a; |
| src_argb += src_stride_argb; |
| } |
| } |
| |
| LIBYUV_NOINLINE |
| static void SplitARGBPlaneOpaque(const uint8_t* src_argb, |
| int src_stride_argb, |
| uint8_t* dst_r, |
| int dst_stride_r, |
| uint8_t* dst_g, |
| int dst_stride_g, |
| uint8_t* dst_b, |
| int dst_stride_b, |
| int width, |
| int height) { |
| int y; |
| void (*SplitXRGBRow)(const uint8_t* src_rgb, uint8_t* dst_r, uint8_t* dst_g, |
| uint8_t* dst_b, int width) = SplitXRGBRow_C; |
| assert(height > 0); |
| |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| if (src_stride_argb == width * 4 && dst_stride_r == width && |
| dst_stride_g == width && dst_stride_b == width) { |
| width *= height; |
| height = 1; |
| src_stride_argb = dst_stride_r = dst_stride_g = dst_stride_b = 0; |
| } |
| |
| #if defined(HAS_SPLITXRGBROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| SplitXRGBRow = SplitXRGBRow_Any_SSE2; |
| if (IS_ALIGNED(width, 8)) { |
| SplitXRGBRow = SplitXRGBRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITXRGBROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| SplitXRGBRow = SplitXRGBRow_Any_SSSE3; |
| if (IS_ALIGNED(width, 8)) { |
| SplitXRGBRow = SplitXRGBRow_SSSE3; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITXRGBROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| SplitXRGBRow = SplitXRGBRow_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| SplitXRGBRow = SplitXRGBRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITXRGBROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| SplitXRGBRow = SplitXRGBRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| SplitXRGBRow = SplitXRGBRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_SPLITXRGBROW_RVV) |
| if (TestCpuFlag(kCpuHasRVV)) { |
| SplitXRGBRow = SplitXRGBRow_RVV; |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| SplitXRGBRow(src_argb, dst_r, dst_g, dst_b, width); |
| dst_r += dst_stride_r; |
| dst_g += dst_stride_g; |
| dst_b += dst_stride_b; |
| src_argb += src_stride_argb; |
| } |
| } |
| |
| LIBYUV_API |
| void SplitARGBPlane(const uint8_t* src_argb, |
| int src_stride_argb, |
| uint8_t* dst_r, |
| int dst_stride_r, |
| uint8_t* dst_g, |
| int dst_stride_g, |
| uint8_t* dst_b, |
| int dst_stride_b, |
| uint8_t* dst_a, |
| int dst_stride_a, |
| int width, |
| int height) { |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_r = dst_r + (height - 1) * dst_stride_r; |
| dst_g = dst_g + (height - 1) * dst_stride_g; |
| dst_b = dst_b + (height - 1) * dst_stride_b; |
| dst_a = dst_a + (height - 1) * dst_stride_a; |
| dst_stride_r = -dst_stride_r; |
| dst_stride_g = -dst_stride_g; |
| dst_stride_b = -dst_stride_b; |
| dst_stride_a = -dst_stride_a; |
| } |
| |
| if (dst_a == NULL) { |
| SplitARGBPlaneOpaque(src_argb, src_stride_argb, dst_r, dst_stride_r, dst_g, |
| dst_stride_g, dst_b, dst_stride_b, width, height); |
| } else { |
| SplitARGBPlaneAlpha(src_argb, src_stride_argb, dst_r, dst_stride_r, dst_g, |
| dst_stride_g, dst_b, dst_stride_b, dst_a, dst_stride_a, |
| width, height); |
| } |
| } |
| |
| LIBYUV_NOINLINE |
| static void MergeARGBPlaneAlpha(const uint8_t* src_r, |
| int src_stride_r, |
| const uint8_t* src_g, |
| int src_stride_g, |
| const uint8_t* src_b, |
| int src_stride_b, |
| const uint8_t* src_a, |
| int src_stride_a, |
| uint8_t* dst_argb, |
| int dst_stride_argb, |
| int width, |
| int height) { |
| int y; |
| void (*MergeARGBRow)(const uint8_t* src_r, const uint8_t* src_g, |
| const uint8_t* src_b, const uint8_t* src_a, |
| uint8_t* dst_argb, int width) = MergeARGBRow_C; |
| |
| assert(height > 0); |
| |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| if (src_stride_r == width && src_stride_g == width && src_stride_b == width && |
| src_stride_a == width && dst_stride_argb == width * 4) { |
| width *= height; |
| height = 1; |
| src_stride_r = src_stride_g = src_stride_b = src_stride_a = |
| dst_stride_argb = 0; |
| } |
| #if defined(HAS_MERGEARGBROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| MergeARGBRow = MergeARGBRow_Any_SSE2; |
| if (IS_ALIGNED(width, 8)) { |
| MergeARGBRow = MergeARGBRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEARGBROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MergeARGBRow = MergeARGBRow_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| MergeARGBRow = MergeARGBRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEARGBROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MergeARGBRow = MergeARGBRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| MergeARGBRow = MergeARGBRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEARGBROW_RVV) |
| if (TestCpuFlag(kCpuHasRVV)) { |
| MergeARGBRow = MergeARGBRow_RVV; |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| MergeARGBRow(src_r, src_g, src_b, src_a, dst_argb, width); |
| src_r += src_stride_r; |
| src_g += src_stride_g; |
| src_b += src_stride_b; |
| src_a += src_stride_a; |
| dst_argb += dst_stride_argb; |
| } |
| } |
| |
| LIBYUV_NOINLINE |
| static void MergeARGBPlaneOpaque(const uint8_t* src_r, |
| int src_stride_r, |
| const uint8_t* src_g, |
| int src_stride_g, |
| const uint8_t* src_b, |
| int src_stride_b, |
| uint8_t* dst_argb, |
| int dst_stride_argb, |
| int width, |
| int height) { |
| int y; |
| void (*MergeXRGBRow)(const uint8_t* src_r, const uint8_t* src_g, |
| const uint8_t* src_b, uint8_t* dst_argb, int width) = |
| MergeXRGBRow_C; |
| |
| assert(height > 0); |
| |
| if (width <= 0 || height == 0) { |
| return; |
| } |
| if (src_stride_r == width && src_stride_g == width && src_stride_b == width && |
| dst_stride_argb == width * 4) { |
| width *= height; |
| height = 1; |
| src_stride_r = src_stride_g = src_stride_b = dst_stride_argb = 0; |
| } |
| #if defined(HAS_MERGEXRGBROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| MergeXRGBRow = MergeXRGBRow_Any_SSE2; |
| if (IS_ALIGNED(width, 8)) { |
| MergeXRGBRow = MergeXRGBRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEXRGBROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MergeXRGBRow = MergeXRGBRow_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| MergeXRGBRow = MergeXRGBRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEXRGBROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MergeXRGBRow = MergeXRGBRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| MergeXRGBRow = MergeXRGBRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEXRGBROW_RVV) |
| if (TestCpuFlag(kCpuHasRVV)) { |
| MergeXRGBRow = MergeXRGBRow_RVV; |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| MergeXRGBRow(src_r, src_g, src_b, dst_argb, width); |
| src_r += src_stride_r; |
| src_g += src_stride_g; |
| src_b += src_stride_b; |
| dst_argb += dst_stride_argb; |
| } |
| } |
| |
| LIBYUV_API |
| void MergeARGBPlane(const uint8_t* src_r, |
| int src_stride_r, |
| const uint8_t* src_g, |
| int src_stride_g, |
| const uint8_t* src_b, |
| int src_stride_b, |
| const uint8_t* src_a, |
| int src_stride_a, |
| uint8_t* dst_argb, |
| int dst_stride_argb, |
| int width, |
| int height) { |
| // 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 (src_a == NULL) { |
| MergeARGBPlaneOpaque(src_r, src_stride_r, src_g, src_stride_g, src_b, |
| src_stride_b, dst_argb, dst_stride_argb, width, |
| height); |
| } else { |
| MergeARGBPlaneAlpha(src_r, src_stride_r, src_g, src_stride_g, src_b, |
| src_stride_b, src_a, src_stride_a, dst_argb, |
| dst_stride_argb, width, height); |
| } |
| } |
| |
| // TODO(yuan): Support 2 bit alpha channel. |
| LIBYUV_API |
| void MergeXR30Plane(const uint16_t* src_r, |
| int src_stride_r, |
| const uint16_t* src_g, |
| int src_stride_g, |
| const uint16_t* src_b, |
| int src_stride_b, |
| uint8_t* dst_ar30, |
| int dst_stride_ar30, |
| int width, |
| int height, |
| int depth) { |
| int y; |
| void (*MergeXR30Row)(const uint16_t* src_r, const uint16_t* src_g, |
| const uint16_t* src_b, uint8_t* dst_ar30, int depth, |
| int width) = MergeXR30Row_C; |
| |
| // 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; |
| } |
| // Coalesce rows. |
| if (src_stride_r == width && src_stride_g == width && src_stride_b == width && |
| dst_stride_ar30 == width * 4) { |
| width *= height; |
| height = 1; |
| src_stride_r = src_stride_g = src_stride_b = dst_stride_ar30 = 0; |
| } |
| #if defined(HAS_MERGEXR30ROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MergeXR30Row = MergeXR30Row_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| MergeXR30Row = MergeXR30Row_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEXR30ROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| if (depth == 10) { |
| MergeXR30Row = MergeXR30Row_10_Any_NEON; |
| if (IS_ALIGNED(width, 8)) { |
| MergeXR30Row = MergeXR30Row_10_NEON; |
| } |
| } else { |
| MergeXR30Row = MergeXR30Row_Any_NEON; |
| if (IS_ALIGNED(width, 8)) { |
| MergeXR30Row = MergeXR30Row_NEON; |
| } |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| MergeXR30Row(src_r, src_g, src_b, dst_ar30, depth, width); |
| src_r += src_stride_r; |
| src_g += src_stride_g; |
| src_b += src_stride_b; |
| dst_ar30 += dst_stride_ar30; |
| } |
| } |
| |
| LIBYUV_NOINLINE |
| static void MergeAR64PlaneAlpha(const uint16_t* src_r, |
| int src_stride_r, |
| const uint16_t* src_g, |
| int src_stride_g, |
| const uint16_t* src_b, |
| int src_stride_b, |
| const uint16_t* src_a, |
| int src_stride_a, |
| uint16_t* dst_ar64, |
| int dst_stride_ar64, |
| int width, |
| int height, |
| int depth) { |
| int y; |
| void (*MergeAR64Row)(const uint16_t* src_r, const uint16_t* src_g, |
| const uint16_t* src_b, const uint16_t* src_a, |
| uint16_t* dst_argb, int depth, int width) = |
| MergeAR64Row_C; |
| |
| if (src_stride_r == width && src_stride_g == width && src_stride_b == width && |
| src_stride_a == width && dst_stride_ar64 == width * 4) { |
| width *= height; |
| height = 1; |
| src_stride_r = src_stride_g = src_stride_b = src_stride_a = |
| dst_stride_ar64 = 0; |
| } |
| #if defined(HAS_MERGEAR64ROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MergeAR64Row = MergeAR64Row_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| MergeAR64Row = MergeAR64Row_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEAR64ROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MergeAR64Row = MergeAR64Row_Any_NEON; |
| if (IS_ALIGNED(width, 8)) { |
| MergeAR64Row = MergeAR64Row_NEON; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| MergeAR64Row(src_r, src_g, src_b, src_a, dst_ar64, depth, width); |
| src_r += src_stride_r; |
| src_g += src_stride_g; |
| src_b += src_stride_b; |
| src_a += src_stride_a; |
| dst_ar64 += dst_stride_ar64; |
| } |
| } |
| |
| LIBYUV_NOINLINE |
| static void MergeAR64PlaneOpaque(const uint16_t* src_r, |
| int src_stride_r, |
| const uint16_t* src_g, |
| int src_stride_g, |
| const uint16_t* src_b, |
| int src_stride_b, |
| uint16_t* dst_ar64, |
| int dst_stride_ar64, |
| int width, |
| int height, |
| int depth) { |
| int y; |
| void (*MergeXR64Row)(const uint16_t* src_r, const uint16_t* src_g, |
| const uint16_t* src_b, uint16_t* dst_argb, int depth, |
| int width) = MergeXR64Row_C; |
| |
| // Coalesce rows. |
| if (src_stride_r == width && src_stride_g == width && src_stride_b == width && |
| dst_stride_ar64 == width * 4) { |
| width *= height; |
| height = 1; |
| src_stride_r = src_stride_g = src_stride_b = dst_stride_ar64 = 0; |
| } |
| #if defined(HAS_MERGEXR64ROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MergeXR64Row = MergeXR64Row_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| MergeXR64Row = MergeXR64Row_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEXR64ROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MergeXR64Row = MergeXR64Row_Any_NEON; |
| if (IS_ALIGNED(width, 8)) { |
| MergeXR64Row = MergeXR64Row_NEON; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| MergeXR64Row(src_r, src_g, src_b, dst_ar64, depth, width); |
| src_r += src_stride_r; |
| src_g += src_stride_g; |
| src_b += src_stride_b; |
| dst_ar64 += dst_stride_ar64; |
| } |
| } |
| |
| LIBYUV_API |
| void MergeAR64Plane(const uint16_t* src_r, |
| int src_stride_r, |
| const uint16_t* src_g, |
| int src_stride_g, |
| const uint16_t* src_b, |
| int src_stride_b, |
| const uint16_t* src_a, |
| int src_stride_a, |
| uint16_t* dst_ar64, |
| int dst_stride_ar64, |
| int width, |
| int height, |
| int depth) { |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| dst_ar64 = dst_ar64 + (height - 1) * dst_stride_ar64; |
| dst_stride_ar64 = -dst_stride_ar64; |
| } |
| |
| if (src_a == NULL) { |
| MergeAR64PlaneOpaque(src_r, src_stride_r, src_g, src_stride_g, src_b, |
| src_stride_b, dst_ar64, dst_stride_ar64, width, height, |
| depth); |
| } else { |
| MergeAR64PlaneAlpha(src_r, src_stride_r, src_g, src_stride_g, src_b, |
| src_stride_b, src_a, src_stride_a, dst_ar64, |
| dst_stride_ar64, width, height, depth); |
| } |
| } |
| |
| LIBYUV_NOINLINE |
| static void MergeARGB16To8PlaneAlpha(const uint16_t* src_r, |
| int src_stride_r, |
| const uint16_t* src_g, |
| int src_stride_g, |
| const uint16_t* src_b, |
| int src_stride_b, |
| const uint16_t* src_a, |
| int src_stride_a, |
| uint8_t* dst_argb, |
| int dst_stride_argb, |
| int width, |
| int height, |
| int depth) { |
| int y; |
| void (*MergeARGB16To8Row)(const uint16_t* src_r, const uint16_t* src_g, |
| const uint16_t* src_b, const uint16_t* src_a, |
| uint8_t* dst_argb, int depth, int width) = |
| MergeARGB16To8Row_C; |
| |
| if (src_stride_r == width && src_stride_g == width && src_stride_b == width && |
| src_stride_a == width && dst_stride_argb == width * 4) { |
| width *= height; |
| height = 1; |
| src_stride_r = src_stride_g = src_stride_b = src_stride_a = |
| dst_stride_argb = 0; |
| } |
| #if defined(HAS_MERGEARGB16TO8ROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MergeARGB16To8Row = MergeARGB16To8Row_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| MergeARGB16To8Row = MergeARGB16To8Row_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEARGB16TO8ROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MergeARGB16To8Row = MergeARGB16To8Row_Any_NEON; |
| if (IS_ALIGNED(width, 8)) { |
| MergeARGB16To8Row = MergeARGB16To8Row_NEON; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| MergeARGB16To8Row(src_r, src_g, src_b, src_a, dst_argb, depth, width); |
| src_r += src_stride_r; |
| src_g += src_stride_g; |
| src_b += src_stride_b; |
| src_a += src_stride_a; |
| dst_argb += dst_stride_argb; |
| } |
| } |
| |
| LIBYUV_NOINLINE |
| static void MergeARGB16To8PlaneOpaque(const uint16_t* src_r, |
| int src_stride_r, |
| const uint16_t* src_g, |
| int src_stride_g, |
| const uint16_t* src_b, |
| int src_stride_b, |
| uint8_t* dst_argb, |
| int dst_stride_argb, |
| int width, |
| int height, |
| int depth) { |
| int y; |
| void (*MergeXRGB16To8Row)(const uint16_t* src_r, const uint16_t* src_g, |
| const uint16_t* src_b, uint8_t* dst_argb, int depth, |
| int width) = MergeXRGB16To8Row_C; |
| |
| // Coalesce rows. |
| if (src_stride_r == width && src_stride_g == width && src_stride_b == width && |
| dst_stride_argb == width * 4) { |
| width *= height; |
| height = 1; |
| src_stride_r = src_stride_g = src_stride_b = dst_stride_argb = 0; |
| } |
| #if defined(HAS_MERGEXRGB16TO8ROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MergeXRGB16To8Row = MergeXRGB16To8Row_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| MergeXRGB16To8Row = MergeXRGB16To8Row_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MERGEXRGB16TO8ROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MergeXRGB16To8Row = MergeXRGB16To8Row_Any_NEON; |
| if (IS_ALIGNED(width, 8)) { |
| MergeXRGB16To8Row = MergeXRGB16To8Row_NEON; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| MergeXRGB16To8Row(src_r, src_g, src_b, dst_argb, depth, width); |
| src_r += src_stride_r; |
| src_g += src_stride_g; |
| src_b += src_stride_b; |
| dst_argb += dst_stride_argb; |
| } |
| } |
| |
| LIBYUV_API |
| void MergeARGB16To8Plane(const uint16_t* src_r, |
| int src_stride_r, |
| const uint16_t* src_g, |
| int src_stride_g, |
| const uint16_t* src_b, |
| int src_stride_b, |
| const uint16_t* src_a, |
| int src_stride_a, |
| uint8_t* dst_argb, |
| int dst_stride_argb, |
| int width, |
| int height, |
| int depth) { |
| // 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 (src_a == NULL) { |
| MergeARGB16To8PlaneOpaque(src_r, src_stride_r, src_g, src_stride_g, src_b, |
| src_stride_b, dst_argb, dst_stride_argb, width, |
| height, depth); |
| } else { |
| MergeARGB16To8PlaneAlpha(src_r, src_stride_r, src_g, src_stride_g, src_b, |
| src_stride_b, src_a, src_stride_a, dst_argb, |
| dst_stride_argb, width, height, depth); |
| } |
| } |
| |
| // Convert YUY2 to I422. |
| LIBYUV_API |
| int YUY2ToI422(const uint8_t* src_yuy2, |
| int src_stride_yuy2, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| uint8_t* dst_u, |
| int dst_stride_u, |
| uint8_t* dst_v, |
| int dst_stride_v, |
| int width, |
| int height) { |
| int y; |
| void (*YUY2ToUV422Row)(const uint8_t* src_yuy2, uint8_t* dst_u, |
| uint8_t* dst_v, int width) = YUY2ToUV422Row_C; |
| void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) = |
| YUY2ToYRow_C; |
| if (!src_yuy2 || !dst_y || !dst_u || !dst_v || 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_y == width && |
| dst_stride_u * 2 == width && dst_stride_v * 2 == width && |
| width * height <= 32768) { |
| width *= height; |
| height = 1; |
| src_stride_yuy2 = dst_stride_y = dst_stride_u = dst_stride_v = 0; |
| } |
| #if defined(HAS_YUY2TOYROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2; |
| YUY2ToYRow = YUY2ToYRow_Any_SSE2; |
| if (IS_ALIGNED(width, 16)) { |
| YUY2ToUV422Row = YUY2ToUV422Row_SSE2; |
| YUY2ToYRow = YUY2ToYRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_YUY2TOYROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2; |
| YUY2ToYRow = YUY2ToYRow_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| YUY2ToUV422Row = YUY2ToUV422Row_AVX2; |
| YUY2ToYRow = YUY2ToYRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_YUY2TOYROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| YUY2ToYRow = YUY2ToYRow_Any_NEON; |
| YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| YUY2ToYRow = YUY2ToYRow_NEON; |
| YUY2ToUV422Row = YUY2ToUV422Row_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_YUY2TOYROW_MSA) && defined(HAS_YUY2TOUV422ROW_MSA) |
| if (TestCpuFlag(kCpuHasMSA)) { |
| YUY2ToYRow = YUY2ToYRow_Any_MSA; |
| YUY2ToUV422Row = YUY2ToUV422Row_Any_MSA; |
| if (IS_ALIGNED(width, 32)) { |
| YUY2ToYRow = YUY2ToYRow_MSA; |
| YUY2ToUV422Row = YUY2ToUV422Row_MSA; |
| } |
| } |
| #endif |
| #if defined(HAS_YUY2TOYROW_LSX) && defined(HAS_YUY2TOUV422ROW_LSX) |
| if (TestCpuFlag(kCpuHasLSX)) { |
| YUY2ToYRow = YUY2ToYRow_Any_LSX; |
| YUY2ToUV422Row = YUY2ToUV422Row_Any_LSX; |
| if (IS_ALIGNED(width, 16)) { |
| YUY2ToYRow = YUY2ToYRow_LSX; |
| YUY2ToUV422Row = YUY2ToUV422Row_LSX; |
| } |
| } |
| #endif |
| #if defined(HAS_YUY2TOYROW_LASX) && defined(HAS_YUY2TOUV422ROW_LASX) |
| if (TestCpuFlag(kCpuHasLASX)) { |
| YUY2ToYRow = YUY2ToYRow_Any_LASX; |
| YUY2ToUV422Row = YUY2ToUV422Row_Any_LASX; |
| if (IS_ALIGNED(width, 32)) { |
| YUY2ToYRow = YUY2ToYRow_LASX; |
| YUY2ToUV422Row = YUY2ToUV422Row_LASX; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width); |
| YUY2ToYRow(src_yuy2, dst_y, width); |
| src_yuy2 += src_stride_yuy2; |
| dst_y += dst_stride_y; |
| dst_u += dst_stride_u; |
| dst_v += dst_stride_v; |
| } |
| return 0; |
| } |
| |
| // Convert UYVY to I422. |
| LIBYUV_API |
| int UYVYToI422(const uint8_t* src_uyvy, |
| int src_stride_uyvy, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| uint8_t* dst_u, |
| int dst_stride_u, |
| uint8_t* dst_v, |
| int dst_stride_v, |
| int width, |
| int height) { |
| int y; |
| void (*UYVYToUV422Row)(const uint8_t* src_uyvy, uint8_t* dst_u, |
| uint8_t* dst_v, int width) = UYVYToUV422Row_C; |
| void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) = |
| UYVYToYRow_C; |
| if (!src_uyvy || !dst_y || !dst_u || !dst_v || 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_y == width && |
| dst_stride_u * 2 == width && dst_stride_v * 2 == width && |
| width * height <= 32768) { |
| width *= height; |
| height = 1; |
| src_stride_uyvy = dst_stride_y = dst_stride_u = dst_stride_v = 0; |
| } |
| #if defined(HAS_UYVYTOYROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| UYVYToUV422Row = UYVYToUV422Row_Any_SSE2; |
| UYVYToYRow = UYVYToYRow_Any_SSE2; |
| if (IS_ALIGNED(width, 16)) { |
| UYVYToUV422Row = UYVYToUV422Row_SSE2; |
| UYVYToYRow = UYVYToYRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_UYVYTOYROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| UYVYToUV422Row = UYVYToUV422Row_Any_AVX2; |
| UYVYToYRow = UYVYToYRow_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| UYVYToUV422Row = UYVYToUV422Row_AVX2; |
| UYVYToYRow = UYVYToYRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_UYVYTOYROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| UYVYToYRow = UYVYToYRow_Any_NEON; |
| UYVYToUV422Row = UYVYToUV422Row_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| UYVYToYRow = UYVYToYRow_NEON; |
| UYVYToUV422Row = UYVYToUV422Row_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_UYVYTOYROW_MSA) && defined(HAS_UYVYTOUV422ROW_MSA) |
| if (TestCpuFlag(kCpuHasMSA)) { |
| UYVYToYRow = UYVYToYRow_Any_MSA; |
| UYVYToUV422Row = UYVYToUV422Row_Any_MSA; |
| if (IS_ALIGNED(width, 32)) { |
| UYVYToYRow = UYVYToYRow_MSA; |
| UYVYToUV422Row = UYVYToUV422Row_MSA; |
| } |
| } |
| #endif |
| #if defined(HAS_UYVYTOYROW_LSX) && defined(HAS_UYVYTOUV422ROW_LSX) |
| if (TestCpuFlag(kCpuHasLSX)) { |
| UYVYToYRow = UYVYToYRow_Any_LSX; |
| UYVYToUV422Row = UYVYToUV422Row_Any_LSX; |
| if (IS_ALIGNED(width, 16)) { |
| UYVYToYRow = UYVYToYRow_LSX; |
| UYVYToUV422Row = UYVYToUV422Row_LSX; |
| } |
| } |
| #endif |
| #if defined(HAS_UYVYTOYROW_LASX) && defined(HAS_UYVYTOUV422ROW_LASX) |
| if (TestCpuFlag(kCpuHasLASX)) { |
| UYVYToYRow = UYVYToYRow_Any_LASX; |
| UYVYToUV422Row = UYVYToUV422Row_Any_LASX; |
| if (IS_ALIGNED(width, 32)) { |
| UYVYToYRow = UYVYToYRow_LASX; |
| UYVYToUV422Row = UYVYToUV422Row_LASX; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| UYVYToUV422Row(src_uyvy, dst_u, dst_v, width); |
| UYVYToYRow(src_uyvy, dst_y, width); |
| src_uyvy += src_stride_uyvy; |
| dst_y += dst_stride_y; |
| dst_u += dst_stride_u; |
| dst_v += dst_stride_v; |
| } |
| return 0; |
| } |
| |
| // Convert YUY2 to Y. |
| LIBYUV_API |
| int YUY2ToY(const uint8_t* src_yuy2, |
| int src_stride_yuy2, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height) { |
| int y; |
| void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) = |
| YUY2ToYRow_C; |
| if (!src_yuy2 || !dst_y || 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_y == width) { |
| width *= height; |
| height = 1; |
| src_stride_yuy2 = dst_stride_y = 0; |
| } |
| #if defined(HAS_YUY2TOYROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| YUY2ToYRow = YUY2ToYRow_Any_SSE2; |
| if (IS_ALIGNED(width, 16)) { |
| YUY2ToYRow = YUY2ToYRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_YUY2TOYROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| YUY2ToYRow = YUY2ToYRow_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| YUY2ToYRow = YUY2ToYRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_YUY2TOYROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| YUY2ToYRow = YUY2ToYRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| YUY2ToYRow = YUY2ToYRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_YUY2TOYROW_MSA) |
| if (TestCpuFlag(kCpuHasMSA)) { |
| YUY2ToYRow = YUY2ToYRow_Any_MSA; |
| if (IS_ALIGNED(width, 32)) { |
| YUY2ToYRow = YUY2ToYRow_MSA; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| YUY2ToYRow(src_yuy2, dst_y, width); |
| src_yuy2 += src_stride_yuy2; |
| dst_y += dst_stride_y; |
| } |
| return 0; |
| } |
| |
| // Convert UYVY to Y. |
| LIBYUV_API |
| int UYVYToY(const uint8_t* src_uyvy, |
| int src_stride_uyvy, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height) { |
| int y; |
| void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) = |
| UYVYToYRow_C; |
| if (!src_uyvy || !dst_y || 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_y == width) { |
| width *= height; |
| height = 1; |
| src_stride_uyvy = dst_stride_y = 0; |
| } |
| #if defined(HAS_UYVYTOYROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| UYVYToYRow = UYVYToYRow_Any_SSE2; |
| if (IS_ALIGNED(width, 16)) { |
| UYVYToYRow = UYVYToYRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_UYVYTOYROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| UYVYToYRow = UYVYToYRow_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| UYVYToYRow = UYVYToYRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_UYVYTOYROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| UYVYToYRow = UYVYToYRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| UYVYToYRow = UYVYToYRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_UYVYTOYROW_MSA) |
| if (TestCpuFlag(kCpuHasMSA)) { |
| UYVYToYRow = UYVYToYRow_Any_MSA; |
| if (IS_ALIGNED(width, 32)) { |
| UYVYToYRow = UYVYToYRow_MSA; |
| } |
| } |
| #endif |
| #if defined(HAS_UYVYTOYROW_LSX) |
| if (TestCpuFlag(kCpuHasLSX)) { |
| UYVYToYRow = UYVYToYRow_Any_LSX; |
| if (IS_ALIGNED(width, 16)) { |
| UYVYToYRow = UYVYToYRow_LSX; |
| } |
| } |
| #endif |
| |
| for (y = 0; y < height; ++y) { |
| UYVYToYRow(src_uyvy, dst_y, width); |
| src_uyvy += src_stride_uyvy; |
| dst_y += dst_stride_y; |
| } |
| return 0; |
| } |
| |
| // Mirror a plane of data. |
| // See Also I400Mirror |
| LIBYUV_API |
| void MirrorPlane(const uint8_t* src_y, |
| int src_stride_y, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height) { |
| int y; |
| void (*MirrorRow)(const uint8_t* src, uint8_t* dst, int width) = MirrorRow_C; |
| // 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; |
| } |
| #if defined(HAS_MIRRORROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MirrorRow = MirrorRow_Any_NEON; |
| if (IS_ALIGNED(width, 32)) { |
| MirrorRow = MirrorRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_MIRRORROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| MirrorRow = MirrorRow_Any_SSSE3; |
| if (IS_ALIGNED(width, 16)) { |
| MirrorRow = MirrorRow_SSSE3; |
| } |
| } |
| #endif |
| #if defined(HAS_MIRRORROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MirrorRow = MirrorRow_Any_AVX2; |
| if (IS_ALIGNED(width, 32)) { |
| MirrorRow = MirrorRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MIRRORROW_MSA) |
| if (TestCpuFlag(kCpuHasMSA)) { |
| MirrorRow = MirrorRow_Any_MSA; |
| if (IS_ALIGNED(width, 64)) { |
| MirrorRow = MirrorRow_MSA; |
| } |
| } |
| #endif |
| #if defined(HAS_MIRRORROW_LSX) |
| if (TestCpuFlag(kCpuHasLSX)) { |
| MirrorRow = MirrorRow_Any_LSX; |
| if (IS_ALIGNED(width, 32)) { |
| MirrorRow = MirrorRow_LSX; |
| } |
| } |
| #endif |
| #if defined(HAS_MIRRORROW_LASX) |
| if (TestCpuFlag(kCpuHasLASX)) { |
| MirrorRow = MirrorRow_Any_LASX; |
| if (IS_ALIGNED(width, 64)) { |
| MirrorRow = MirrorRow_LASX; |
| } |
| } |
| #endif |
| |
| // Mirror plane |
| for (y = 0; y < height; ++y) { |
| MirrorRow(src_y, dst_y, width); |
| src_y += src_stride_y; |
| dst_y += dst_stride_y; |
| } |
| } |
| |
| // Mirror a plane of UV data. |
| LIBYUV_API |
| void MirrorUVPlane(const uint8_t* src_uv, |
| int src_stride_uv, |
| uint8_t* dst_uv, |
| int dst_stride_uv, |
| int width, |
| int height) { |
| int y; |
| void (*MirrorUVRow)(const uint8_t* src, uint8_t* dst, int width) = |
| MirrorUVRow_C; |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| src_uv = src_uv + (height - 1) * src_stride_uv; |
| src_stride_uv = -src_stride_uv; |
| } |
| #if defined(HAS_MIRRORUVROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| MirrorUVRow = MirrorUVRow_Any_NEON; |
| if (IS_ALIGNED(width, 32)) { |
| MirrorUVRow = MirrorUVRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_MIRRORUVROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| MirrorUVRow = MirrorUVRow_Any_SSSE3; |
| if (IS_ALIGNED(width, 8)) { |
| MirrorUVRow = MirrorUVRow_SSSE3; |
| } |
| } |
| #endif |
| #if defined(HAS_MIRRORUVROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| MirrorUVRow = MirrorUVRow_Any_AVX2; |
| if (IS_ALIGNED(width, 16)) { |
| MirrorUVRow = MirrorUVRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_MIRRORUVROW_MSA) |
| if (TestCpuFlag(kCpuHasMSA)) { |
| MirrorUVRow = MirrorUVRow_Any_MSA; |
| if (IS_ALIGNED(width, 8)) { |
| MirrorUVRow = MirrorUVRow_MSA; |
| } |
| } |
| #endif |
| #if defined(HAS_MIRRORUVROW_LSX) |
| if (TestCpuFlag(kCpuHasLSX)) { |
| MirrorUVRow = MirrorUVRow_Any_LSX; |
| if (IS_ALIGNED(width, 8)) { |
| MirrorUVRow = MirrorUVRow_LSX; |
| } |
| } |
| #endif |
| #if defined(HAS_MIRRORUVROW_LASX) |
| if (TestCpuFlag(kCpuHasLASX)) { |
| MirrorUVRow = MirrorUVRow_Any_LASX; |
| if (IS_ALIGNED(width, 16)) { |
| MirrorUVRow = MirrorUVRow_LASX; |
| } |
| } |
| #endif |
| |
| // MirrorUV plane |
| for (y = 0; y < height; ++y) { |
| MirrorUVRow(src_uv, dst_uv, width); |
| src_uv += src_stride_uv; |
| dst_uv += dst_stride_uv; |
| } |
| } |
| |
| // Mirror I400 with optional flipping |
| LIBYUV_API |
| int I400Mirror(const uint8_t* src_y, |
| int src_stride_y, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| int width, |
| int height) { |
| if (!src_y || !dst_y || 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; |
| } |
| |
| MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| return 0; |
| } |
| |
| // Mirror I420 with optional flipping |
| LIBYUV_API |
| int I420Mirror(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_y, |
| int dst_stride_y, |
| uint8_t* dst_u, |
| int dst_stride_u, |
| uint8_t* dst_v, |
| int dst_stride_v, |
| int width, |
| int height) { |
| int halfwidth = (width + 1) >> 1; |
| int halfheight = (height + 1) >> 1; |
| |
| if (!src_y || !src_u || !src_v || !dst_u || !dst_v || width <= 0 || |
| height == 0) { |
| return -1; |
| } |
| |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| halfheight = (height + 1) >> 1; |
| src_y = src_y + (height - 1) * src_stride_y; |
| src_u = src_u + (halfheight - 1) * src_stride_u; |
| src_v = src_v + (halfheight - 1) * src_stride_v; |
| src_stride_y = -src_stride_y; |
| src_stride_u = -src_stride_u; |
| src_stride_v = -src_stride_v; |
| } |
| |
| if (dst_y) { |
| MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| } |
| MirrorPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight); |
| MirrorPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); |
| return 0; |
| } |
| |
| // NV12 mirror. |
| LIBYUV_API |
| int NV12Mirror(const uint8_t* src_y, |
| int src_stride_y, |
| const uint8_t* src_uv, |
| int src_stride_uv, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| uint8_t* dst_uv, |
| int dst_stride_uv, |
| int width, |
| int height) { |
| int halfwidth = (width + 1) >> 1; |
| int halfheight = (height + 1) >> 1; |
| |
| if (!src_y || !src_uv || !dst_uv || width <= 0 || height == 0) { |
| return -1; |
| } |
| |
| // Negative height means invert the image. |
| if (height < 0) { |
| height = -height; |
| halfheight = (height + 1) >> 1; |
| src_y = src_y + (height - 1) * src_stride_y; |
| src_uv = src_uv + (halfheight - 1) * src_stride_uv; |
| src_stride_y = -src_stride_y; |
| src_stride_uv = -src_stride_uv; |
| } |
| |
| if (dst_y) { |
| MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
| } |
| MirrorUVPlane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, halfwidth, |
| halfheight); |
| return 0; |
| } |
| |
| // ARGB mirror. |
| LIBYUV_API |
| int ARGBMirror(const uint8_t* src_argb, |
| int src_stride_argb, |
| uint8_t* dst_argb, |
| int dst_stride_argb, |
| int width, |
| int height) { |
| int y; |
| void (*ARGBMirrorRow)(const uint8_t* src, uint8_t* dst, int width) = |
| ARGBMirrorRow_C; |
| 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; |
| } |
| #if defined(HAS_ARGBMIRRORROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| ARGBMirrorRow = ARGBMirrorRow_Any_NEON; |
| if (IS_ALIGNED(width, 8)) { |
| ARGBMirrorRow = ARGBMirrorRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_ARGBMIRRORROW_SSE2) |
| if (TestCpuFlag(kCpuHasSSE2)) { |
| ARGBMirrorRow = ARGBMirrorRow_Any_SSE2; |
| if (IS_ALIGNED(width, 4)) { |
| ARGBMirrorRow = ARGBMirrorRow_SSE2; |
| } |
| } |
| #endif |
| #if defined(HAS_ARGBMIRRORROW_AVX2) |
| if (TestCpuFlag(kCpuHasAVX2)) { |
| ARGBMirrorRow = ARGBMirrorRow_Any_AVX2; |
| if (IS_ALIGNED(width, 8)) { |
| ARGBMirrorRow = ARGBMirrorRow_AVX2; |
| } |
| } |
| #endif |
| #if defined(HAS_ARGBMIRRORROW_MSA) |
| if (TestCpuFlag(kCpuHasMSA)) { |
| ARGBMirrorRow = ARGBMirrorRow_Any_MSA; |
| if (IS_ALIGNED(width, 16)) { |
| ARGBMirrorRow = ARGBMirrorRow_MSA; |
| } |
| } |
| #endif |
| #if defined(HAS_ARGBMIRRORROW_LSX) |
| if (TestCpuFlag(kCpuHasLSX)) { |
| ARGBMirrorRow = ARGBMirrorRow_Any_LSX; |
| if (IS_ALIGNED(width, 8)) { |
| ARGBMirrorRow = ARGBMirrorRow_LSX; |
| } |
| } |
| #endif |
| #if defined(HAS_ARGBMIRRORROW_LASX) |
| if (TestCpuFlag(kCpuHasLASX)) { |
| ARGBMirrorRow = ARGBMirrorRow_Any_LASX; |
| if (IS_ALIGNED(width, 16)) { |
| ARGBMirrorRow = ARGBMirrorRow_LASX; |
| } |
| } |
| #endif |
| |
| // Mirror plane |
| for (y = 0; y < height; ++y) { |
| ARGBMirrorRow(src_argb, dst_argb, width); |
| src_argb += src_stride_argb; |
| dst_argb += dst_stride_argb; |
| } |
| return 0; |
| } |
| |
| // RGB24 mirror. |
| LIBYUV_API |
| int RGB24Mirror(const uint8_t* src_rgb24, |
| int src_stride_rgb24, |
| uint8_t* dst_rgb24, |
| int dst_stride_rgb24, |
| int width, |
| int height) { |
| int y; |
| void (*RGB24MirrorRow)(const uint8_t* src, uint8_t* dst, int width) = |
| RGB24MirrorRow_C; |
| if (!src_rgb24 || !dst_rgb24 || 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; |
| } |
| #if defined(HAS_RGB24MIRRORROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| RGB24MirrorRow = RGB24MirrorRow_Any_NEON; |
| if (IS_ALIGNED(width, 16)) { |
| RGB24MirrorRow = RGB24MirrorRow_NEON; |
| } |
| } |
| #endif |
| #if defined(HAS_RGB24MIRRORROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| RGB24MirrorRow = RGB24MirrorRow_Any_SSSE3; |
| if (IS_ALIGNED(width, 16)) { |
| RGB24MirrorRow = RGB24MirrorRow_SSSE3; |
| } |
| } |
| #endif |
| |
| // Mirror plane |
| for (y = 0; y < height; ++y) { |
| RGB24MirrorRow(src_rgb24, dst_rgb24, width); |
| src_rgb24 += src_stride_rgb24; |
| dst_rgb24 += dst_stride_rgb24; |
| } |
| return 0; |
| } |
| |
| // Alpha Blend 2 ARGB images and store to destination. |
| LIBYUV_API |
| int ARGBBlend(const uint8_t* src_argb0, |
| int src_stride_argb0, |
| const uint8_t* src_argb1, |
| int src_stride_argb1, |
| uint8_t* dst_argb, |
| int dst_stride_argb, |
| int width, |
| int height) { |
| int y; |
| void (*ARGBBlendRow)(const uint8_t* src_argb, const uint8_t* src_argb1, |
| uint8_t* dst_argb, int width) = ARGBBlendRow_C; |
| if (!src_argb0 || !src_argb1 || !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_argb0 == width * 4 && src_stride_argb1 == width * 4 && |
| dst_stride_argb == width * 4) { |
| width *= height; |
| height = 1; |
| src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0; |
| } |
| #if defined(HAS_ARGBBLENDROW_SSSE3) |
| if (TestCpuFlag(kCpuHasSSSE3)) { |
| ARGBBlendRow = ARGBBlendRow_SSSE3; |
| } |
| #endif |
| #if defined(HAS_ARGBBLENDROW_NEON) |
| if (TestCpuFlag(kCpuHasNEON)) { |
| ARGBBlendRow = ARGBBlendRow_NEON; |
| } |
| #endif |
| #if defined(HAS_ARGBBLENDROW_MSA) |
| if (TestCpuFlag(kCpuHasMSA)) { |
| ARGBBlendRow = ARGBBlendRow_MSA; |
| } |
| #endif |
| #if defined(HAS_ARGBBLENDROW_LSX) |
| if (TestCpuFlag(kCpuHasLSX)) { |
| ARGBBlendRow = ARGBBlendRow_LSX; |
| } |
| #endif |
| #if defined(HAS_ARGBBLENDROW_RVV) |
| if (TestCpuFlag(kCpuHasRVV)) { |
| ARGBBlendRow = ARGBBlendRow_RVV; |
| } |
| #endif |
| for (y = 0; y < height; ++y) { |
| ARGBBlendRow(src_argb0, src_argb1, dst_argb, width); |
| src_argb0 += src_stride_argb0; |
| src_argb1 += src_stride_argb1; |
| dst_argb += dst_stride_argb; |
|