#ifndef __cplusplus
#error "ccap_convert.h is for C++ only. For C language, please use ccap_convert_c.h instead."
#endif
#pragma once
#ifndef CCAP_CONVERT_H
#define CCAP_CONVERT_H
#include "ccap_def.h"
#include <algorithm>
#include <cstdint>
#include <memory>
namespace ccap {
CCAP_EXPORT bool hasAVX2();
CCAP_EXPORT bool canUseAVX2();
CCAP_EXPORT bool enableAVX2(bool enable);
CCAP_EXPORT bool hasAppleAccelerate();
CCAP_EXPORT bool canUseAppleAccelerate();
CCAP_EXPORT bool enableAppleAccelerate(bool enable);
CCAP_EXPORT bool hasNEON();
CCAP_EXPORT bool canUseNEON();
CCAP_EXPORT bool enableNEON(bool enable);
enum class ConvertBackend : uint32_t {
AUTO, CPU, AVX2, AppleAccelerate, NEON, };
CCAP_EXPORT ConvertBackend getConvertBackend();
CCAP_EXPORT bool setConvertBackend(ConvertBackend backend);
inline void yuv2rgb601v(int y, int u, int v, int& r, int& g, int& b) {
y = y - 16; u = u - 128; v = v - 128;
r = (298 * y + 409 * v + 128) >> 8;
g = (298 * y - 100 * u - 208 * v + 128) >> 8;
b = (298 * y + 516 * u + 128) >> 8;
r = std::clamp(r, 0, 255);
g = std::clamp(g, 0, 255);
b = std::clamp(b, 0, 255);
}
inline void yuv2rgb709v(int y, int u, int v, int& r, int& g, int& b) {
y = y - 16; u = u - 128; v = v - 128;
r = (298 * y + 459 * v + 128) >> 8;
g = (298 * y - 55 * u - 136 * v + 128) >> 8;
b = (298 * y + 541 * u + 128) >> 8;
r = std::clamp(r, 0, 255);
g = std::clamp(g, 0, 255);
b = std::clamp(b, 0, 255);
}
inline void yuv2rgb601f(int y, int u, int v, int& r, int& g, int& b) {
u = u - 128; v = v - 128;
r = (256 * y + 351 * v + 128) >> 8;
g = (256 * y - 86 * u - 179 * v + 128) >> 8;
b = (256 * y + 443 * u + 128) >> 8;
r = std::clamp(r, 0, 255);
g = std::clamp(g, 0, 255);
b = std::clamp(b, 0, 255);
}
inline void yuv2rgb709f(int y, int u, int v, int& r, int& g, int& b) {
u = u - 128; v = v - 128;
r = (256 * y + 403 * v + 128) >> 8;
g = (256 * y - 48 * u - 120 * v + 128) >> 8;
b = (256 * y + 475 * u + 128) >> 8;
r = std::clamp(r, 0, 255);
g = std::clamp(g, 0, 255);
b = std::clamp(b, 0, 255);
}
enum class ConvertFlag {
BT601 = 0x1, BT709 = 0x2, FullRange = 0x10, VideoRange = 0x20, Default = BT601 | VideoRange, };
inline bool operator&(ConvertFlag lhs, ConvertFlag rhs) { return static_cast<bool>(static_cast<int>(lhs) & static_cast<int>(rhs)); }
inline ConvertFlag operator|(ConvertFlag lhs, ConvertFlag rhs) {
return static_cast<ConvertFlag>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
typedef void (*YuvToRgbFunc)(int y, int u, int v, int& r, int& g, int& b);
inline YuvToRgbFunc getYuvToRgbFunc(bool is601, bool isFullRange) {
if (is601) {
if (isFullRange)
return yuv2rgb601f;
else
return yuv2rgb601v;
} else {
if (isFullRange)
return yuv2rgb709f;
else
return yuv2rgb709v;
}
}
template <int inputChannels, int outputChannels, int swapRB>
CCAP_EXPORT void colorShuffle(const uint8_t* src, int srcStride, uint8_t* dst, int dstStride, int width, int height);
inline void rgbaToBgra(const uint8_t* src, int srcStride, uint8_t* dst, int dstStride, int width, int height) {
colorShuffle<4, 4, true>(src, srcStride, dst, dstStride, width, height);
}
constexpr auto bgraToRgba = rgbaToBgra;
inline void rgbaToBgr(const uint8_t* src, int srcStride, uint8_t* dst, int dstStride, int width, int height) {
colorShuffle<4, 3, true>(src, srcStride, dst, dstStride, width, height);
}
constexpr auto bgraToRgb = rgbaToBgr;
inline void rgbaToRgb(const uint8_t* src, int srcStride, uint8_t* dst, int dstStride, int width, int height) {
colorShuffle<4, 3, false>(src, srcStride, dst, dstStride, width, height);
}
constexpr auto bgra2bgr = rgbaToRgb;
inline void rgbToBgra(const uint8_t* src, int srcStride, uint8_t* dst, int dstStride, int width, int height) {
colorShuffle<3, 4, true>(src, srcStride, dst, dstStride, width, height);
}
constexpr auto bgrToRgba = rgbToBgra;
inline void rgbToRgba(const uint8_t* src, int srcStride, uint8_t* dst, int dstStride, int width, int height) {
colorShuffle<3, 4, false>(src, srcStride, dst, dstStride, width, height);
}
constexpr auto bgrToBgra = rgbToRgba;
inline void rgbToBgr(const uint8_t* src, int srcStride, uint8_t* dst, int dstStride, int width, int height) {
colorShuffle<3, 3, true>(src, srcStride, dst, dstStride, width, height);
}
constexpr auto bgrToRgb = rgbToBgr;
CCAP_EXPORT void nv12ToBgr24(const uint8_t* srcY, int srcYStride,
const uint8_t* srcUV, int srcUVStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void nv12ToRgb24(const uint8_t* srcY, int srcYStride,
const uint8_t* srcUV, int srcUVStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void nv12ToBgra32(const uint8_t* srcY, int srcYStride,
const uint8_t* srcUV, int srcUVStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void nv12ToRgba32(const uint8_t* srcY, int srcYStride,
const uint8_t* srcUV, int srcUVStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void i420ToBgr24(const uint8_t* srcY, int srcYStride,
const uint8_t* srcU, int srcUStride,
const uint8_t* srcV, int srcVStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void i420ToRgb24(const uint8_t* srcY, int srcYStride,
const uint8_t* srcU, int srcUStride,
const uint8_t* srcV, int srcVStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void i420ToBgra32(const uint8_t* srcY, int srcYStride,
const uint8_t* srcU, int srcUStride,
const uint8_t* srcV, int srcVStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void i420ToRgba32(const uint8_t* srcY, int srcYStride,
const uint8_t* srcU, int srcUStride,
const uint8_t* srcV, int srcVStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void yuyvToBgr24(const uint8_t* src, int srcStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void yuyvToRgb24(const uint8_t* src, int srcStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void yuyvToBgra32(const uint8_t* src, int srcStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void yuyvToRgba32(const uint8_t* src, int srcStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void uyvyToBgr24(const uint8_t* src, int srcStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void uyvyToRgb24(const uint8_t* src, int srcStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void uyvyToBgra32(const uint8_t* src, int srcStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
CCAP_EXPORT void uyvyToRgba32(const uint8_t* src, int srcStride,
uint8_t* dst, int dstStride,
int width, int height, ConvertFlag flag = ConvertFlag::Default);
class Allocator;
CCAP_EXPORT std::shared_ptr<ccap::Allocator> getSharedAllocator();
CCAP_EXPORT void resetSharedAllocator();
}
#endif