* Copyright (C) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pixel_convert.h"
#include <map>
#include <mutex>
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
#include "astcenc.h"
#endif
#ifndef _WIN32
#include "securec.h"
#else
#include "memory.h"
#endif
#include "pixel_convert_adapter.h"
#include "image_utils.h"
#include "pixel_map.h"
#include "image_log.h"
#include "media_errors.h"
#include "memory_manager.h"
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
#include "surface_buffer.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include "libavcodec/avcodec.h"
#ifdef __cplusplus
}
#endif
#undef LOG_DOMAIN
#define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
#undef LOG_TAG
#define LOG_TAG "PixelConvert"
namespace OHOS {
namespace Media {
using namespace std;
#if __BYTE_ORDER == __LITTLE_ENDIAN
constexpr bool IS_LITTLE_ENDIAN = true;
#else
constexpr bool IS_LITTLE_ENDIAN = false;
#endif
constexpr int32_t DMA_LINE_SIZE = 256;
static const uint8_t NUM_2 = 2;
constexpr uint8_t YUV420_P010_BYTES = 2;
constexpr uint8_t BYTE_POS_0 = 0;
constexpr uint8_t BYTE_POS_1 = 1;
constexpr uint8_t BYTE_POS_2 = 2;
constexpr uint8_t BYTE_POS_3 = 3;
constexpr uint8_t BYTE_POS_4 = 4;
constexpr uint8_t BYTE_POS_5 = 5;
constexpr uint8_t BYTE_POS_6 = 6;
constexpr uint8_t BYTE_POS_7 = 7;
constexpr uint8_t BYTE_POS_8 = 8;
constexpr uint8_t BYTE_POS_9 = 9;
constexpr uint8_t BYTE_POS_10 = 10;
constexpr uint8_t BYTE_POS_11 = 11;
constexpr uint8_t BYTE_POS_12 = 12;
constexpr uint8_t BYTE_POS_13 = 13;
constexpr uint8_t BYTE_POS_14 = 14;
constexpr uint8_t BYTE_POS_15 = 15;
constexpr uint32_t ASTC_BLOCK_SIZE_4 = 4;
constexpr uint32_t ASTC_MAGIC_ID = 0x5CA1AB13;
constexpr uint32_t UNPACK_SHIFT_1 = 8;
constexpr uint32_t UNPACK_SHIFT_2 = 16;
constexpr uint32_t UNPACK_SHIFT_3 = 24;
constexpr uint32_t ASTC_UNIT_BYTES = 16;
constexpr uint32_t ASTC_DIM_MAX = 8192;
constexpr uint32_t BYTES_PER_PIXEL = 4;
constexpr uint32_t BIT_SHIFT_16BITS = 16;
constexpr uint32_t EVEN_ALIGNMENT = 2;
constexpr int32_t CONVERT_ERROR = -1;
constexpr uint32_t UV_PLANES_COUNT = 2;
constexpr uint8_t RGB565_EXTRA_BYTES = 2;
static const std::map<YuvConversion, const int> SWS_CS_COEFFICIENT = {
{YuvConversion::BT601, SWS_CS_DEFAULT},
{YuvConversion::BT709, SWS_CS_ITU709},
{YuvConversion::BT2020, SWS_CS_BT2020},
{YuvConversion::BT240, SWS_CS_SMPTE240M},
{YuvConversion::BTFCC, SWS_CS_FCC}
};
struct AstcInfo {
uint32_t astcBufSize;
uint8_t *astcBuf;
PixelFormat format;
Size astcSize;
unsigned int dimX;
unsigned int dimY;
};
static void AlphaTypeConvertOnRGB(uint32_t &A, uint32_t &R, uint32_t &G, uint32_t &B,
const ProcFuncExtension &extension)
{
switch (extension.alphaConvertType) {
case AlphaConvertType::PREMUL_CONVERT_UNPREMUL:
R = Unpremul255(R, A);
G = Unpremul255(G, A);
B = Unpremul255(B, A);
break;
case AlphaConvertType::PREMUL_CONVERT_OPAQUE:
R = Unpremul255(R, A);
G = Unpremul255(G, A);
B = Unpremul255(B, A);
A = ALPHA_OPAQUE;
break;
case AlphaConvertType::UNPREMUL_CONVERT_PREMUL:
R = Premul255(R, A);
G = Premul255(G, A);
B = Premul255(B, A);
break;
case AlphaConvertType::UNPREMUL_CONVERT_OPAQUE:
A = ALPHA_OPAQUE;
break;
default:
break;
}
}
static uint32_t FillARGB8888(uint32_t A, uint32_t R, uint32_t G, uint32_t B)
{
if (IS_LITTLE_ENDIAN) {
return ((B << SHIFT_24_BIT) | (G << SHIFT_16_BIT) | (R << SHIFT_8_BIT) | A);
}
return ((A << SHIFT_24_BIT) | (R << SHIFT_16_BIT) | (G << SHIFT_8_BIT) | B);
}
static uint32_t FillABGR8888(uint32_t A, uint32_t B, uint32_t G, uint32_t R)
{
if (IS_LITTLE_ENDIAN) {
return ((R << SHIFT_24_BIT) | (G << SHIFT_16_BIT) | (B << SHIFT_8_BIT) | A);
}
return ((A << SHIFT_24_BIT) | (B << SHIFT_16_BIT) | (G << SHIFT_8_BIT) | R);
}
static uint32_t FillRGBA8888(uint32_t R, uint32_t G, uint32_t B, uint32_t A)
{
if (IS_LITTLE_ENDIAN) {
return ((A << SHIFT_24_BIT) | (B << SHIFT_16_BIT) | (G << SHIFT_8_BIT) | R);
}
return ((R << SHIFT_24_BIT) | (G << SHIFT_16_BIT) | (B << SHIFT_8_BIT) | A);
}
static uint32_t FillBGRA8888(uint32_t B, uint32_t G, uint32_t R, uint32_t A)
{
if (IS_LITTLE_ENDIAN) {
return ((A << SHIFT_24_BIT) | (R << SHIFT_16_BIT) | (G << SHIFT_8_BIT) | B);
}
return ((B << SHIFT_24_BIT) | (G << SHIFT_16_BIT) | (R << SHIFT_8_BIT) | A);
}
static uint16_t FillRGB565(uint32_t R, uint32_t G, uint32_t B)
{
if (IS_LITTLE_ENDIAN) {
return ((B << SHIFT_11_BIT) | (G << SHIFT_5_BIT) | R);
}
return ((R << SHIFT_11_BIT) | (G << SHIFT_5_BIT) | B);
}
static uint64_t FillRGBAF16(float R, float G, float B, float A)
{
uint64_t R16 = FloatToHalf(R);
uint64_t G16 = FloatToHalf(G);
uint64_t B16 = FloatToHalf(B);
uint64_t A16 = FloatToHalf(A);
if (IS_LITTLE_ENDIAN) {
return ((A16 << SHIFT_48_BIT) | (R16 << SHIFT_32_BIT) | (G16 << SHIFT_16_BIT) | B16);
}
return ((B16 << SHIFT_48_BIT) | (G16 << SHIFT_32_BIT) | (R16 << SHIFT_16_BIT) | A16);
}
constexpr uint8_t BYTE_BITS = 8;
constexpr uint8_t BYTE_BITS_MAX_INDEX = 7;
template<typename T>
static void BitConvert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t white,
uint32_t black)
{
destinationRow[0] = (*sourceRow & GET_8_BIT) ? white : black;
uint32_t bitIndex = 0;
uint8_t currentSource = 0;
* 1 byte = 8 bit
* 7: 8 bit index
*/
for (uint32_t i = 1; i < sourceWidth; i++) {
bitIndex = i % BYTE_BITS;
currentSource = *(sourceRow + i / BYTE_BITS);
if (bitIndex > BYTE_BITS_MAX_INDEX) {
continue;
}
destinationRow[i] = ((currentSource >> (BYTE_BITS_MAX_INDEX - bitIndex)) & GET_1_BIT) ? white : black;
}
}
static void BitConvertGray(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint8_t *newDestinationRow = static_cast<uint8_t *>(destinationRow);
BitConvert(newDestinationRow, sourceRow, sourceWidth, GRAYSCALE_WHITE, GRAYSCALE_BLACK);
}
static void BitConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
BitConvert(newDestinationRow, sourceRow, sourceWidth, ARGB_WHITE, ARGB_BLACK);
}
static void BitConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint16_t *newDestinationRow = static_cast<uint16_t *>(destinationRow);
BitConvert(newDestinationRow, sourceRow, sourceWidth, RGB_WHITE, RGB_BLACK);
}
constexpr uint32_t BRANCH_GRAY_TO_ARGB8888 = 0x00000001;
constexpr uint32_t BRANCH_GRAY_TO_RGB565 = 0x00000002;
template<typename T>
static void GrayConvert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t R = sourceRow[i];
uint32_t G = sourceRow[i];
uint32_t B = sourceRow[i];
if (branch == BRANCH_GRAY_TO_ARGB8888) {
uint32_t A = ALPHA_OPAQUE;
destinationRow[i] = ((A << SHIFT_24_BIT) | (R << SHIFT_16_BIT) | (G << SHIFT_8_BIT) | B);
} else if (branch == BRANCH_GRAY_TO_RGB565) {
R = R >> SHIFT_3_BIT;
G = G >> SHIFT_2_BIT;
B = B >> SHIFT_3_BIT;
destinationRow[i] = ((R << SHIFT_11_BIT) | (G << SHIFT_5_BIT) | B);
} else {
break;
}
}
}
static void GrayConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
GrayConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_GRAY_TO_ARGB8888);
}
static void GrayConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint16_t *newDestinationRow = static_cast<uint16_t *>(destinationRow);
GrayConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_GRAY_TO_RGB565);
}
constexpr uint32_t BRANCH_ARGB8888 = 0x10000001;
constexpr uint32_t BRANCH_ALPHA = 0x10000002;
template<typename T>
static void GrayAlphaConvert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch,
const ProcFuncExtension &extension)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t A = sourceRow[1];
uint32_t R = sourceRow[0];
uint32_t G = sourceRow[0];
uint32_t B = sourceRow[0];
AlphaTypeConvertOnRGB(A, R, G, B, extension);
if (branch == BRANCH_ARGB8888) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_ALPHA) {
destinationRow[i] = A;
} else {
break;
}
sourceRow += SIZE_2_BYTE;
}
}
static void GrayAlphaConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
GrayAlphaConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888, extension);
}
static void GrayAlphaConvertAlpha(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint8_t *newDestinationRow = static_cast<uint8_t *>(destinationRow);
GrayAlphaConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ALPHA, extension);
}
constexpr uint32_t BRANCH_BGR888_TO_ARGB8888 = 0x20000001;
constexpr uint32_t BRANCH_BGR888_TO_RGBA8888 = 0x20000002;
constexpr uint32_t BRANCH_BGR888_TO_BGRA8888 = 0x20000003;
constexpr uint32_t BRANCH_BGR888_TO_RGB565 = 0x20000004;
constexpr uint32_t BRANCH_BGR888_TO_RGBAF16 = 0x20000005;
template<typename T>
static void BGR888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t R = sourceRow[2];
uint32_t G = sourceRow[1];
uint32_t B = sourceRow[0];
uint32_t A = ALPHA_OPAQUE;
if (branch == BRANCH_BGR888_TO_ARGB8888) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_BGR888_TO_RGBA8888) {
destinationRow[i] = FillRGBA8888(R, G, B, A);
} else if (branch == BRANCH_BGR888_TO_BGRA8888) {
destinationRow[i] = FillBGRA8888(B, G, R, A);
} else if (branch == BRANCH_BGR888_TO_RGB565) {
R = R >> SHIFT_3_BIT;
G = G >> SHIFT_2_BIT;
B = B >> SHIFT_3_BIT;
destinationRow[i] = ((B << SHIFT_11_BIT) | (G << SHIFT_5_BIT) | R);
} else if (branch == BRANCH_BGR888_TO_RGBAF16) {
destinationRow[i] = FillRGBAF16(R, G, B, A);
} else {
break;
}
sourceRow += SIZE_3_BYTE;
}
}
static void BGR888ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_ARGB8888);
}
static void BGR888ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_RGBA8888);
}
static void BGR888ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_BGRA8888);
}
static void BGR888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint16_t *newDestinationRow = static_cast<uint16_t *>(destinationRow);
BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_RGB565);
}
static void BGR888ConvertRGBAF16(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint64_t *newDestinationRow = static_cast<uint64_t *>(destinationRow);
BGR888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGR888_TO_RGBAF16);
}
constexpr uint32_t BRANCH_RGB888_TO_ARGB8888 = 0x30000001;
constexpr uint32_t BRANCH_RGB888_TO_RGBA8888 = 0x30000002;
constexpr uint32_t BRANCH_RGB888_TO_BGRA8888 = 0x30000003;
constexpr uint32_t BRANCH_RGB888_TO_RGB565 = 0x30000004;
constexpr uint32_t BRANCH_RGB888_TO_RGBAF16 = 0x30000005;
template<typename T>
static void RGB888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t R = sourceRow[0];
uint32_t G = sourceRow[1];
uint32_t B = sourceRow[2];
uint32_t A = ALPHA_OPAQUE;
if (branch == BRANCH_RGB888_TO_ARGB8888) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_RGB888_TO_RGBA8888) {
destinationRow[i] = FillRGBA8888(R, G, B, A);
} else if (branch == BRANCH_RGB888_TO_BGRA8888) {
destinationRow[i] = FillBGRA8888(B, G, R, A);
} else if (branch == BRANCH_RGB888_TO_RGB565) {
R = R >> SHIFT_3_BIT;
G = G >> SHIFT_2_BIT;
B = B >> SHIFT_3_BIT;
destinationRow[i] = FillRGB565(R, G, B);
} else if (branch == BRANCH_RGB888_TO_RGBAF16) {
destinationRow[i] = FillRGBAF16(R, G, B, A);
} else {
break;
}
sourceRow += SIZE_3_BYTE;
}
}
static void RGB888ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_ARGB8888);
}
static void RGB888ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_RGBA8888);
}
static void RGB888ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_BGRA8888);
}
static void RGB888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint16_t *newDestinationRow = static_cast<uint16_t *>(destinationRow);
RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_RGB565);
}
static void RGB888ConvertRGBAF16(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint64_t *newDestinationRow = static_cast<uint64_t *>(destinationRow);
RGB888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB888_TO_RGBAF16);
}
constexpr uint32_t BRANCH_RGBA8888_TO_RGBA8888_ALPHA = 0x40000001;
constexpr uint32_t BRANCH_RGBA8888_TO_ARGB8888 = 0x40000002;
constexpr uint32_t BRANCH_RGBA8888_TO_BGRA8888 = 0x40000003;
constexpr uint32_t BRANCH_RGBA8888_TO_RGB565 = 0x40000004;
constexpr uint32_t BRANCH_RGBA8888_TO_RGBAF16 = 0x40000005;
template<typename T>
static void RGBA8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch,
const ProcFuncExtension &extension)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t R = sourceRow[0];
uint32_t G = sourceRow[1];
uint32_t B = sourceRow[2];
uint32_t A = sourceRow[3];
AlphaTypeConvertOnRGB(A, R, G, B, extension);
if (branch == BRANCH_RGBA8888_TO_RGBA8888_ALPHA) {
destinationRow[i] = FillRGBA8888(R, G, B, A);
} else if (branch == BRANCH_RGBA8888_TO_ARGB8888) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_RGBA8888_TO_BGRA8888) {
destinationRow[i] = FillBGRA8888(B, G, R, A);
} else if (branch == BRANCH_RGBA8888_TO_RGB565) {
R = R >> SHIFT_3_BIT;
G = G >> SHIFT_2_BIT;
B = B >> SHIFT_3_BIT;
destinationRow[i] = FillRGB565(R, G, B);
} else if (branch == BRANCH_RGBA8888_TO_RGBAF16) {
destinationRow[i] = FillRGBAF16(R, G, B, A);
} else {
break;
}
sourceRow += SIZE_4_BYTE;
}
}
static void RGBA8888ConvertRGBA8888Alpha(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_RGBA8888_ALPHA, extension);
}
static void RGBA8888ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_ARGB8888, extension);
}
static void RGBA8888ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_BGRA8888, extension);
}
static void RGBA8888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint16_t *newDestinationRow = static_cast<uint16_t *>(destinationRow);
RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_RGB565, extension);
}
static void RGBA8888ConvertRGBAF16(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint64_t *newDestinationRow = static_cast<uint64_t *>(destinationRow);
RGBA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA8888_TO_RGBAF16, extension);
}
constexpr uint32_t BRANCH_BGRA8888_TO_BGRA8888_ALPHA = 0x80000001;
constexpr uint32_t BRANCH_BGRA8888_TO_ARGB8888 = 0x80000002;
constexpr uint32_t BRANCH_BGRA8888_TO_RGBA8888 = 0x80000003;
constexpr uint32_t BRANCH_BGRA8888_TO_RGB565 = 0x80000004;
constexpr uint32_t BRANCH_BGRA8888_TO_RGBAF16 = 0x80000005;
template<typename T>
static void BGRA8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch,
const ProcFuncExtension &extension)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t B = sourceRow[0];
uint32_t G = sourceRow[1];
uint32_t R = sourceRow[2];
uint32_t A = sourceRow[3];
AlphaTypeConvertOnRGB(A, R, G, B, extension);
if (branch == BRANCH_BGRA8888_TO_BGRA8888_ALPHA) {
destinationRow[i] = FillBGRA8888(B, G, R, A);
} else if (branch == BRANCH_BGRA8888_TO_ARGB8888) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_BGRA8888_TO_RGBA8888) {
destinationRow[i] = FillRGBA8888(R, G, B, A);
} else if (branch == BRANCH_BGRA8888_TO_RGB565) {
R = R >> SHIFT_3_BIT;
G = G >> SHIFT_2_BIT;
B = B >> SHIFT_3_BIT;
destinationRow[i] = FillRGB565(R, G, B);
} else if (branch == BRANCH_BGRA8888_TO_RGBAF16) {
destinationRow[i] = FillRGBAF16(R, G, B, A);
} else {
break;
}
sourceRow += SIZE_4_BYTE;
}
}
static void BGRA8888ConvertBGRA8888Alpha(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_BGRA8888_ALPHA, extension);
}
static void BGRA8888ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_ARGB8888, extension);
}
static void BGRA8888ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_RGBA8888, extension);
}
static void BGRA8888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint16_t *newDestinationRow = static_cast<uint16_t *>(destinationRow);
BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_RGB565, extension);
}
static void BGRA8888ConvertRGBAF16(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint64_t *newDestinationRow = static_cast<uint64_t *>(destinationRow);
BGRA8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_BGRA8888_TO_RGBAF16, extension);
}
constexpr uint32_t BRANCH_ARGB8888_TO_ARGB8888_ALPHA = 0x90000001;
constexpr uint32_t BRANCH_ARGB8888_TO_RGBA8888 = 0x90000002;
constexpr uint32_t BRANCH_ARGB8888_TO_BGRA8888 = 0x90000003;
constexpr uint32_t BRANCH_ARGB8888_TO_RGB565 = 0x90000004;
constexpr uint32_t BRANCH_ARGB8888_TO_RGBAF16 = 0x90000005;
template<typename T>
static void ARGB8888Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch,
const ProcFuncExtension &extension)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t A = sourceRow[0];
uint32_t R = sourceRow[1];
uint32_t G = sourceRow[2];
uint32_t B = sourceRow[3];
AlphaTypeConvertOnRGB(A, R, G, B, extension);
if (branch == BRANCH_ARGB8888_TO_ARGB8888_ALPHA) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_ARGB8888_TO_RGBA8888) {
destinationRow[i] = FillRGBA8888(R, G, B, A);
} else if (branch == BRANCH_ARGB8888_TO_BGRA8888) {
destinationRow[i] = FillBGRA8888(B, G, R, A);
} else if (branch == BRANCH_ARGB8888_TO_RGB565) {
R = R >> SHIFT_3_BIT;
G = G >> SHIFT_2_BIT;
B = B >> SHIFT_3_BIT;
destinationRow[i] = FillRGB565(R, G, B);
} else if (branch == BRANCH_ARGB8888_TO_RGBAF16) {
destinationRow[i] = FillRGBAF16(R, G, B, A);
} else {
break;
}
sourceRow += SIZE_4_BYTE;
}
}
static void ARGB8888ConvertARGB8888Alpha(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_ARGB8888_ALPHA, extension);
}
static void ARGB8888ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_RGBA8888, extension);
}
static void ARGB8888ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_BGRA8888, extension);
}
static void ARGB8888ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint16_t *newDestinationRow = static_cast<uint16_t *>(destinationRow);
ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_RGB565, extension);
}
static void ARGB8888ConvertRGBAF16(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint64_t *newDestinationRow = static_cast<uint64_t *>(destinationRow);
ARGB8888Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_ARGB8888_TO_RGBAF16, extension);
}
constexpr uint32_t BRANCH_RGB161616_TO_ARGB8888 = 0x50000001;
constexpr uint32_t BRANCH_RGB161616_TO_ABGR8888 = 0x50000002;
constexpr uint32_t BRANCH_RGB161616_TO_RGBA8888 = 0x50000003;
constexpr uint32_t BRANCH_RGB161616_TO_BGRA8888 = 0x50000004;
constexpr uint32_t BRANCH_RGB161616_TO_RGB565 = 0x50000005;
constexpr uint32_t BRANCH_RGB161616_TO_RGBAF16 = 0x50000006;
template<typename T>
static void RGB161616Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t R = sourceRow[0];
uint32_t G = sourceRow[2];
uint32_t B = sourceRow[4];
uint32_t A = ALPHA_OPAQUE;
if (branch == BRANCH_RGB161616_TO_ARGB8888) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_RGB161616_TO_ABGR8888) {
destinationRow[i] = FillABGR8888(A, B, G, R);
} else if (branch == BRANCH_RGB161616_TO_RGBA8888) {
destinationRow[i] = FillRGBA8888(R, G, B, A);
} else if (branch == BRANCH_RGB161616_TO_BGRA8888) {
destinationRow[i] = FillBGRA8888(B, G, R, A);
} else if (branch == BRANCH_RGB161616_TO_RGB565) {
R = R >> SHIFT_3_BIT;
G = G >> SHIFT_2_BIT;
B = B >> SHIFT_3_BIT;
destinationRow[i] = FillRGB565(R, G, B);
} else if (branch == BRANCH_RGB161616_TO_RGBAF16) {
destinationRow[i] = FillRGBAF16(R, G, B, A);
} else {
break;
}
sourceRow += SIZE_6_BYTE;
}
}
static void RGB161616ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_ARGB8888);
}
static void RGB161616ConvertABGR8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_ABGR8888);
}
static void RGB161616ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_RGBA8888);
}
static void RGB161616ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_BGRA8888);
}
static void RGB161616ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint16_t *newDestinationRow = static_cast<uint16_t *>(destinationRow);
RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_RGB565);
}
static void RGB161616ConvertRGBAF16(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint64_t *newDestinationRow = static_cast<uint64_t *>(destinationRow);
RGB161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB161616_TO_RGBAF16);
}
constexpr uint32_t BRANCH_RGBA16161616_TO_ARGB8888 = 0x60000001;
constexpr uint32_t BRANCH_RGBA16161616_TO_ABGR8888 = 0x60000002;
constexpr uint32_t BRANCH_RGBA16161616_TO_RGBA8888 = 0x60000003;
constexpr uint32_t BRANCH_RGBA16161616_TO_BGRA8888 = 0x60000004;
constexpr uint32_t BRANCH_RGBA16161616_TO_RGBAF16 = 0x60000005;
template<typename T>
static void RGBA16161616Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch,
const ProcFuncExtension &extension)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t R = sourceRow[0];
uint32_t G = sourceRow[2];
uint32_t B = sourceRow[4];
uint32_t A = sourceRow[6];
AlphaTypeConvertOnRGB(A, R, G, B, extension);
if (branch == BRANCH_RGBA16161616_TO_ARGB8888) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_RGBA16161616_TO_ABGR8888) {
destinationRow[i] = FillABGR8888(A, B, G, R);
} else if (branch == BRANCH_RGBA16161616_TO_RGBA8888) {
destinationRow[i] = FillRGBA8888(A, B, G, R);
} else if (branch == BRANCH_RGBA16161616_TO_BGRA8888) {
destinationRow[i] = FillBGRA8888(A, B, G, R);
} else if (branch == BRANCH_RGBA16161616_TO_RGBAF16) {
destinationRow[i] = FillRGBAF16(R, G, B, A);
} else {
break;
}
sourceRow += SIZE_8_BYTE;
}
}
static void RGBA16161616ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_ARGB8888, extension);
}
static void RGBA16161616ConvertABGR8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_ABGR8888, extension);
}
static void RGBA16161616ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_RGBA8888, extension);
}
static void RGBA16161616ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_BGRA8888, extension);
}
static void RGBA16161616ConvertRGBAF16(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint64_t *newDestinationRow = static_cast<uint64_t *>(destinationRow);
RGBA16161616Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBA16161616_TO_RGBAF16, extension);
}
constexpr uint32_t BRANCH_CMYK_TO_ARGB8888 = 0x70000001;
constexpr uint32_t BRANCH_CMYK_TO_ABGR8888 = 0x70000002;
constexpr uint32_t BRANCH_CMYK_TO_RGBA8888 = 0x70000003;
constexpr uint32_t BRANCH_CMYK_TO_BGRA8888 = 0x70000004;
constexpr uint32_t BRANCH_CMYK_TO_RGB565 = 0x70000005;
template<typename T>
static void CMYKConvert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint8_t C = sourceRow[0];
uint8_t M = sourceRow[1];
uint8_t Y = sourceRow[2];
uint8_t K = sourceRow[3];
uint32_t R = Premul255(C, K);
uint32_t G = Premul255(M, K);
uint32_t B = Premul255(Y, K);
uint32_t A = ALPHA_OPAQUE;
if (branch == BRANCH_CMYK_TO_ARGB8888) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_CMYK_TO_ABGR8888) {
destinationRow[i] = FillABGR8888(A, B, G, R);
} else if (branch == BRANCH_CMYK_TO_RGBA8888) {
destinationRow[i] = FillRGBA8888(R, G, B, A);
} else if (branch == BRANCH_CMYK_TO_BGRA8888) {
destinationRow[i] = FillBGRA8888(B, G, R, A);
} else if (branch == BRANCH_CMYK_TO_RGB565) {
R = R >> SHIFT_3_BIT;
G = R >> SHIFT_2_BIT;
B = B >> SHIFT_3_BIT;
destinationRow[i] = FillRGB565(R, G, B);
} else {
break;
}
sourceRow += SIZE_4_BYTE;
}
}
static void CMYKConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
CMYKConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_CMYK_TO_ARGB8888);
}
static void CMYKConvertABGR8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
CMYKConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_CMYK_TO_ABGR8888);
}
static void CMYKConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
CMYKConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_CMYK_TO_RGBA8888);
}
static void CMYKConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
CMYKConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_CMYK_TO_BGRA8888);
}
static void CMYKConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
CMYKConvert(newDestinationRow, sourceRow, sourceWidth, BRANCH_CMYK_TO_RGB565);
}
constexpr uint32_t BRANCH_RGB565_TO_ARGB8888 = 0x11000001;
constexpr uint32_t BRANCH_RGB565_TO_RGBA8888 = 0x11000002;
constexpr uint32_t BRANCH_RGB565_TO_BGRA8888 = 0x11000003;
constexpr uint32_t BRANCH_RGB565_TO_RGBAF16 = 0x11000004;
template<typename T>
static void RGB565Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t R = (sourceRow[0] >> SHIFT_3_BIT) & SHIFT_5_MASK;
uint32_t G = ((sourceRow[0] & SHIFT_3_MASK) << SHIFT_3_BIT) | ((sourceRow[1] >> SHIFT_5_BIT) & SHIFT_3_MASK);
uint32_t B = sourceRow[1] & SHIFT_5_MASK;
uint32_t A = ALPHA_OPAQUE;
if (branch == BRANCH_RGB565_TO_ARGB8888) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_RGB565_TO_RGBA8888) {
destinationRow[i] = FillRGBA8888(R, G, B, A);
} else if (branch == BRANCH_RGB565_TO_BGRA8888) {
destinationRow[i] = FillBGRA8888(B, G, R, A);
} else if (branch == BRANCH_RGB565_TO_RGBAF16) {
destinationRow[i] = FillRGBAF16(R, G, B, A);
} else {
break;
}
sourceRow += SIZE_2_BYTE;
}
}
static void RGB565ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGB565Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB565_TO_ARGB8888);
}
static void RGB565ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGB565Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB565_TO_RGBA8888);
}
static void RGB565ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGB565Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB565_TO_BGRA8888);
}
static void RGB565ConvertRGBAF16(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint64_t *newDestinationRow = static_cast<uint64_t *>(destinationRow);
RGB565Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGB565_TO_RGBAF16);
}
constexpr uint32_t BRANCH_RGBAF16_TO_ARGB8888 = 0x13000001;
constexpr uint32_t BRANCH_RGBAF16_TO_RGBA8888 = 0x13000002;
constexpr uint32_t BRANCH_RGBAF16_TO_BGRA8888 = 0x13000003;
constexpr uint32_t BRANCH_RGBAF16_TO_ABGR8888 = 0x13000004;
constexpr uint32_t BRANCH_RGBAF16_TO_RGB565 = 0x13000005;
template<typename T>
static void RGBAF16Convert(T *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth, uint32_t branch,
const ProcFuncExtension &extension)
{
for (uint32_t i = 0; i < sourceWidth; i++) {
uint32_t R = HalfToUint32(sourceRow, IS_LITTLE_ENDIAN);
uint32_t G = HalfToUint32(sourceRow + 2, IS_LITTLE_ENDIAN);
uint32_t B = HalfToUint32(sourceRow + 4, IS_LITTLE_ENDIAN);
uint32_t A = HalfToUint32(sourceRow + 6, IS_LITTLE_ENDIAN);
AlphaTypeConvertOnRGB(A, R, G, B, extension);
if (branch == BRANCH_RGBAF16_TO_ARGB8888) {
destinationRow[i] = FillARGB8888(A, R, G, B);
} else if (branch == BRANCH_RGBAF16_TO_RGBA8888) {
destinationRow[i] = FillRGBA8888(R, G, B, A);
} else if (branch == BRANCH_RGBAF16_TO_BGRA8888) {
destinationRow[i] = FillBGRA8888(B, G, R, A);
} else if (branch == BRANCH_RGBAF16_TO_ABGR8888) {
destinationRow[i] = FillABGR8888(A, B, G, R);
} else if (branch == BRANCH_RGBAF16_TO_RGB565) {
R = R >> SHIFT_3_BIT;
G = G >> SHIFT_2_BIT;
B = B >> SHIFT_3_BIT;
destinationRow[i] = FillRGB565(R, G, B);
} else {
break;
}
sourceRow += SIZE_8_BYTE;
}
}
static void RGBAF16ConvertARGB8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBAF16Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBAF16_TO_ARGB8888, extension);
}
static void RGBAF16ConvertRGBA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBAF16Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBAF16_TO_RGBA8888, extension);
}
static void RGBAF16ConvertBGRA8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBAF16Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBAF16_TO_BGRA8888, extension);
}
static void RGBAF16ConvertABGR8888(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint32_t *newDestinationRow = static_cast<uint32_t *>(destinationRow);
RGBAF16Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBAF16_TO_ABGR8888, extension);
}
static void RGBAF16ConvertRGB565(void *destinationRow, const uint8_t *sourceRow, uint32_t sourceWidth,
const ProcFuncExtension &extension)
{
uint16_t *newDestinationRow = static_cast<uint16_t *>(destinationRow);
RGBAF16Convert(newDestinationRow, sourceRow, sourceWidth, BRANCH_RGBAF16_TO_RGB565, extension);
}
static map<string, ProcFuncType> g_procMapping;
static mutex g_procMutex;
static string MakeKey(uint32_t srcFormat, uint32_t dstFormat)
{
return to_string(srcFormat) + ("_") + to_string(dstFormat);
}
static void InitGrayProc()
{
g_procMapping.emplace(MakeKey(GRAY_BIT, ARGB_8888), &BitConvertARGB8888);
g_procMapping.emplace(MakeKey(GRAY_BIT, RGB_565), &BitConvertRGB565);
g_procMapping.emplace(MakeKey(GRAY_BIT, ALPHA_8), &BitConvertGray);
g_procMapping.emplace(MakeKey(ALPHA_8, ARGB_8888), &GrayConvertARGB8888);
g_procMapping.emplace(MakeKey(ALPHA_8, RGB_565), &GrayConvertRGB565);
g_procMapping.emplace(MakeKey(GRAY_ALPHA, ARGB_8888), &GrayAlphaConvertARGB8888);
g_procMapping.emplace(MakeKey(GRAY_ALPHA, ALPHA_8), &GrayAlphaConvertAlpha);
}
static void InitRGBProc()
{
g_procMapping.emplace(MakeKey(RGB_888, ARGB_8888), &RGB888ConvertARGB8888);
g_procMapping.emplace(MakeKey(RGB_888, RGBA_8888), &RGB888ConvertRGBA8888);
g_procMapping.emplace(MakeKey(RGB_888, BGRA_8888), &RGB888ConvertBGRA8888);
g_procMapping.emplace(MakeKey(RGB_888, RGB_565), &RGB888ConvertRGB565);
g_procMapping.emplace(MakeKey(BGR_888, ARGB_8888), &BGR888ConvertARGB8888);
g_procMapping.emplace(MakeKey(BGR_888, RGBA_8888), &BGR888ConvertRGBA8888);
g_procMapping.emplace(MakeKey(BGR_888, BGRA_8888), &BGR888ConvertBGRA8888);
g_procMapping.emplace(MakeKey(BGR_888, RGB_565), &BGR888ConvertRGB565);
g_procMapping.emplace(MakeKey(RGB_161616, ARGB_8888), &RGB161616ConvertARGB8888);
g_procMapping.emplace(MakeKey(RGB_161616, ABGR_8888), &RGB161616ConvertABGR8888);
g_procMapping.emplace(MakeKey(RGB_161616, RGBA_8888), &RGB161616ConvertRGBA8888);
g_procMapping.emplace(MakeKey(RGB_161616, BGRA_8888), &RGB161616ConvertBGRA8888);
g_procMapping.emplace(MakeKey(RGB_161616, RGB_565), &RGB161616ConvertRGB565);
g_procMapping.emplace(MakeKey(RGB_565, ARGB_8888), &RGB565ConvertARGB8888);
g_procMapping.emplace(MakeKey(RGB_565, RGBA_8888), &RGB565ConvertRGBA8888);
g_procMapping.emplace(MakeKey(RGB_565, BGRA_8888), &RGB565ConvertBGRA8888);
}
static void InitRGBAProc()
{
g_procMapping.emplace(MakeKey(RGBA_8888, RGBA_8888), &RGBA8888ConvertRGBA8888Alpha);
g_procMapping.emplace(MakeKey(RGBA_8888, ARGB_8888), &RGBA8888ConvertARGB8888);
g_procMapping.emplace(MakeKey(RGBA_8888, BGRA_8888), &RGBA8888ConvertBGRA8888);
g_procMapping.emplace(MakeKey(RGBA_8888, RGB_565), &RGBA8888ConvertRGB565);
g_procMapping.emplace(MakeKey(BGRA_8888, RGBA_8888), &BGRA8888ConvertRGBA8888);
g_procMapping.emplace(MakeKey(BGRA_8888, ARGB_8888), &BGRA8888ConvertARGB8888);
g_procMapping.emplace(MakeKey(BGRA_8888, BGRA_8888), &BGRA8888ConvertBGRA8888Alpha);
g_procMapping.emplace(MakeKey(BGRA_8888, RGB_565), &BGRA8888ConvertRGB565);
g_procMapping.emplace(MakeKey(ARGB_8888, RGBA_8888), &ARGB8888ConvertRGBA8888);
g_procMapping.emplace(MakeKey(ARGB_8888, ARGB_8888), &ARGB8888ConvertARGB8888Alpha);
g_procMapping.emplace(MakeKey(ARGB_8888, BGRA_8888), &ARGB8888ConvertBGRA8888);
g_procMapping.emplace(MakeKey(ARGB_8888, RGB_565), &ARGB8888ConvertRGB565);
g_procMapping.emplace(MakeKey(RGBA_16161616, ARGB_8888), &RGBA16161616ConvertARGB8888);
g_procMapping.emplace(MakeKey(RGBA_16161616, RGBA_8888), &RGBA16161616ConvertRGBA8888);
g_procMapping.emplace(MakeKey(RGBA_16161616, BGRA_8888), &RGBA16161616ConvertBGRA8888);
g_procMapping.emplace(MakeKey(RGBA_16161616, ABGR_8888), &RGBA16161616ConvertABGR8888);
}
static void InitCMYKProc()
{
g_procMapping.emplace(MakeKey(CMKY, ARGB_8888), &CMYKConvertARGB8888);
g_procMapping.emplace(MakeKey(CMKY, RGBA_8888), &CMYKConvertRGBA8888);
g_procMapping.emplace(MakeKey(CMKY, BGRA_8888), &CMYKConvertBGRA8888);
g_procMapping.emplace(MakeKey(CMKY, ABGR_8888), &CMYKConvertABGR8888);
g_procMapping.emplace(MakeKey(CMKY, RGB_565), &CMYKConvertRGB565);
}
static void InitF16Proc()
{
g_procMapping.emplace(MakeKey(RGBA_F16, ARGB_8888), &RGBAF16ConvertARGB8888);
g_procMapping.emplace(MakeKey(RGBA_F16, RGBA_8888), &RGBAF16ConvertRGBA8888);
g_procMapping.emplace(MakeKey(RGBA_F16, BGRA_8888), &RGBAF16ConvertBGRA8888);
g_procMapping.emplace(MakeKey(RGBA_F16, ABGR_8888), &RGBAF16ConvertABGR8888);
g_procMapping.emplace(MakeKey(RGBA_F16, RGB_565), &RGBAF16ConvertRGB565);
g_procMapping.emplace(MakeKey(BGR_888, RGBA_F16), &BGR888ConvertRGBAF16);
g_procMapping.emplace(MakeKey(RGB_888, RGBA_F16), &RGB888ConvertRGBAF16);
g_procMapping.emplace(MakeKey(RGB_161616, RGBA_F16), &RGB161616ConvertRGBAF16);
g_procMapping.emplace(MakeKey(ARGB_8888, RGBA_F16), &ARGB8888ConvertRGBAF16);
g_procMapping.emplace(MakeKey(RGBA_8888, RGBA_F16), &RGBA8888ConvertRGBAF16);
g_procMapping.emplace(MakeKey(BGRA_8888, RGBA_F16), &BGRA8888ConvertRGBAF16);
g_procMapping.emplace(MakeKey(RGB_565, RGBA_F16), &RGB565ConvertRGBAF16);
g_procMapping.emplace(MakeKey(RGBA_16161616, RGBA_F16), &RGBA16161616ConvertRGBAF16);
}
static ProcFuncType GetProcFuncType(uint32_t srcPixelFormat, uint32_t dstPixelFormat)
{
unique_lock<mutex> guard(g_procMutex);
if (g_procMapping.empty()) {
InitGrayProc();
InitRGBProc();
InitRGBAProc();
InitCMYKProc();
InitF16Proc();
}
guard.unlock();
string procKey = MakeKey(srcPixelFormat, dstPixelFormat);
map<string, ProcFuncType>::iterator iter = g_procMapping.find(procKey);
if (iter != g_procMapping.end()) {
return iter->second;
}
return nullptr;
}
static AVPixelFormat PixelFormatToAVPixelFormat(const PixelFormat &pixelFormat)
{
auto formatSearch = PixelConvertAdapter::FFMPEG_PIXEL_FORMAT_MAP.find(pixelFormat);
return (formatSearch != PixelConvertAdapter::FFMPEG_PIXEL_FORMAT_MAP.end()) ?
formatSearch->second : AVPixelFormat::AV_PIX_FMT_NONE;
}
typedef struct FFMpegConvertInfo {
AVPixelFormat format = AVPixelFormat::AV_PIX_FMT_NONE;
int32_t width = 0;
int32_t height = 0;
int32_t alignSize = 1;
} FFMPEG_CONVERT_INFO;
static bool FFMpegConvert(const void *srcPixels, const FFMPEG_CONVERT_INFO& srcInfo,
void *dstPixels, const FFMPEG_CONVERT_INFO& dstInfo, YUVConvertColorSpaceDetails &colorSpaceDetails)
{
bool ret = true;
AVFrame *inputFrame = nullptr;
AVFrame *outputFrame = nullptr;
CHECK_ERROR_RETURN_RET_LOG(srcInfo.format == AVPixelFormat::AV_PIX_FMT_NONE ||
dstInfo.format == AVPixelFormat::AV_PIX_FMT_NONE, false, "unsupport src/dst pixel format!");
CHECK_ERROR_RETURN_RET_LOG((srcInfo.width <= 0 || srcInfo.height <= 0 ||
dstInfo.width <= 0 || dstInfo.height <= 0 ||
(SWS_CS_COEFFICIENT.find(colorSpaceDetails.srcYuvConversion) == SWS_CS_COEFFICIENT.end()) ||
(SWS_CS_COEFFICIENT.find(colorSpaceDetails.dstYuvConversion) == SWS_CS_COEFFICIENT.end())),
false, "src/dst width/height colorTableCoefficients error!");
inputFrame = av_frame_alloc();
outputFrame = av_frame_alloc();
if (inputFrame != nullptr && outputFrame != nullptr) {
struct SwsContext *ctx = sws_getContext(srcInfo.width, srcInfo.height, srcInfo.format,
dstInfo.width, dstInfo.height, dstInfo.format, SWS_POINT, nullptr, nullptr, nullptr);
IMAGE_LOGE("srcInfo.width:%{public}d, srcInfo.height:%{public}d", srcInfo.width, srcInfo.height);
if (ctx != nullptr) {
auto srcColorTable = sws_getCoefficients(SWS_CS_COEFFICIENT.at(colorSpaceDetails.srcYuvConversion));
auto dstColorTable = sws_getCoefficients(SWS_CS_COEFFICIENT.at(colorSpaceDetails.dstYuvConversion));
sws_setColorspaceDetails(ctx,
srcColorTable, colorSpaceDetails.srcRange,
dstColorTable, colorSpaceDetails.dstRange,
0, 1 << BIT_SHIFT_16BITS, 1 << BIT_SHIFT_16BITS);
av_image_fill_arrays(inputFrame->data, inputFrame->linesize,
const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(srcPixels)),
srcInfo.format, srcInfo.width, srcInfo.height, srcInfo.alignSize);
av_image_fill_arrays(outputFrame->data, outputFrame->linesize,
const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(dstPixels)),
dstInfo.format, dstInfo.width, dstInfo.height, dstInfo.alignSize);
sws_scale(ctx, const_cast<const uint8_t **>(reinterpret_cast<uint8_t **>(inputFrame->data)),
inputFrame->linesize, 0, srcInfo.height, outputFrame->data, outputFrame->linesize);
sws_freeContext(ctx);
} else {
IMAGE_LOGE("FFMpeg: sws_getContext failed!");
ret = false;
}
} else {
IMAGE_LOGE("FFMpeg: av_frame_alloc failed!");
ret = false;
}
av_frame_free(&inputFrame);
av_frame_free(&outputFrame);
return ret;
}
static bool FFMpegConvert(const void *srcPixels, const FFMPEG_CONVERT_INFO& srcInfo,
void *dstPixels, const FFMPEG_CONVERT_INFO& dstInfo)
{
YUVConvertColorSpaceDetails colorSpaceDetails = { 0, 0 };
return FFMpegConvert(srcPixels, srcInfo, dstPixels, dstInfo, colorSpaceDetails);
}
static bool NV12P010ToNV21P010(const uint16_t *srcBuffer, const ImageInfo &info, uint16_t *destBuffer)
{
bool cond = (info.size.width <= 0 || info.size.height <= 0);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "Invalid Pixelmap size: width = %{public}d, height = %{public}d",
info.size.width, info.size.height);
uint32_t width = static_cast<uint32_t>(info.size.width);
uint32_t height = static_cast<uint32_t>(info.size.height);
cond = (width > UINT32_MAX / height);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "Image size too large: width = %{public}u, height = %{public}u",
width, height);
uint32_t ysize = width * height;
uint32_t sizeUV = ysize / NUM_2;
const uint16_t *srcUV = srcBuffer + ysize;
uint16_t *dstVU = destBuffer + ysize;
for (uint32_t i = 0; i < ysize; i++) {
destBuffer[i] = srcBuffer[i];
}
for (uint32_t i = 0; i < sizeUV / UV_PLANES_COUNT; i++) {
dstVU[UV_PLANES_COUNT * i] = srcUV[UV_PLANES_COUNT * i + 1];
dstVU[UV_PLANES_COUNT * i + 1] = srcUV[UV_PLANES_COUNT * i];
}
return true;
}
bool IsYUVP010Format(PixelFormat format)
{
return (format == PixelFormat::YCBCR_P010) || (format == PixelFormat::YCRCB_P010);
}
static bool ConvertForFFMPEG(const void *srcPixels, PixelFormat srcpixelmap, ImageInfo srcInfo,
void *dstPixels, PixelFormat dstpixelmap)
{
FFMPEG_CONVERT_INFO srcFFmpegInfo = {PixelFormatToAVPixelFormat(srcpixelmap),
srcInfo.size.width, srcInfo.size.height, 1};
FFMPEG_CONVERT_INFO dstFFmpegInfo = {PixelFormatToAVPixelFormat(dstpixelmap),
srcInfo.size.width, srcInfo.size.height, 1};
CHECK_ERROR_RETURN_RET_LOG((!FFMpegConvert(srcPixels, srcFFmpegInfo, dstPixels, dstFFmpegInfo)),
false, "[PixelMap]Convert: ffmpeg convert failed!");
return true;
}
static int64_t GetValidBufferSize(const ImageInfo &dstInfo)
{
int64_t rowDataSize = ImageUtils::GetRowDataSizeByPixelFormat(dstInfo.size.width, dstInfo.pixelFormat);
CHECK_ERROR_RETURN_RET_LOG(rowDataSize <= 0, CONVERT_ERROR,
"[PixelMap] AllocPixelMapMemory: get row data size failed");
int64_t bufferSize;
bool cond = __builtin_mul_overflow(rowDataSize, dstInfo.size.height, &bufferSize);
CHECK_ERROR_RETURN_RET_LOG(cond, -1, "[PixelMap]Create: bufferSize overflowed");
CHECK_ERROR_RETURN_RET_LOG(bufferSize > UINT32_MAX, CONVERT_ERROR,
"[PixelMap]Create: Pixelmap size too large: width = %{public}d, height = %{public}d",
dstInfo.size.width, dstInfo.size.height);
return bufferSize;
}
static bool IsRGBFormat(PixelFormat format)
{
return (format == PixelFormat::RGB_888) || (format == PixelFormat::RGB_565);
}
static bool ConvertAndCollapseByFFMpeg(const void *srcPixels, const ImageInfo &srcInfo, void *dstPixels,
const ImageInfo &dstInfo, bool useDMA)
{
FFMPEG_CONVERT_INFO srcFFMpegInfo = {PixelFormatToAVPixelFormat(srcInfo.pixelFormat),
srcInfo.size.width, srcInfo.size.height, useDMA ? DMA_LINE_SIZE : 1};
FFMPEG_CONVERT_INFO dstFFMpegInfo = {PixelFormatToAVPixelFormat(dstInfo.pixelFormat),
dstInfo.size.width, dstInfo.size.height, 1};
std::unique_ptr<uint8_t[]> tmpBuffer = nullptr;
bool needTmpBuffer = false;
int64_t bufferSize = 0;
if (IsRGBFormat(srcInfo.pixelFormat) && dstInfo.pixelFormat == PixelFormat::ARGB_8888) {
bufferSize = GetValidBufferSize(dstInfo);
CHECK_ERROR_RETURN_RET(bufferSize <= 0, false);
tmpBuffer = std::make_unique<uint8_t[]>(bufferSize + 1);
CHECK_ERROR_RETURN_RET_LOG(tmpBuffer == nullptr, false,
"[PixelMap] ConvertAndCollapseByFFMpeg: alloc memory failed!");
needTmpBuffer = true;
}
void* conversionTarget = needTmpBuffer ? static_cast<void*>(tmpBuffer.get()) : dstPixels;
bool cond = FFMpegConvert(srcPixels, srcFFMpegInfo, conversionTarget, dstFFMpegInfo);
CHECK_ERROR_RETURN_RET_LOG(!cond, false, "[PixelMap] ConvertAndCollapseByFFMpeg: FFMpeg convert failed!");
if (needTmpBuffer) {
CHECK_ERROR_RETURN_RET_LOG(memcpy_s(dstPixels, bufferSize, conversionTarget, bufferSize) != 0, false,
"[PixelMap] ConvertAndCollapseByFFMpeg: memcpy_s failed!");
}
return true;
}
static bool P010ConvertRGBA1010102(const void *srcPixels, ImageInfo srcInfo,
void *dstPixels, ImageInfo dstInfo)
{
FFMPEG_CONVERT_INFO srcFFmpegInfo = {PixelFormatToAVPixelFormat(srcInfo.pixelFormat),
srcInfo.size.width, srcInfo.size.height, 1};
FFMPEG_CONVERT_INFO tmpFFmpegInfo = {PixelFormatToAVPixelFormat(PixelFormat::RGBA_F16),
srcInfo.size.width, srcInfo.size.height, 1};
int tmpPixelsLen = av_image_get_buffer_size(tmpFFmpegInfo.format, tmpFFmpegInfo.width, tmpFFmpegInfo.height,
tmpFFmpegInfo.alignSize);
CHECK_ERROR_RETURN_RET_LOG((tmpPixelsLen <= 0), false, "[PixelMap]Convert: Get tmp pixels length failed!");
uint8_t* tmpPixels = new(std::nothrow) uint8_t[tmpPixelsLen];
CHECK_ERROR_RETURN_RET_LOG(tmpPixels == nullptr, false, "[PixelMap]Convert: alloc memory failed!");
memset_s(tmpPixels, tmpPixelsLen, 0, tmpPixelsLen);
if (!FFMpegConvert(srcPixels, srcFFmpegInfo, tmpPixels, tmpFFmpegInfo)) {
IMAGE_LOGE("[PixelMap]Convert: ffmpeg convert failed!");
delete[] tmpPixels;
tmpPixels = nullptr;
return false;
}
ImageInfo tmpInfo = srcInfo;
tmpInfo.pixelFormat = PixelFormat::RGBA_U16;
tmpInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
Position pos;
if (!PixelConvertAdapter::WritePixelsConvert(tmpPixels, PixelMap::GetRGBxRowDataSize(tmpInfo), tmpInfo,
dstPixels, pos, PixelMap::GetRGBxRowDataSize(dstInfo), dstInfo)) {
IMAGE_LOGE("[PixelMap]Convert: ConvertFromYUV: pixel convert in adapter failed.");
delete[] tmpPixels;
tmpPixels = nullptr;
return false;
}
delete[] tmpPixels;
tmpPixels = nullptr;
return true;
}
static bool P010ConvertRGB565(const uint8_t* srcP010, const ImageInfo& srcInfo,
void* dstPixels, const ImageInfo& dstInfo)
{
int64_t bufferSize = GetValidBufferSize(dstInfo);
CHECK_ERROR_RETURN_RET(bufferSize <= 0, false);
std::unique_ptr<uint8_t[]> tmpBuffer =
std::make_unique<uint8_t[]>(bufferSize + RGB565_EXTRA_BYTES);
CHECK_ERROR_RETURN_RET_LOG(tmpBuffer == nullptr, false, "P010ConvertRGB565: alloc temp buffer failed");
CHECK_ERROR_RETURN_RET_LOG(!ConvertForFFMPEG(srcP010, srcInfo.pixelFormat, srcInfo, tmpBuffer.get(),
dstInfo.pixelFormat), false, "P010ConvertRGB565: FFMpeg convert failed");
CHECK_ERROR_RETURN_RET_LOG(memcpy_s(dstPixels, bufferSize, tmpBuffer.get(), bufferSize) != 0, false,
"P010ConvertRGB565: memcpy_s dstPixels failed!");
return true;
}
static bool ConvertRGBA1010102ToYUV(const void *srcPixels, ImageInfo srcInfo,
void *dstPixels, ImageInfo dstInfo)
{
ImageInfo copySrcInfo = srcInfo;
copySrcInfo.pixelFormat = PixelFormat::RGBA_U16;
bool cond = ImageUtils::GetAlignedNumber(copySrcInfo.size.width, EVEN_ALIGNMENT) &&
ImageUtils::GetAlignedNumber(copySrcInfo.size.height, EVEN_ALIGNMENT);
CHECK_ERROR_RETURN_RET(!cond, false);
int copySrcLen = PixelMap::GetRGBxByteCount(copySrcInfo);
CHECK_ERROR_RETURN_RET_LOG(copySrcLen <= 0, false, "[PixelMap]Convert: Get copySrc pixels length failed!");
std::unique_ptr<uint8_t[]> copySrcBuffer = std::make_unique<uint8_t[]>(copySrcLen);
CHECK_ERROR_RETURN_RET_LOG(copySrcBuffer == nullptr, false, "[PixelMap]Convert: alloc memory failed!");
uint8_t* copySrcPixels = copySrcBuffer.get();
memset_s(copySrcPixels, copySrcLen, 0, copySrcLen);
Position pos;
cond = PixelConvertAdapter::WritePixelsConvert(srcPixels, PixelMap::GetRGBxRowDataSize(srcInfo), srcInfo,
copySrcPixels, pos, PixelMap::GetRGBxRowDataSize(copySrcInfo), copySrcInfo);
CHECK_ERROR_RETURN_RET_LOG(!cond, false, "[PixelMap]Convert: ConvertToYUV: pixel convert in adapter failed.");
FFMPEG_CONVERT_INFO srcFFmpegInfo = {PixelFormatToAVPixelFormat(PixelFormat::RGBA_F16),
copySrcInfo.size.width, copySrcInfo.size.height, 1};
FFMPEG_CONVERT_INFO dstFFmpegInfo = {PixelFormatToAVPixelFormat(dstInfo.pixelFormat),
dstInfo.size.width, dstInfo.size.height, 1};
cond = FFMpegConvert(copySrcPixels, srcFFmpegInfo, dstPixels, dstFFmpegInfo);
CHECK_ERROR_RETURN_RET_LOG(!cond, false, "[PixelMap]Convert: ffmpeg convert failed!");
return true;
}
static int32_t YUVConvertRGB(const void *srcPixels, const ImageInfo &srcInfo,
void *dstPixels, const ImageInfo &dstInfo, YUVConvertColorSpaceDetails &colorSpaceDetails)
{
FFMPEG_CONVERT_INFO srcFFmpegInfo = {PixelFormatToAVPixelFormat(srcInfo.pixelFormat),
srcInfo.size.width, srcInfo.size.height, 1};
FFMPEG_CONVERT_INFO tmpFFmpegInfo = {PixelFormatToAVPixelFormat(PixelFormat::RGB_888),
srcInfo.size.width, srcInfo.size.height, 1};
int tmpPixelsLen = av_image_get_buffer_size(tmpFFmpegInfo.format, tmpFFmpegInfo.width, tmpFFmpegInfo.height,
tmpFFmpegInfo.alignSize);
CHECK_ERROR_RETURN_RET_LOG((tmpPixelsLen <= 0), -1, "[PixelMap]Convert: Get tmp pixels length failed!");
uint8_t* tmpPixels = new(std::nothrow) uint8_t[tmpPixelsLen];
CHECK_ERROR_RETURN_RET_LOG(tmpPixels == nullptr, -1, "[PixelMap]Convert: alloc memory failed!");
memset_s(tmpPixels, tmpPixelsLen, 0, tmpPixelsLen);
if (!FFMpegConvert(srcPixels, srcFFmpegInfo, static_cast<void *>(tmpPixels), tmpFFmpegInfo, colorSpaceDetails)) {
IMAGE_LOGE("[PixelMap]Convert: ffmpeg convert failed!");
delete[] tmpPixels;
tmpPixels = nullptr;
return -1;
}
ImageInfo tmpInfo = srcInfo;
tmpInfo.pixelFormat = PixelFormat::RGB_888;
Position pos;
if (!PixelConvertAdapter::WritePixelsConvert(tmpPixels, PixelMap::GetRGBxRowDataSize(tmpInfo), tmpInfo,
dstPixels, pos, PixelMap::GetRGBxRowDataSize(dstInfo), dstInfo)) {
IMAGE_LOGE("[PixelMap]Convert: ConvertFromYUV: pixel convert in adapter failed.");
delete[] tmpPixels;
tmpPixels = nullptr;
return -1;
}
delete[] tmpPixels;
tmpPixels = nullptr;
return PixelMap::GetRGBxByteCount(dstInfo);
}
static int32_t ConvertFromYUV(const BufferInfo &srcBufferInfo, const int32_t srcLength, BufferInfo &dstBufferInfo)
{
bool cond = srcBufferInfo.pixels == nullptr || dstBufferInfo.pixels == nullptr || srcLength <= 0;
CHECK_ERROR_RETURN_RET_LOG(cond, CONVERT_ERROR,
"[PixelMap]Convert: src pixels or dst pixels or src pixels length invalid.");
const ImageInfo &srcInfo = srcBufferInfo.imageInfo;
const ImageInfo &dstInfo = dstBufferInfo.imageInfo;
YUVConvertColorSpaceDetails colorSpaceDetails = {
srcBufferInfo.range,
dstBufferInfo.range,
srcBufferInfo.yuvConversion,
dstBufferInfo.yuvConversion
};
cond = (srcInfo.pixelFormat != PixelFormat::NV21 && srcInfo.pixelFormat != PixelFormat::NV12) ||
(dstInfo.pixelFormat == PixelFormat::NV21 || dstInfo.pixelFormat == PixelFormat::NV12);
CHECK_ERROR_RETURN_RET_LOG(cond, CONVERT_ERROR, "[PixelMap]Convert: src or dst pixel format invalid.");
ImageInfo copySrcInfo = srcInfo;
cond = ImageUtils::GetAlignedNumber(copySrcInfo.size.width, EVEN_ALIGNMENT) &&
ImageUtils::GetAlignedNumber(copySrcInfo.size.height, EVEN_ALIGNMENT);
CHECK_ERROR_RETURN_RET(!cond, CONVERT_ERROR);
int32_t copySrcLen = PixelMap::GetAllocatedByteCount(copySrcInfo);
CHECK_ERROR_RETURN_RET_LOG((copySrcLen <= 0), -1, "[PixelMap]Convert: Get copySrcLen pixels length failed!");
std::unique_ptr<uint8_t[]> copySrcBuffer = std::make_unique<uint8_t[]>(copySrcLen);
CHECK_ERROR_RETURN_RET_LOG((copySrcBuffer == nullptr), -1, "[PixelMap]Convert: alloc memory failed!");
uint8_t* copySrcPixels = copySrcBuffer.get();
memset_s(copySrcPixels, copySrcLen, 0, copySrcLen);
cond = memcpy_s(copySrcPixels, copySrcLen, srcBufferInfo.pixels, std::min(srcLength, copySrcLen)) != EOK;
CHECK_ERROR_RETURN_RET(cond, -1);
if ((srcInfo.pixelFormat == PixelFormat::NV12 && dstInfo.pixelFormat == PixelFormat::YCBCR_P010) ||
(srcInfo.pixelFormat == PixelFormat::NV21 && dstInfo.pixelFormat == PixelFormat::YCRCB_P010)) {
return ConvertForFFMPEG(copySrcPixels, PixelFormat::NV12, srcInfo, dstBufferInfo.pixels,
PixelFormat::YCBCR_P010) == true ? PixelMap::GetYUVByteCount(dstInfo) : -1;
}
if ((srcInfo.pixelFormat == PixelFormat::NV12 && dstInfo.pixelFormat == PixelFormat::YCRCB_P010) ||
(srcInfo.pixelFormat == PixelFormat::NV21 && dstInfo.pixelFormat == PixelFormat::YCBCR_P010)) {
return ConvertForFFMPEG(copySrcPixels, PixelFormat::NV21, srcInfo, dstBufferInfo.pixels,
PixelFormat::YCBCR_P010) == true ? PixelMap::GetYUVByteCount(dstInfo) : -1;
}
return YUVConvertRGB(copySrcPixels, srcInfo, dstBufferInfo.pixels, dstInfo, colorSpaceDetails);
}
static int32_t ConvertFromP010(const void *srcPixels, const int32_t srcLength, const ImageInfo &srcInfo,
void *dstPixels, const ImageInfo &dstInfo)
{
bool cond = srcPixels == nullptr || dstPixels == nullptr || srcLength <= 0;
CHECK_ERROR_RETURN_RET_LOG(cond, CONVERT_ERROR,
"[PixelMap]Convert: src pixels or dst pixels or src pixels length invalid.");
cond = (srcInfo.pixelFormat != PixelFormat::YCRCB_P010 && srcInfo.pixelFormat != PixelFormat::YCBCR_P010) ||
IsYUVP010Format(dstInfo.pixelFormat);
CHECK_ERROR_RETURN_RET_LOG(cond, CONVERT_ERROR, "[PixelMap]Convert: src or dst pixel format invalid.");
ImageInfo copySrcInfo = srcInfo;
cond = ImageUtils::GetAlignedNumber(copySrcInfo.size.width, EVEN_ALIGNMENT) &&
ImageUtils::GetAlignedNumber(copySrcInfo.size.height, EVEN_ALIGNMENT);
CHECK_ERROR_RETURN_RET(!cond, CONVERT_ERROR);
int32_t srcP010Length = PixelMap::GetAllocatedByteCount(copySrcInfo);
std::unique_ptr<uint8_t[]> srcP010Buffer = std::make_unique<uint8_t[]>(srcP010Length);
CHECK_ERROR_RETURN_RET_LOG(srcP010Buffer == nullptr, CONVERT_ERROR, "[PixelMap]Convert: alloc memory failed!");
uint8_t* srcP010 = srcP010Buffer.get();
memset_s(srcP010, srcP010Length, 0, srcP010Length);
if (srcInfo.pixelFormat == PixelFormat::YCRCB_P010) {
NV12P010ToNV21P010(const_cast<uint16_t *>(reinterpret_cast<const uint16_t *>(srcPixels)), srcInfo,
reinterpret_cast<uint16_t *>(srcP010));
} else {
CHECK_ERROR_RETURN_RET(memcpy_s(srcP010, srcP010Length, srcPixels, srcLength) != 0, CONVERT_ERROR);
}
if (dstInfo.pixelFormat == PixelFormat::RGBA_1010102) {
if (P010ConvertRGBA1010102(srcP010, srcInfo, dstPixels, dstInfo)) {
return PixelMap::GetRGBxByteCount(dstInfo);
}
return -1;
} else if (dstInfo.pixelFormat == PixelFormat::RGB_565) {
if (P010ConvertRGB565(srcP010, srcInfo, dstPixels, dstInfo)) {
return PixelMap::GetRGBxByteCount(dstInfo);
}
return -1;
} else {
if (ConvertForFFMPEG(srcP010, srcInfo.pixelFormat, srcInfo, dstPixels, dstInfo.pixelFormat)) {
return PixelMap::GetRGBxByteCount(dstInfo);
}
return -1;
}
}
static int32_t RGBConvertYUV(const void *srcPixels, const ImageInfo &srcInfo,
void *dstPixels, const ImageInfo &dstInfo)
{
ImageInfo tmpInfo = srcInfo;
tmpInfo.pixelFormat = PixelFormat::RGB_888;
uint32_t tmpWidth = (static_cast<uint32_t>(tmpInfo.size.width) & 1) == 1 ?
static_cast<uint32_t>(tmpInfo.size.width) + 1 : static_cast<uint32_t>(tmpInfo.size.width);
size_t tmpPixelsLen = static_cast<size_t>(tmpWidth) * static_cast<size_t>(tmpInfo.size.height) *
static_cast<size_t>(ImageUtils::GetPixelBytes(tmpInfo.pixelFormat));
CHECK_ERROR_RETURN_RET_LOG(tmpPixelsLen == 0 || tmpPixelsLen > INT32_MAX, CONVERT_ERROR,
"[PixelMap]Convert: Get tmp pixels length failed!");
uint8_t* tmpPixels = new(std::nothrow) uint8_t[tmpPixelsLen];
CHECK_ERROR_RETURN_RET_LOG((tmpPixels == nullptr), -1, "[PixelMap]Convert: alloc memory failed!");
memset_s(tmpPixels, tmpPixelsLen, 0, tmpPixelsLen);
Position pos;
if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, PixelMap::GetRGBxRowDataSize(srcInfo), srcInfo,
tmpPixels, pos, PixelMap::GetRGBxRowDataSize(tmpInfo), tmpInfo)) {
IMAGE_LOGE("[PixelMap]Convert: ConvertToYUV: pixel convert in adapter failed.");
delete[] tmpPixels;
tmpPixels = nullptr;
return -1;
}
FFMPEG_CONVERT_INFO srcFFmpegInfo = {PixelFormatToAVPixelFormat(PixelFormat::RGB_888),
tmpInfo.size.width, tmpInfo.size.height, 1};
FFMPEG_CONVERT_INFO dstFFmpegInfo = {PixelFormatToAVPixelFormat(dstInfo.pixelFormat),
dstInfo.size.width, dstInfo.size.height, 1};
if (!FFMpegConvert(tmpPixels, srcFFmpegInfo, (void *)dstPixels, dstFFmpegInfo)) {
IMAGE_LOGE("[PixelMap]Convert: ffmpeg convert failed!");
delete[] tmpPixels;
tmpPixels = nullptr;
return -1;
}
delete[] tmpPixels;
tmpPixels = nullptr;
return av_image_get_buffer_size(dstFFmpegInfo.format, dstFFmpegInfo.width, dstFFmpegInfo.height,
dstFFmpegInfo.alignSize);
}
static int32_t ConvertToYUV(const void *srcPixels, const int32_t srcLength, const ImageInfo &srcInfo,
void *dstPixels, const ImageInfo &dstInfo)
{
bool cond = srcPixels == nullptr || dstPixels == nullptr || srcLength <= 0;
CHECK_ERROR_RETURN_RET_LOG(cond, CONVERT_ERROR,
"[PixelMap]Convert: src pixels or dst pixels or src pixel length invalid");
cond = (srcInfo.pixelFormat == PixelFormat::NV21 || srcInfo.pixelFormat == PixelFormat::NV12) ||
(dstInfo.pixelFormat != PixelFormat::NV21 && dstInfo.pixelFormat != PixelFormat::NV12);
CHECK_ERROR_RETURN_RET_LOG(cond, CONVERT_ERROR, "[PixelMap]Convert: src or dst pixel format invalid.");
ImageInfo copySrcInfo = srcInfo;
cond = ImageUtils::GetAlignedNumber(copySrcInfo.size.width, EVEN_ALIGNMENT) &&
ImageUtils::GetAlignedNumber(copySrcInfo.size.height, EVEN_ALIGNMENT);
CHECK_ERROR_RETURN_RET(!cond, CONVERT_ERROR);
int32_t copySrcLen = PixelMap::GetAllocatedByteCount(copySrcInfo);
CHECK_ERROR_RETURN_RET_LOG((copySrcLen <= 0), -1, "[PixelMap]Convert: Get copySrcLen pixels length failed!");
std::unique_ptr<uint8_t[]> copySrcBuffer = std::make_unique<uint8_t[]>(copySrcLen);
CHECK_ERROR_RETURN_RET_LOG((copySrcBuffer == nullptr), -1, "[PixelMap]Convert: alloc memory failed!");
uint8_t* copySrcPixels = copySrcBuffer.get();
memset_s(copySrcPixels, copySrcLen, 0, copySrcLen);
cond = memcpy_s(copySrcPixels, copySrcLen, srcPixels, std::min(srcLength, copySrcLen)) != EOK;
CHECK_ERROR_RETURN_RET(cond, -1);
if ((srcInfo.pixelFormat == PixelFormat::YCBCR_P010 && dstInfo.pixelFormat == PixelFormat::NV12) ||
(srcInfo.pixelFormat == PixelFormat::YCRCB_P010 && dstInfo.pixelFormat == PixelFormat::NV21)) {
return ConvertForFFMPEG(copySrcPixels, PixelFormat::YCBCR_P010, srcInfo, dstPixels,
PixelFormat::NV12) == true ? PixelMap::GetYUVByteCount(dstInfo) : -1;
}
if ((srcInfo.pixelFormat == PixelFormat::YCBCR_P010 && dstInfo.pixelFormat == PixelFormat::NV21) ||
(srcInfo.pixelFormat == PixelFormat::YCRCB_P010 && dstInfo.pixelFormat == PixelFormat::NV12)) {
return ConvertForFFMPEG(copySrcPixels, PixelFormat::YCBCR_P010, srcInfo, dstPixels,
PixelFormat::NV21) == true ? PixelMap::GetYUVByteCount(dstInfo) : -1;
}
return RGBConvertYUV(copySrcPixels, srcInfo, dstPixels, dstInfo);
}
static int32_t ConvertToP010(const BufferInfo &src, BufferInfo &dst)
{
const void *srcPixels = src.pixels;
const int32_t srcLength = src.length;
const ImageInfo &srcInfo = src.imageInfo;
void *dstPixels = dst.pixels;
const ImageInfo &dstInfo = dst.imageInfo;
CHECK_ERROR_RETURN_RET_LOG((srcPixels == nullptr || dstPixels == nullptr || srcLength <= 0), -1,
"[PixelMap]Convert: src pixels or dst pixels or src pixel length invalid");
CHECK_ERROR_RETURN_RET_LOG((IsYUVP010Format(srcInfo.pixelFormat) ||
(dstInfo.pixelFormat != PixelFormat::YCRCB_P010 && dstInfo.pixelFormat != PixelFormat::YCBCR_P010)),
-1, "[PixelMap]Convert: src or dst pixel format invalid.");
int32_t dstLength = PixelMap::GetYUVByteCount(dstInfo);
CHECK_ERROR_RETURN_RET_LOG(dstLength <= 0, -1, "[PixelMap]Convert: Get dstP010 length failed!");
std::unique_ptr<uint8_t[]> dstP010Buffer = std::make_unique<uint8_t[]>(dstLength);
CHECK_ERROR_RETURN_RET_LOG(dstP010Buffer == nullptr, CONVERT_ERROR, "[PixelMap]Convert: alloc memory failed!");
uint8_t* dstP010 = dstP010Buffer.get();
memset_s(dstP010, dstLength, 0, dstLength);
bool cond = false;
if (srcInfo.pixelFormat == PixelFormat::RGBA_1010102) {
cond = ConvertRGBA1010102ToYUV(srcPixels, srcInfo, dstP010, dstInfo);
CHECK_ERROR_RETURN_RET(!cond, CONVERT_ERROR);
} else {
ImageInfo copySrcInfo = srcInfo;
cond = ImageUtils::GetAlignedNumber(copySrcInfo.size.width, EVEN_ALIGNMENT) &&
ImageUtils::GetAlignedNumber(copySrcInfo.size.height, EVEN_ALIGNMENT);
CHECK_ERROR_RETURN_RET(!cond, CONVERT_ERROR);
int32_t copySrcLength = PixelMap::GetAllocatedByteCount(copySrcInfo);
std::unique_ptr<uint8_t[]> copySrcBuffer = std::make_unique<uint8_t[]>(copySrcLength);
cond = copySrcBuffer == nullptr || EOK != memcpy_s(copySrcBuffer.get(), copySrcLength, srcPixels, srcLength);
CHECK_ERROR_RETURN_RET_LOG(cond, CONVERT_ERROR, "alloc memory or memcpy_s failed!");
cond = ConvertForFFMPEG(copySrcBuffer.get(), srcInfo.pixelFormat, srcInfo, dstP010, dstInfo.pixelFormat);
CHECK_ERROR_RETURN_RET(!cond, CONVERT_ERROR);
}
if (dstInfo.pixelFormat == PixelFormat::YCRCB_P010) {
NV12P010ToNV21P010(reinterpret_cast<uint16_t *>(dstP010), dstInfo, static_cast<uint16_t *>(dstPixels));
} else {
CHECK_ERROR_RETURN_RET(memcpy_s(dstPixels, dst.length, dstP010, dstLength) != 0, CONVERT_ERROR);
}
return dstLength;
}
static int32_t YUVConvert(const BufferInfo &src, const int32_t srcLength, BufferInfo &dst)
{
ImageInfo srcInfo = src.imageInfo;
ImageInfo dstInfo = dst.imageInfo;
const void *srcPixels = src.pixels;
void* dstPixels = dst.pixels;
if (srcInfo.pixelFormat == dstInfo.pixelFormat &&
srcInfo.size.width == dstInfo.size.width && srcInfo.size.height == dstInfo.size.height) {
IMAGE_LOGD("src pixel format is equal dst pixel format. no need to convert.");
int32_t minLength = static_cast<int32_t>(dst.length) < srcLength ?
static_cast<int32_t>(dst.length) : srcLength;
auto result = memcpy_s(dstPixels, dst.length, srcPixels, minLength);
return result == 0 ? minLength : -1;
}
if (IsYUVP010Format(srcInfo.pixelFormat) && IsYUVP010Format(dstInfo.pixelFormat)) {
if (srcInfo.size.width == dstInfo.size.width && srcInfo.size.height == dstInfo.size.height) {
return NV12P010ToNV21P010(const_cast<uint16_t *>(reinterpret_cast<const uint16_t *>(srcPixels)), dstInfo,
reinterpret_cast<uint16_t *>(dstPixels)) == true ? srcLength : -1;
}
}
ImageInfo copySrcInfo = srcInfo;
bool cond = ImageUtils::GetAlignedNumber(copySrcInfo.size.width, EVEN_ALIGNMENT) &&
ImageUtils::GetAlignedNumber(copySrcInfo.size.height, EVEN_ALIGNMENT);
CHECK_ERROR_RETURN_RET(!cond, CONVERT_ERROR);
int32_t copySrcLen = PixelMap::GetAllocatedByteCount(copySrcInfo);
CHECK_ERROR_RETURN_RET_LOG((copySrcLen <= 0), -1, "[PixelMap]Convert: Get copySrcLen pixels length failed!");
std::unique_ptr<uint8_t[]> copySrcBuffer = std::make_unique<uint8_t[]>(copySrcLen);
CHECK_ERROR_RETURN_RET_LOG((copySrcBuffer == nullptr), -1, "[PixelMap]Convert: alloc memory failed!");
uint8_t* copySrcPixels = copySrcBuffer.get();
memset_s(copySrcPixels, copySrcLen, 0, copySrcLen);
cond = memcpy_s(copySrcPixels, copySrcLen, srcPixels, std::min(srcLength, copySrcLen)) != EOK;
CHECK_ERROR_RETURN_RET(cond, -1);
FFMPEG_CONVERT_INFO srcFFmpegInfo = {PixelFormatToAVPixelFormat(srcInfo.pixelFormat), srcInfo.size.width,
srcInfo.size.height, 1};
FFMPEG_CONVERT_INFO dstFFmpegInfo = {PixelFormatToAVPixelFormat(dstInfo.pixelFormat), dstInfo.size.width,
dstInfo.size.height, 1};
CHECK_ERROR_RETURN_RET_LOG(!FFMpegConvert(copySrcPixels, srcFFmpegInfo, dstPixels, dstFFmpegInfo),
-1, "[PixelMap]Convert: ffmpeg convert failed!");
return av_image_get_buffer_size(dstFFmpegInfo.format, dstFFmpegInfo.width, dstFFmpegInfo.height,
dstFFmpegInfo.alignSize);
}
static bool IsInterYUVConvert(PixelFormat srcPixelFormat, PixelFormat dstPixelFormat)
{
return (srcPixelFormat == PixelFormat::NV12 || srcPixelFormat == PixelFormat::NV21) &&
(dstPixelFormat == PixelFormat::NV12 || dstPixelFormat == PixelFormat::NV21);
}
static int32_t ConvertAlphaF16ToYUV(const BufferInfo &src, BufferInfo &dst)
{
ImageInfo tmpInfo = src.imageInfo;
tmpInfo.pixelFormat = PixelFormat::BGRA_8888;
tmpInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
int32_t tmpLength = PixelMap::GetRGBxByteCount(tmpInfo);
CHECK_ERROR_RETURN_RET_LOG(tmpLength <= 0, CONVERT_ERROR,
"[PixelMap]Convert: Get ALPHA_F16 temp BGRA buffer length failed.");
std::unique_ptr<uint8_t[]> tmpBuffer = std::make_unique<uint8_t[]>(tmpLength);
CHECK_ERROR_RETURN_RET_LOG(tmpBuffer == nullptr, CONVERT_ERROR,
"[PixelMap]Convert: alloc ALPHA_F16 temp BGRA buffer failed.");
memset_s(tmpBuffer.get(), tmpLength, 0, tmpLength);
Position pos;
bool converted = PixelConvertAdapter::WritePixelsConvert(src.pixels,
src.rowStride == 0 ? PixelMap::GetRGBxRowDataSize(src.imageInfo) : src.rowStride, src.imageInfo,
tmpBuffer.get(), pos, PixelMap::GetRGBxRowDataSize(tmpInfo), tmpInfo);
CHECK_ERROR_RETURN_RET_LOG(!converted, CONVERT_ERROR,
"[PixelMap]Convert: ALPHA_F16 temp BGRA convert failed.");
if (dst.imageInfo.pixelFormat == PixelFormat::NV12 || dst.imageInfo.pixelFormat == PixelFormat::NV21) {
return ConvertToYUV(tmpBuffer.get(), tmpLength, tmpInfo, dst.pixels, dst.imageInfo);
}
BufferInfo tmpSrc = src;
tmpSrc.pixels = tmpBuffer.get();
tmpSrc.rowStride = PixelMap::GetRGBxRowDataSize(tmpInfo);
tmpSrc.imageInfo = tmpInfo;
tmpSrc.length = static_cast<uint32_t>(tmpLength);
return ConvertToP010(tmpSrc, dst);
}
int32_t PixelConvert::PixelsConvert(const BufferInfo &src, BufferInfo &dst, bool useDMA)
{
CHECK_ERROR_RETURN_RET_LOG(!(IsValidBufferInfo(src) && IsValidBufferInfo(dst)), CONVERT_ERROR,
"[PixelMap]Convert: pixels or image info or row stride or src pixels length invalid.");
return ConvertAndCollapseByFFMpeg(src.pixels, src.imageInfo, dst.pixels, dst.imageInfo, useDMA) ?
PixelMap::GetRGBxByteCount(dst.imageInfo) : -1;
}
int32_t PixelConvert::CopySrcBufferAndConvert(const BufferInfo &src, BufferInfo &dst, int32_t srcLength, bool useDMA)
{
bool cond = src.pixels == nullptr || dst.pixels == nullptr || srcLength <= 0;
CHECK_ERROR_RETURN_RET_LOG(cond, CONVERT_ERROR,
"[PixelMap]Convert: src pixels or dst pixels or src pixels length invalid.");
ImageInfo copySrcInfo = src.imageInfo;
cond = ImageUtils::GetAlignedNumber(copySrcInfo.size.width, EVEN_ALIGNMENT) &&
ImageUtils::GetAlignedNumber(copySrcInfo.size.height, EVEN_ALIGNMENT);
CHECK_ERROR_RETURN_RET(!cond, CONVERT_ERROR);
int32_t copySrcLen = PixelMap::GetAllocatedByteCount(copySrcInfo);
std::unique_ptr<uint8_t[]> copySrcBuffer = std::make_unique<uint8_t[]>(copySrcLen);
CHECK_ERROR_RETURN_RET_LOG(copySrcBuffer == nullptr, CONVERT_ERROR, "[PixelMap]Convert: alloc memory failed!");
uint8_t* copySrcPixels = copySrcBuffer.get();
memset_s(copySrcPixels, copySrcLen, 0, copySrcLen);
CHECK_ERROR_RETURN_RET(memcpy_s(copySrcPixels, copySrcLen, src.pixels, srcLength) != 0, CONVERT_ERROR);
return ConvertAndCollapseByFFMpeg(copySrcPixels, src.imageInfo, dst.pixels, dst.imageInfo, useDMA) ?
PixelMap::GetRGBxByteCount(dst.imageInfo) : CONVERT_ERROR;
}
static bool TryYUVPixelsConvert(const BufferInfo &src, BufferInfo &dst, int32_t srcLength, int32_t &dstLength)
{
PixelFormat srcPixelFormat = src.imageInfo.pixelFormat;
PixelFormat dstPixelFormat = dst.imageInfo.pixelFormat;
if (IsInterYUVConvert(srcPixelFormat, dstPixelFormat) ||
(IsYUVP010Format(srcPixelFormat) && IsYUVP010Format(dstPixelFormat)) ||
(srcPixelFormat == PixelFormat::Y8 && dstPixelFormat == PixelFormat::Y8)) {
dstLength = YUVConvert(src, srcLength, dst);
return true;
}
if (srcPixelFormat == PixelFormat::NV12 || srcPixelFormat == PixelFormat::NV21) {
dstLength = ConvertFromYUV(src, srcLength, dst);
return true;
}
if (dstPixelFormat == PixelFormat::NV12 || dstPixelFormat == PixelFormat::NV21) {
dstLength = ConvertToYUV(src.pixels, srcLength, src.imageInfo, dst.pixels, dst.imageInfo);
return true;
}
if (IsYUVP010Format(srcPixelFormat)) {
dstLength = ConvertFromP010(src.pixels, srcLength, src.imageInfo, dst.pixels, dst.imageInfo);
return true;
}
if (IsYUVP010Format(dstPixelFormat)) {
dstLength = ConvertToP010(src, dst);
return true;
}
return false;
}
int32_t PixelConvert::PixelsConvert(const BufferInfo &src, BufferInfo &dst, int32_t srcLength, bool useDMA)
{
bool cond = IsValidBufferInfo(src) && IsValidBufferInfo(dst) && srcLength > 0;
CHECK_ERROR_RETURN_RET_LOG(!cond, CONVERT_ERROR,
"PixelsConvert: pixels or image info or row stride or src pixels length invalid.");
PixelFormat srcPixelFormat = src.imageInfo.pixelFormat;
PixelFormat dstPixelFormat = dst.imageInfo.pixelFormat;
if (srcPixelFormat == PixelFormat::ALPHA_F16 &&
(dstPixelFormat == PixelFormat::NV12 || dstPixelFormat == PixelFormat::NV21 ||
IsYUVP010Format(dstPixelFormat))) {
return ConvertAlphaF16ToYUV(src, dst);
}
if (dstPixelFormat == PixelFormat::ARGB_8888) {
if (useDMA || (src.imageInfo.size.width % EVEN_ALIGNMENT == 0 &&
src.imageInfo.size.height % EVEN_ALIGNMENT == 0)) {
return ConvertAndCollapseByFFMpeg(src.pixels, src.imageInfo, dst.pixels, dst.imageInfo, useDMA) ?
PixelMap::GetRGBxByteCount(dst.imageInfo) : CONVERT_ERROR;
} else {
return CopySrcBufferAndConvert(src, dst, srcLength, useDMA);
}
}
int32_t dstLength = 0;
if (TryYUVPixelsConvert(src, dst, srcLength, dstLength)) {
return dstLength;
}
Position pos;
const int32_t width = src.imageInfo.size.width;
const int32_t height = src.imageInfo.size.height;
const int32_t pixelBytes = ImageUtils::GetPixelBytes(src.imageInfo.pixelFormat);
cond = width <= 0 || height <= 0 || pixelBytes <= 0 ||
ImageUtils::CheckMulOverflow(width, height, pixelBytes);
CHECK_ERROR_RETURN_RET_LOG(cond, CONVERT_ERROR, "source image size or byte count is invalid");
const int32_t srcByteCount = width * height * pixelBytes;
cond = srcLength < srcByteCount;
CHECK_ERROR_PRINT_LOG(cond, "srcLength = %{public}d, size:(%{public}d, %{public}d)", srcLength,
src.imageInfo.size.width, src.imageInfo.size.height);
IMAGE_LOGD("srcLength = %{public}d, size:(%{public}d, %{public}d)", srcLength,
src.imageInfo.size.width, src.imageInfo.size.height);
cond = PixelConvertAdapter::WritePixelsConvert(src.pixels,
src.rowStride == 0 ? PixelMap::GetRGBxRowDataSize(src.imageInfo) : src.rowStride, src.imageInfo,
dst.pixels, pos, useDMA ? dst.rowStride : PixelMap::GetRGBxRowDataSize(dst.imageInfo), dst.imageInfo);
CHECK_ERROR_RETURN_RET_LOG(!cond, CONVERT_ERROR, "PixelsConvert: pixel convert in adapter failed.");
return PixelMap::GetRGBxByteCount(dst.imageInfo);
}
PixelConvert::PixelConvert(ProcFuncType funcPtr, ProcFuncExtension extension, bool isNeedConvert)
: procFunc_(funcPtr), procFuncExtension_(extension), isNeedConvert_(isNeedConvert)
{}
std::unique_ptr<PixelConvert> PixelConvert::Create(const ImageInfo &srcInfo, const ImageInfo &dstInfo)
{
bool cond = (srcInfo.pixelFormat == PixelFormat::UNKNOWN || dstInfo.pixelFormat == PixelFormat::UNKNOWN);
CHECK_ERROR_RETURN_RET_LOG(cond, nullptr, "source or destination pixel format unknown");
uint32_t srcFormat = static_cast<uint32_t>(srcInfo.pixelFormat);
uint32_t dstFormat = static_cast<uint32_t>(dstInfo.pixelFormat);
ProcFuncType funcPtr = GetProcFuncType(srcFormat, dstFormat);
CHECK_ERROR_RETURN_RET_LOG(funcPtr == nullptr, nullptr,
"not found convert function. pixelFormat %{public}u -> %{public}u", srcFormat, dstFormat);
ProcFuncExtension extension;
extension.alphaConvertType = GetAlphaConvertType(srcInfo.alphaType, dstInfo.alphaType);
bool isNeedConvert = true;
if ((srcInfo.pixelFormat == dstInfo.pixelFormat) && (extension.alphaConvertType == AlphaConvertType::NO_CONVERT)) {
isNeedConvert = false;
}
return make_unique<PixelConvert>(funcPtr, extension, isNeedConvert);
}
AlphaConvertType PixelConvert::GetAlphaConvertType(const AlphaType &srcType, const AlphaType &dstType)
{
if (srcType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN || dstType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) {
IMAGE_LOGD("source or destination alpha type unknown");
return AlphaConvertType::NO_CONVERT;
}
if ((srcType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL) && (dstType == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL)) {
return AlphaConvertType::PREMUL_CONVERT_UNPREMUL;
}
if ((srcType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL) && (dstType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE)) {
return AlphaConvertType::PREMUL_CONVERT_OPAQUE;
}
if ((srcType == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL) && (dstType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL)) {
return AlphaConvertType::UNPREMUL_CONVERT_PREMUL;
}
if ((srcType == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL) && (dstType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE)) {
return AlphaConvertType::UNPREMUL_CONVERT_OPAQUE;
}
return AlphaConvertType::NO_CONVERT;
}
bool PixelConvert::IsValidRowStride(int32_t rowStride, const ImageInfo &imageInfo)
{
if (imageInfo.pixelFormat == PixelFormat::YCBCR_P010 ||
imageInfo.pixelFormat == PixelFormat::YCRCB_P010) {
return rowStride == 0 || rowStride >= imageInfo.size.width * YUV420_P010_BYTES;
}
return rowStride == 0 || rowStride >= imageInfo.size.width * ImageUtils::GetPixelBytes(imageInfo.pixelFormat);
}
bool PixelConvert::IsValidBufferInfo(const BufferInfo &bufferInfo)
{
return bufferInfo.pixels != nullptr && IsValidRowStride(bufferInfo.rowStride, bufferInfo.imageInfo);
}
void PixelConvert::Convert(void *destinationPixels, const uint8_t *sourcePixels, uint32_t sourcePixelsNum)
{
bool cond = (destinationPixels == nullptr) || (sourcePixels == nullptr);
CHECK_ERROR_RETURN_LOG(cond, "destinationPixel or sourcePixel is null");
CHECK_ERROR_RETURN_LOG(!isNeedConvert_, "no need convert");
procFunc_(destinationPixels, sourcePixels, sourcePixelsNum, procFuncExtension_);
}
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
static unsigned int UnpackBytes(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
return static_cast<unsigned int>(a) +
(static_cast<unsigned int>(b) << UNPACK_SHIFT_1) +
(static_cast<unsigned int>(c) << UNPACK_SHIFT_2) +
(static_cast<unsigned int>(d) << UNPACK_SHIFT_3);
}
static bool CheckAstcHead(uint8_t *astcBuf, unsigned int &blockX, unsigned int &blockY, uint32_t astcBufSize)
{
CHECK_ERROR_RETURN_RET_LOG(astcBufSize < ASTC_UNIT_BYTES + ASTC_UNIT_BYTES, false,
"DecAstc astcBufSize: %{public}d is invalid", astcBufSize);
unsigned int magicVal = UnpackBytes(astcBuf[BYTE_POS_0], astcBuf[BYTE_POS_1], astcBuf[BYTE_POS_2],
astcBuf[BYTE_POS_3]);
CHECK_ERROR_RETURN_RET_LOG(magicVal != ASTC_MAGIC_ID, false, "DecAstc magicVal: %{public}d is invalid", magicVal);
blockX = static_cast<unsigned int>(astcBuf[BYTE_POS_4]);
blockY = static_cast<unsigned int>(astcBuf[BYTE_POS_5]);
CHECK_ERROR_RETURN_RET_LOG(blockX != ASTC_BLOCK_SIZE_4 || blockY != blockX, false,
"DecAstc blockX: %{public}d blockY: %{public}d not 4x4 or w!=h", blockX, blockY);
CHECK_ERROR_RETURN_RET_LOG(astcBuf[BYTE_POS_6] != 1, false, "DecAstc astc buffer is not 1d");
bool cond = UnpackBytes(astcBuf[BYTE_POS_13], astcBuf[BYTE_POS_14], astcBuf[BYTE_POS_15], 0) != 1;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "DecAstc astc buffer is not 1d");
CHECK_ERROR_RETURN_RET(blockX == 0 || blockY == 0, false);
return true;
}
static bool InitAstcOutImage(astcenc_image &outImage, uint8_t *astcBuf, uint8_t *recRgba, uint32_t stride)
{
outImage.dim_x = UnpackBytes(astcBuf[BYTE_POS_7], astcBuf[BYTE_POS_8], astcBuf[BYTE_POS_9], 0);
outImage.dim_y = UnpackBytes(astcBuf[BYTE_POS_10], astcBuf[BYTE_POS_11], astcBuf[BYTE_POS_12], 0);
outImage.dim_z = 1;
outImage.dim_stride = stride;
outImage.data_type = ASTCENC_TYPE_U8;
outImage.data = new void* [1];
CHECK_ERROR_RETURN_RET_LOG(outImage.data == nullptr, false, "DecAstc outImage.data is null");
outImage.data[0] = recRgba;
return true;
}
static void FreeAstcMem(astcenc_image &outImage, astcenc_context *codec_context)
{
if (outImage.data != nullptr) {
delete[] outImage.data;
}
if (codec_context != nullptr) {
astcenc_context_free(codec_context);
}
}
static bool DecAstc(uint8_t *recRgba, uint32_t stride, AstcInfo astcInfo)
{
unsigned int blockX = 0;
unsigned int blockY = 0;
bool cond = CheckAstcHead(astcInfo.astcBuf, blockX, blockY, astcInfo.astcBufSize);
CHECK_ERROR_RETURN_RET(!cond, false);
unsigned int xblocks = (astcInfo.dimX + blockX - 1) / blockX;
unsigned int yblocks = (astcInfo.dimY + blockY - 1) / blockY;
size_t dataSize = static_cast<size_t>(xblocks) * static_cast<size_t>(yblocks) * ASTC_UNIT_BYTES;
CHECK_ERROR_RETURN_RET_LOG(dataSize + ASTC_UNIT_BYTES > astcInfo.astcBufSize, false,
"DecAstc astc buffer is invalid, dataSize: %{public}zu, astcBufSize: %{public}d",
dataSize, astcInfo.astcBufSize);
astcenc_config config = {};
astcenc_error status = astcenc_config_init(ASTCENC_PRF_LDR_SRGB, blockX, blockY, 1, 0, 0x10, &config);
CHECK_ERROR_RETURN_RET_LOG(status != ASTCENC_SUCCESS, false,
"DecAstc init config failed with %{public}s", astcenc_get_error_string(status));
config.flags = 0x12;
astcenc_context *codec_context = nullptr;
status = astcenc_context_alloc(&config, 1, &codec_context);
CHECK_ERROR_RETURN_RET_LOG(status != ASTCENC_SUCCESS, false,
"DecAstc codec context alloc failed: %{public}s", astcenc_get_error_string(status));
astcenc_image outImage;
if (!InitAstcOutImage(outImage, astcInfo.astcBuf, recRgba, stride)) {
FreeAstcMem(outImage, codec_context);
return false;
}
astcenc_swizzle swz_decode {ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A};
status = astcenc_decompress_image(codec_context, astcInfo.astcBuf + ASTC_UNIT_BYTES, dataSize, &outImage,
&swz_decode, 0);
if (status != ASTCENC_SUCCESS) {
IMAGE_LOGE("DecAstc codec decompress failed: %{public}s", astcenc_get_error_string(status));
FreeAstcMem(outImage, codec_context);
return false;
}
FreeAstcMem(outImage, codec_context);
return true;
}
static bool CheckInputValid(AstcInfo &astcInfo, PixelFormat destFormat)
{
bool isInvalidInput = (astcInfo.astcBufSize < ASTC_UNIT_BYTES || astcInfo.astcBuf == nullptr ||
astcInfo.format != PixelFormat::ASTC_4x4 || destFormat != PixelFormat::RGBA_8888);
CHECK_ERROR_RETURN_RET_LOG(isInvalidInput, false,
"DecAstc input astcBuf is null or src is not astc_4x4 or dst is not rgba_8888");
unsigned int dimX = UnpackBytes(astcInfo.astcBuf[BYTE_POS_7], astcInfo.astcBuf[BYTE_POS_8],
astcInfo.astcBuf[BYTE_POS_9], 0);
unsigned int dimY = UnpackBytes(astcInfo.astcBuf[BYTE_POS_10], astcInfo.astcBuf[BYTE_POS_11],
astcInfo.astcBuf[BYTE_POS_12], 0);
bool cond = dimX > ASTC_DIM_MAX || dimY > ASTC_DIM_MAX ||
dimX != static_cast<unsigned int>(astcInfo.astcSize.width) ||
dimY != static_cast<unsigned int>(astcInfo.astcSize.height);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "DecAstc dimX: %{public}d dimY: %{public}d overflow", dimX, dimY);
astcInfo.dimX = dimX;
astcInfo.dimY = dimY;
return true;
}
static void GetStride(AllocatorType allocatorType, void *data, uint32_t &stride, Size astcSize)
{
if (allocatorType == AllocatorType::DMA_ALLOC) {
SurfaceBuffer *surfaceBuffer = reinterpret_cast<SurfaceBuffer *>(data);
stride = static_cast<uint32_t>(surfaceBuffer->GetStride()) >> NUM_2;
} else {
stride = static_cast<uint32_t>(astcSize.width);
}
}
static void InitAstcInfo(AstcInfo &astcInfo, PixelMap *source)
{
astcInfo.astcBufSize = source->GetCapacity();
astcInfo.astcBuf = const_cast<uint8_t *>(source->GetPixels());
astcInfo.format = source->GetPixelFormat();
source->GetAstcRealSize(astcInfo.astcSize);
}
#endif
std::unique_ptr<PixelMap> PixelConvert::AstcToRgba(PixelMap *source, uint32_t &errorCode, PixelFormat destFormat)
{
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
auto colorSpace = source->InnerGetGrColorSpace();
AstcInfo astcInfo;
if (memset_s(&astcInfo, sizeof(AstcInfo), 0, sizeof(AstcInfo)) != 0) {
IMAGE_LOGE("DecAstc memset failed");
errorCode = ERR_IMAGE_INIT_ABNORMAL;
return nullptr;
}
InitAstcInfo(astcInfo, source);
if (!CheckInputValid(astcInfo, destFormat)) {
errorCode = ERR_IMAGE_INVALID_PARAMETER;
return nullptr;
}
uint32_t byteCount = static_cast<uint32_t>(astcInfo.astcSize.width * astcInfo.astcSize.height * BYTES_PER_PIXEL);
MemoryData memoryData = {nullptr, byteCount, "Create PixelMap", astcInfo.astcSize, PixelFormat::RGBA_8888};
memoryData.usage = source->GetNoPaddingUsage();
AllocatorType allocatorType = ImageUtils::GetPixelMapAllocatorType(astcInfo.astcSize, PixelFormat::RGBA_8888, true,
memoryData.usage);
std::unique_ptr<AbsMemory> dstMemory = MemoryManager::CreateMemory(allocatorType, memoryData);
if (dstMemory == nullptr) {
IMAGE_LOGE("DecAstc malloc failed");
errorCode = ERR_IMAGE_MALLOC_ABNORMAL;
return nullptr;
}
uint8_t *recRgba = static_cast<uint8_t *>(dstMemory->data.data);
uint32_t stride = 0;
GetStride(allocatorType, dstMemory->extend.data, stride, astcInfo.astcSize);
if (!DecAstc(recRgba, stride, astcInfo)) {
IMAGE_LOGE("DecAstc failed");
dstMemory->Release();
errorCode = ERR_IMAGE_DECODE_FAILED;
return nullptr;
}
InitializationOptions opts = { astcInfo.astcSize, PixelFormat::RGBA_8888 };
std::unique_ptr<PixelMap> result = PixelMap::Create(opts);
if (result == nullptr) {
IMAGE_LOGE("DecAstc create pixelmap failed");
dstMemory->Release();
errorCode = ERR_IMAGE_DECODE_FAILED;
return nullptr;
}
result->SetPixelsAddr(static_cast<void *>(recRgba), dstMemory->extend.data, byteCount, allocatorType, nullptr);
result->InnerSetColorSpace(colorSpace);
return result;
#else
errorCode = ERR_IMAGE_DECODE_FAILED;
return nullptr;
#endif
}
}
}