* Copyright (C) 2021-2026 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 "image_utils.h"
#include <sys/stat.h>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <string>
#include <fstream>
#include <sstream>
#include <chrono>
#include <atomic>
#include "__config"
#include "image_log.h"
#include "ios"
#include "istream"
#include "media_errors.h"
#include "memory_manager.h"
#include "new"
#include "plugin_server.h"
#include "securec.h"
#include "singleton.h"
#include "string"
#include "type_traits"
#include "vector"
#include "image_trace.h"
#include "hitrace_meter.h"
#include "image_system_properties.h"
#include "image/abs_image_decoder.h"
#include "pixel_map.h"
#ifdef IOS_PLATFORM
#include <sys/syscall.h>
#endif
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
#include "surface_buffer.h"
#include "surface_type.h"
#include "bundle_mgr_interface.h"
#include "iservice_registry.h"
#include "tokenid_kit.h"
#include "ipc_skeleton.h"
#include "system_ability_definition.h"
#include "os_account_manager.h"
#include "v1_0/cm_color_space.h"
#include "v1_0/buffer_handle_meta_key_type.h"
#include "metadata_helper.h"
#include "v1_0/hdr_static_metadata.h"
#include "vpe_utils.h"
#else
#include "refbase.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 "imageUtils"
namespace OHOS {
namespace Media {
using namespace std;
using namespace MultimediaPlugin;
#if !defined(CROSS_PLATFORM)
static const std::map<PixelFormat, int32_t> PIXEL_FORMAT_TO_GRAPHIC_MAP = {
{ PixelFormat::RGBA_8888, GRAPHIC_PIXEL_FMT_RGBA_8888 },
{ PixelFormat::NV12, GRAPHIC_PIXEL_FMT_YCBCR_420_SP },
{ PixelFormat::NV21, GRAPHIC_PIXEL_FMT_YCRCB_420_SP },
{ PixelFormat::RGBA_1010102, GRAPHIC_PIXEL_FMT_RGBA_1010102 },
{ PixelFormat::BGRA_8888, GRAPHIC_PIXEL_FMT_BGRA_8888 },
{ PixelFormat::RGB_888, GRAPHIC_PIXEL_FMT_RGB_888 },
{ PixelFormat::RGB_565, GRAPHIC_PIXEL_FMT_RGB_565 },
{ PixelFormat::RGBA_F16, GRAPHIC_PIXEL_FMT_RGBA16_FLOAT },
{ PixelFormat::YCBCR_P010, GRAPHIC_PIXEL_FMT_YCBCR_P010 },
{ PixelFormat::YCRCB_P010, GRAPHIC_PIXEL_FMT_YCRCB_P010 },
};
#define GET_VAR_NAME(var) #var
using namespace HDI::Display::Graphic::Common::V1_0;
#endif
constexpr int32_t ALPHA8_BYTES = 1;
constexpr int32_t ALPHA_F16_BYTES = 2;
constexpr int32_t Y8_BYTES = 1;
constexpr int32_t RGB565_BYTES = 2;
constexpr int32_t RGB888_BYTES = 3;
constexpr int32_t ARGB8888_BYTES = 4;
constexpr int32_t RGBA_F16_BYTES = 8;
constexpr int32_t NV21_BYTES = 2;
constexpr uint8_t MOVE_BITS_8 = 8;
constexpr uint8_t MOVE_BITS_16 = 16;
constexpr uint8_t MOVE_BITS_24 = 24;
constexpr int32_t NV21P010_BYTES = 3;
constexpr int32_t ASTC_4X4_BYTES = 1;
constexpr int32_t ASTC_4X4_BLOCK = 4;
constexpr int32_t ASTC_6X6_BLOCK = 6;
constexpr int32_t ASTC_8X8_BLOCK = 8;
constexpr int32_t ASTC_BLOCK_SIZE = 16;
constexpr int32_t ASTC_HEADER_SIZE = 16;
constexpr uint8_t FILL_NUMBER = 3;
constexpr uint8_t ALIGN_NUMBER = 4;
constexpr int32_t DMA_SIZE = 512 * 512;
constexpr int32_t NOPADDING_DMA_SIZE = 256 * 256;
constexpr int32_t FAULT_API_VERSION = -1;
constexpr int32_t BUNDLE_MGR_SERVICE_SYS_ABILITY_ID = 401;
constexpr int32_t BASE_EVEN_DIVISOR = 2;
constexpr float EPSILON = 1e-6;
constexpr float FLOAT_1 = 1.0f;
constexpr int MAX_DIMENSION = INT32_MAX >> 2;
static bool g_pluginRegistered = false;
static const uint8_t NUM_0 = 0;
static const uint8_t NUM_1 = 1;
static const uint8_t NUM_2 = 2;
static const uint8_t NUM_3 = 3;
static const uint8_t NUM_4 = 4;
static const uint8_t NUM_5 = 5;
static const uint8_t NUM_6 = 6;
static const uint8_t NUM_7 = 7;
static const uint8_t INT_255 = 255;
static const string FILE_DIR_IN_THE_SANDBOX = "/data/storage/el2/base/files/";
static constexpr int32_t PLANE_Y = 0;
static constexpr int32_t PLANE_U = 1;
static constexpr int32_t PLANE_V = 2;
constexpr int32_t MEM_DMA = 1;
constexpr int32_t MEM_SHARE = 2;
constexpr uint32_t RGBA1010102_RGB_MASK = 0x3FF;
constexpr uint32_t RGBA1010102_ALPHA_MASK = 0x03;
constexpr uint32_t RGBA1010102_R_SHIFT = 0;
constexpr uint32_t RGBA1010102_G_SHIFT = 10;
constexpr uint32_t RGBA1010102_B_SHIFT = 20;
constexpr uint32_t RGBA1010102_A_SHIFT = 30;
const std::map<PixelFormat, AVPixelFormat> FFMPEG_PIXEL_FORMAT_MAP = {
{PixelFormat::UNKNOWN, AV_PIX_FMT_NONE},
{PixelFormat::NV12, AV_PIX_FMT_NV12},
{PixelFormat::NV21, AV_PIX_FMT_NV21},
{PixelFormat::RGB_565, AV_PIX_FMT_RGB565},
{PixelFormat::RGBA_8888, AV_PIX_FMT_RGBA},
{PixelFormat::BGRA_8888, AV_PIX_FMT_BGRA},
{PixelFormat::ARGB_8888, AV_PIX_FMT_ARGB},
{PixelFormat::RGBA_F16, AV_PIX_FMT_RGBA64},
{PixelFormat::RGB_888, AV_PIX_FMT_RGB24},
{PixelFormat::YCRCB_P010, AV_PIX_FMT_P010LE},
{PixelFormat::YCBCR_P010, AV_PIX_FMT_P010LE},
{PixelFormat::Y8, AV_PIX_FMT_GRAY8},
};
#if !defined(CROSS_PLATFORM)
static const std::map<int32_t, PixelFormat> PIXEL_FORMAT_MAP = {
{ GRAPHIC_PIXEL_FMT_RGBA_8888, PixelFormat::RGBA_8888 },
{ GRAPHIC_PIXEL_FMT_YCBCR_420_SP, PixelFormat::NV12 },
{ GRAPHIC_PIXEL_FMT_YCRCB_420_SP, PixelFormat::NV21 },
{ GRAPHIC_PIXEL_FMT_RGBA_1010102, PixelFormat::RGBA_1010102 },
{ GRAPHIC_PIXEL_FMT_BGRA_8888, PixelFormat::BGRA_8888 },
{ GRAPHIC_PIXEL_FMT_RGB_888, PixelFormat::RGB_888 },
{ GRAPHIC_PIXEL_FMT_RGB_565, PixelFormat::RGB_565 },
{ GRAPHIC_PIXEL_FMT_RGBA16_FLOAT, PixelFormat::RGBA_F16 },
{ GRAPHIC_PIXEL_FMT_YCBCR_P010, PixelFormat::YCBCR_P010 },
{ GRAPHIC_PIXEL_FMT_YCRCB_P010, PixelFormat::YCRCB_P010 },
};
static const std::map<CM_ColorSpaceType, ColorSpace> CM_COLORSPACE_MAP = {
{ CM_COLORSPACE_NONE, ColorSpace::UNKNOWN },
{ CM_BT709_FULL, ColorSpace::ITU_709 },
{ CM_BT2020_HLG_FULL, ColorSpace::ITU_2020 },
{ CM_BT2020_PQ_FULL, ColorSpace::ITU_2020 },
{ CM_BT709_LIMIT, ColorSpace::ITU_709 },
{ CM_BT2020_HLG_LIMIT, ColorSpace::ITU_2020 },
{ CM_BT2020_PQ_LIMIT, ColorSpace::ITU_2020 },
{ CM_SRGB_FULL, ColorSpace::SRGB },
{ CM_P3_FULL, ColorSpace::DISPLAY_P3 },
{ CM_P3_HLG_FULL, ColorSpace::DISPLAY_P3 },
{ CM_P3_PQ_FULL, ColorSpace::DISPLAY_P3 },
{ CM_ADOBERGB_FULL, ColorSpace::ADOBE_RGB_1998 },
{ CM_SRGB_LIMIT, ColorSpace::SRGB },
{ CM_P3_LIMIT, ColorSpace::DISPLAY_P3 },
{ CM_P3_HLG_LIMIT, ColorSpace::DISPLAY_P3 },
{ CM_P3_PQ_LIMIT, ColorSpace::DISPLAY_P3 },
{ CM_ADOBERGB_LIMIT, ColorSpace::ADOBE_RGB_1998 },
{ CM_LINEAR_SRGB, ColorSpace::LINEAR_SRGB },
{ CM_LINEAR_BT709, ColorSpace::ITU_709 },
{ CM_LINEAR_P3, ColorSpace::DISPLAY_P3 },
{ CM_LINEAR_BT2020, ColorSpace::ITU_2020 },
{ CM_DISPLAY_SRGB, ColorSpace::SRGB },
{ CM_DISPLAY_P3_SRGB, ColorSpace::DISPLAY_P3 },
{ CM_DISPLAY_P3_HLG, ColorSpace::DISPLAY_P3 },
{ CM_DISPLAY_P3_PQ, ColorSpace::DISPLAY_P3 },
{ CM_DISPLAY_BT2020_SRGB, ColorSpace::ITU_2020 },
{ CM_DISPLAY_BT2020_HLG, ColorSpace::ITU_2020 },
{ CM_DISPLAY_BT2020_PQ, ColorSpace::ITU_2020 },
};
static const std::map<CM_ColorSpaceType, ColorManager::ColorSpaceName> CM_COLORSPACE_NAME_MAP = {
{CM_COLORSPACE_NONE, ColorManager::NONE},
{CM_BT601_EBU_FULL, ColorManager::BT601_EBU},
{CM_BT601_SMPTE_C_FULL, ColorManager::BT601_SMPTE_C},
{CM_BT709_FULL, ColorManager::BT709},
{CM_BT2020_HLG_FULL, ColorManager::BT2020_HLG},
{CM_BT2020_PQ_FULL, ColorManager::BT2020_PQ},
{CM_BT601_EBU_LIMIT, ColorManager::BT601_EBU_LIMIT},
{CM_BT601_SMPTE_C_LIMIT, ColorManager::BT601_SMPTE_C_LIMIT},
{CM_BT709_LIMIT, ColorManager::BT709_LIMIT},
{CM_BT2020_HLG_LIMIT, ColorManager::BT2020_HLG_LIMIT},
{CM_BT2020_PQ_LIMIT, ColorManager::BT2020_PQ_LIMIT},
{CM_SRGB_FULL, ColorManager::SRGB},
{CM_P3_FULL, ColorManager::DISPLAY_P3},
{CM_P3_HLG_FULL, ColorManager::P3_HLG},
{CM_P3_PQ_FULL, ColorManager::P3_PQ},
{CM_ADOBERGB_FULL, ColorManager::ADOBE_RGB},
{CM_SRGB_LIMIT, ColorManager::SRGB_LIMIT},
{CM_P3_LIMIT, ColorManager::DISPLAY_P3_LIMIT},
{CM_P3_HLG_LIMIT, ColorManager::P3_HLG_LIMIT},
{CM_P3_PQ_LIMIT, ColorManager::P3_PQ_LIMIT},
{CM_ADOBERGB_LIMIT, ColorManager::ADOBE_RGB_LIMIT},
{CM_LINEAR_SRGB, ColorManager::LINEAR_SRGB},
{CM_LINEAR_BT709, ColorManager::LINEAR_BT709},
{CM_LINEAR_P3, ColorManager::LINEAR_P3},
{CM_LINEAR_BT2020, ColorManager::LINEAR_BT2020},
{CM_DISPLAY_SRGB, ColorManager::DISPLAY_SRGB},
{CM_DISPLAY_P3_SRGB, ColorManager::DISPLAY_P3_SRGB},
{CM_DISPLAY_P3_HLG, ColorManager::DISPLAY_P3_HLG},
{CM_DISPLAY_P3_PQ, ColorManager::DISPLAY_P3_PQ},
{CM_DISPLAY_BT2020_SRGB, ColorManager::DISPLAY_BT2020_SRGB},
{CM_DISPLAY_BT2020_HLG, ColorManager::DISPLAY_BT2020_HLG},
{CM_DISPLAY_BT2020_PQ, ColorManager::DISPLAY_BT2020_PQ},
};
#endif
bool ImageUtils::GetFileSize(const string &pathName, size_t &size)
{
if (pathName.empty()) {
IMAGE_LOGE("[ImageUtil]input parameter exception.");
return false;
}
struct stat statbuf;
int ret = stat(pathName.c_str(), &statbuf);
if (ret != 0) {
IMAGE_LOGE("[ImageUtil]get the file size failed, ret:%{public}d, errno:%{public}d.", ret, errno);
return false;
}
size = statbuf.st_size;
return true;
}
bool ImageUtils::GetFileSize(const int fd, size_t &size)
{
struct stat statbuf;
if (fd < 0) {
return false;
}
int ret = fstat(fd, &statbuf);
if (ret != 0) {
IMAGE_LOGE("[ImageUtil]get the file size failed, ret:%{public}d, errno:%{public}d.", ret, errno);
return false;
}
size = statbuf.st_size;
return true;
}
bool ImageUtils::GetInputStreamSize(istream &inputStream, size_t &size)
{
if (inputStream.rdbuf() == nullptr) {
IMAGE_LOGE("[ImageUtil]input parameter exception.");
return false;
}
size_t original = inputStream.tellg();
inputStream.seekg(0, ios_base::end);
size = inputStream.tellg();
inputStream.seekg(original);
return true;
}
int32_t ImageUtils::GetPixelBytes(const PixelFormat &pixelFormat)
{
int pixelBytes = 0;
switch (pixelFormat) {
case PixelFormat::ARGB_8888:
case PixelFormat::BGRA_8888:
case PixelFormat::RGBA_8888:
case PixelFormat::RGBA_1010102:
case PixelFormat::CMYK:
pixelBytes = ARGB8888_BYTES;
break;
case PixelFormat::ALPHA_8:
case PixelFormat::ALPHA_U8:
pixelBytes = ALPHA8_BYTES;
break;
case PixelFormat::Y8:
pixelBytes = Y8_BYTES;
break;
case PixelFormat::ALPHA_F16:
pixelBytes = ALPHA_F16_BYTES;
break;
case PixelFormat::RGB_888:
pixelBytes = RGB888_BYTES;
break;
case PixelFormat::RGB_565:
pixelBytes = RGB565_BYTES;
break;
case PixelFormat::RGBA_F16:
case PixelFormat::RGBA_U16:
pixelBytes = RGBA_F16_BYTES;
break;
case PixelFormat::NV21:
case PixelFormat::NV12:
pixelBytes = NV21_BYTES;
break;
case PixelFormat::ASTC_4x4:
case PixelFormat::ASTC_6x6:
case PixelFormat::ASTC_8x8:
pixelBytes = ASTC_4X4_BYTES;
break;
case PixelFormat::YCBCR_P010:
case PixelFormat::YCRCB_P010:
pixelBytes = NV21P010_BYTES;
break;
default:
IMAGE_LOGE("[ImageUtil]get pixel bytes failed, pixelFormat:%{public}d.",
static_cast<int32_t>(pixelFormat));
break;
}
return pixelBytes;
}
static AVPixelFormat PixelFormatToAVPixelFormat(const PixelFormat &pixelFormat)
{
auto formatSearch = FFMPEG_PIXEL_FORMAT_MAP.find(pixelFormat);
return (formatSearch != FFMPEG_PIXEL_FORMAT_MAP.end()) ?
formatSearch->second : AVPixelFormat::AV_PIX_FMT_NONE;
}
int32_t ImageUtils::GetYUVByteCount(const ImageInfo& info)
{
if (!IsYuvFormat(info.pixelFormat)) {
IMAGE_LOGE("[ImageUtil]unsupported pixel format");
return -1;
}
if (info.size.width <= 0 || info.size.height <= 0) {
IMAGE_LOGE("[ImageUtil]image size error");
return -1;
}
AVPixelFormat avPixelFormat = PixelFormatToAVPixelFormat(info.pixelFormat);
if (avPixelFormat == AVPixelFormat::AV_PIX_FMT_NONE) {
IMAGE_LOGE("[ImageUtil]pixel format to ffmpeg pixel format failed");
return -1;
}
return av_image_get_buffer_size(avPixelFormat, info.size.width, info.size.height, 1);
}
int32_t ImageUtils::GetByteCount(ImageInfo imageInfo)
{
if (ImageUtils::IsAstc(imageInfo.pixelFormat)) {
return static_cast<int32_t>(ImageUtils::GetAstcBytesCount(imageInfo));
}
if (IsYuvFormat(imageInfo.pixelFormat)) {
return GetYUVByteCount(imageInfo);
}
int64_t rowDataSize =
ImageUtils::GetRowDataSizeByPixelFormat(imageInfo.size.width, imageInfo.pixelFormat);
int64_t height = imageInfo.size.height;
int64_t byteCount = rowDataSize * height;
if (rowDataSize <= 0 || byteCount > INT32_MAX) {
IMAGE_LOGE("[PixelMap] GetByteCount failed: invalid rowDataSize or byteCount overflowed");
return 0;
}
return static_cast<int32_t>(byteCount);
}
int32_t ImageUtils::GetRowDataSizeByPixelFormat(const int32_t &width, const PixelFormat &format)
{
uint64_t uWidth = static_cast<uint64_t>(width);
uint64_t pixelBytes = static_cast<uint64_t>(GetPixelBytes(format));
uint64_t rowDataSize = 0;
switch (format) {
case PixelFormat::ALPHA_8:
rowDataSize = pixelBytes * ((uWidth + FILL_NUMBER) / ALIGN_NUMBER * ALIGN_NUMBER);
break;
case PixelFormat::ASTC_4x4:
rowDataSize = pixelBytes * (((uWidth + NUM_3) >> NUM_2) << NUM_2);
break;
case PixelFormat::ASTC_6x6:
rowDataSize = pixelBytes * (((uWidth + NUM_5) / NUM_6) * NUM_6);
break;
case PixelFormat::ASTC_8x8:
rowDataSize = pixelBytes * (((uWidth + NUM_7) >> NUM_3) << NUM_3);
break;
default:
rowDataSize = pixelBytes * uWidth;
}
if (rowDataSize > INT32_MAX) {
IMAGE_LOGE("GetRowDataSizeByPixelFormat failed: rowDataSize overflowed");
return -1;
}
return static_cast<int32_t>(rowDataSize);
}
uint32_t ImageUtils::RegisterPluginServer()
{
#ifdef _WIN32
vector<string> pluginPaths = { "" };
#elif defined(_APPLE)
vector<string> pluginPaths = { "./" };
#elif defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
vector<string> pluginPaths = {};
#else
vector<string> pluginPaths = { "/system/etc/multimediaplugin/image" };
#endif
PluginServer &pluginServer = DelayedRefSingleton<PluginServer>::GetInstance();
uint32_t result = pluginServer.Register(std::move(pluginPaths));
if (result != SUCCESS) {
IMAGE_LOGD("[ImageUtil]failed to register plugin server, ERRNO: %{public}u.", result);
} else {
g_pluginRegistered = true;
IMAGE_LOGD("[ImageUtil]success to register plugin server");
}
return result;
}
PluginServer& ImageUtils::GetPluginServer()
{
if (!g_pluginRegistered) {
uint32_t result = RegisterPluginServer();
if (result != SUCCESS) {
IMAGE_LOGD("[ImageUtil]failed to register plugin server, ERRNO: %{public}u.", result);
}
}
return DelayedRefSingleton<PluginServer>::GetInstance();
}
bool ImageUtils::PathToRealPath(const string &path, string &realPath)
{
if (path.empty()) {
IMAGE_LOGE("path is empty!");
return false;
}
if ((path.length() >= PATH_MAX)) {
IMAGE_LOGE("path len is error, the len is: [%{public}lu]", static_cast<unsigned long>(path.length()));
return false;
}
char tmpPath[PATH_MAX] = { 0 };
#ifdef _WIN32
if (_fullpath(tmpPath, path.c_str(), PATH_MAX) == nullptr) {
IMAGE_LOGW("path to _fullpath error");
}
#else
if (realpath(path.c_str(), tmpPath) == nullptr) {
IMAGE_LOGE("path to realpath is nullptr");
return false;
}
#endif
realPath = tmpPath;
return true;
}
bool ImageUtils::FloatCompareZero(float src)
{
return fabs(src - 0) < EPSILON;
}
AlphaType ImageUtils::GetValidAlphaTypeByFormat(const AlphaType &dstType, const PixelFormat &format)
{
switch (format) {
case PixelFormat::RGBA_8888:
case PixelFormat::BGRA_8888:
case PixelFormat::ARGB_8888:
case PixelFormat::RGBA_1010102:
case PixelFormat::RGBA_U16:
case PixelFormat::RGBA_F16: {
break;
}
case PixelFormat::ALPHA_8:
case PixelFormat::ALPHA_U8: {
if (dstType != AlphaType::IMAGE_ALPHA_TYPE_PREMUL) {
return AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
}
break;
}
case PixelFormat::ALPHA_F16: {
if (dstType != AlphaType::IMAGE_ALPHA_TYPE_PREMUL) {
return AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
}
break;
}
case PixelFormat::RGB_888:
case PixelFormat::RGB_565:
case PixelFormat::Y8: {
if (dstType != AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) {
return AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
}
break;
}
case PixelFormat::NV21:
case PixelFormat::NV12:
case PixelFormat::YCBCR_P010:
case PixelFormat::YCRCB_P010: {
if (dstType != AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) {
return AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
}
break;
}
case PixelFormat::CMYK:
default: {
IMAGE_LOGE("GetValidAlphaTypeByFormat unsupport the format(%{public}d).", format);
return AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
}
}
return dstType;
}
AllocatorType ImageUtils::GetPixelMapAllocatorType(const Size &size, const PixelFormat &format, bool preferDma,
uint64_t &usage)
{
bool isUseDefaultDmaNopadding = false;
return GetPixelMapAllocatorType(size, format, preferDma, usage, isUseDefaultDmaNopadding);
}
AllocatorType ImageUtils::GetPixelMapAllocatorType(const Size &size, const PixelFormat &format, bool preferDma,
uint64_t &usage, bool &isUseDefaultDmaNopadding)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
if (IsSizeSupportDma(size) && (preferDma || (IsWidthAligned(size.width) && IsFormatSupportDma(format))) &&
(format == PixelFormat::RGBA_8888 || format == PixelFormat::ALPHA_F16 || Is10Bit(format))) {
return AllocatorType::DMA_ALLOC;
} else if (IsSupportDefaultDmaNopadding(size, format)) {
usage |= BUFFER_USAGE_PREFER_NO_PADDING | BUFFER_USAGE_ALLOC_NO_IPC;
isUseDefaultDmaNopadding = true;
return AllocatorType::DMA_ALLOC;
} else {
return AllocatorType::SHARE_MEM_ALLOC;
}
#else
return AllocatorType::HEAP_ALLOC;
#endif
}
bool ImageUtils::IsValidImageInfo(const ImageInfo &info)
{
if (info.size.width <= 0 || info.size.height <= 0 || info.size.width > MAX_DIMENSION ||
info.size.height > MAX_DIMENSION) {
IMAGE_LOGE("width(%{public}d) or height(%{public}d) is invalid.", info.size.width, info.size.height);
return false;
}
if (info.pixelFormat == PixelFormat::UNKNOWN || info.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) {
IMAGE_LOGE("check pixelformat and alphatype is invalid.");
return false;
}
return true;
}
bool ImageUtils::IsValidAuxiliaryInfo(const std::shared_ptr<PixelMap> &pixelMap, const AuxiliaryPictureInfo &info)
{
int32_t rowSize = ImageUtils::GetRowDataSizeByPixelFormat(info.size.width, info.pixelFormat);
bool cond = rowSize <= 0 || info.size.height <= 0 ||
rowSize > std::numeric_limits<int32_t>::max() / info.size.height;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "%{public}s rowSize: %{public}d, height: %{public}d may overflowed",
__func__, rowSize, info.size.height);
uint32_t infoSize = static_cast<uint32_t>(rowSize * info.size.height);
if (info.pixelFormat == PixelFormat::NV21 || info.pixelFormat == PixelFormat::NV12) {
ImageInfo imageInfo;
imageInfo.size = info.size;
imageInfo.pixelFormat = info.pixelFormat;
int32_t byteCount = ImageUtils::GetByteCount(imageInfo);
infoSize = (byteCount > 0) ? static_cast<uint32_t>(byteCount) : infoSize;
}
uint32_t pixelsSize = pixelMap->GetCapacity();
cond = infoSize > pixelsSize;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "%{public}s invalid infoSize: %{public}u, pixelsSize: %{public}u",
__func__, infoSize, pixelsSize);
return true;
}
bool ImageUtils::IsAstc(PixelFormat format)
{
return format == PixelFormat::ASTC_4x4 || format == PixelFormat::ASTC_6x6 || format == PixelFormat::ASTC_8x8;
}
bool IsYUV8Bit(PixelFormat &format)
{
return format == PixelFormat::NV12 || format == PixelFormat::NV21 || format == PixelFormat::Y8;
}
bool IsYUV10Bit(PixelFormat &format)
{
return format == PixelFormat::YCBCR_P010 || format == PixelFormat::YCRCB_P010;
}
bool ImageUtils::IsYuvFormat(PixelFormat format)
{
return IsYUV8Bit(format) || IsYUV10Bit(format);
}
bool ImageUtils::IsRGBX(PixelFormat format)
{
return format == PixelFormat::ARGB_8888 || format == PixelFormat::RGB_565 ||
format == PixelFormat::RGBA_8888 || format == PixelFormat::BGRA_8888 ||
format == PixelFormat::RGB_888 || format == PixelFormat::ALPHA_8 ||
format == PixelFormat::ALPHA_U8 || format == PixelFormat::ALPHA_F16 ||
format == PixelFormat::RGBA_F16 || format == PixelFormat::RGBA_1010102 ||
format == PixelFormat::RGBA_U16 || format == PixelFormat::UNKNOWN;
}
bool ImageUtils::IsAlpha8(PixelFormat format)
{
return format == PixelFormat::ALPHA_8 || format == PixelFormat::ALPHA_U8;
}
bool ImageUtils::PixelMapCreateCheckFormat(PixelFormat format)
{
if (IsRGBX(format)) {
return true;
}
if (IsYuvFormat(format)) {
return true;
}
return false;
}
bool ImageUtils::CheckTlvSupportedFormat(PixelFormat format)
{
if (format == PixelFormat::UNKNOWN || format == PixelFormat::RGBA_U16 ||
IsYUV8Bit(format)) {
return false;
}
if (IsRGBX(format)) {
return true;
}
if (IsYUV10Bit(format)) {
return true;
}
return false;
}
bool ImageUtils::IsWidthAligned(const int32_t &width)
{
return ((static_cast<uint32_t>(width) * NUM_4) & INT_255) == 0;
}
bool ImageUtils::IsSizeSupportDma(const Size &size, bool isUseDefaultDmaNopadding)
{
if (size.width > 0 && size.height > INT_MAX / size.width) {
return false;
}
int32_t minSize = isUseDefaultDmaNopadding ? NOPADDING_DMA_SIZE : DMA_SIZE;
return size.width * size.height >= minSize;
}
bool ImageUtils::IsFormatSupportDma(const PixelFormat &format)
{
return format == PixelFormat::UNKNOWN || format == PixelFormat::RGBA_8888 || format == PixelFormat::ALPHA_F16;
}
bool ImageUtils::IsSupportDefaultDmaNopadding(const Size &size, const PixelFormat &format)
{
if (ImageSystemProperties::GetDefaultDmaNoPaddingEnabled() && ImageSystemProperties::GetNoPaddingEnabled() &&
IsSizeSupportDma(size, true) && (format == PixelFormat::BGRA_8888 || format == PixelFormat::RGBA_8888)) {
return true;
}
return false;
}
bool ImageUtils::Is10Bit(const PixelFormat &format)
{
return format == PixelFormat::RGBA_1010102 ||
format == PixelFormat::YCRCB_P010 || format == PixelFormat::YCBCR_P010;
}
bool ImageUtils::CheckMulOverflow(int32_t width, int32_t bytesPerPixel)
{
if (width == 0 || bytesPerPixel == 0) {
IMAGE_LOGE("param is 0");
return true;
}
int32_t rowSize;
if (__builtin_mul_overflow(width, bytesPerPixel, &rowSize)) {
IMAGE_LOGE("width * bytesPerPixel overflow!");
return true;
}
return false;
}
bool ImageUtils::CheckMulOverflow(int32_t width, int32_t height, int32_t bytesPerPixel)
{
if (width == 0 || height == 0 || bytesPerPixel == 0) {
IMAGE_LOGE("param is 0");
return true;
}
int32_t rectSize;
if (__builtin_mul_overflow(width, height, &rectSize)) {
IMAGE_LOGE("width * height overflow!");
return true;
}
int32_t bufferSize;
if (__builtin_mul_overflow(rectSize, bytesPerPixel, &bufferSize)) {
IMAGE_LOGE("bytesPerPixel overflow!");
return true;
}
return false;
}
bool ImageUtils::CheckFloatMulOverflow(float num1, float num2)
{
if (fabs(num1) <= FLOAT_1 || fabs(num2) <= FLOAT_1) {
return false;
}
CHECK_ERROR_RETURN_RET_LOG(fabs(num1) > std::numeric_limits<float>::max() / fabs(num2), true,
"num1 * num2 overflow! num1:%{public}f, num2:%{public}f", num1, num2);
return false;
}
bool ImageUtils::CheckFloatToInt32Overflow(float value)
{
return value > static_cast<float>(std::numeric_limits<int32_t>::max()) ||
value < static_cast<float>(std::numeric_limits<int32_t>::min());
}
static void ReversePixels(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)
{
if (byteCount % NUM_4 != NUM_0) {
IMAGE_LOGE("Pixel count must multiple of 4.");
return;
}
uint8_t *src = srcPixels;
uint8_t *dst = dstPixels;
for (uint32_t i = NUM_0 ; i < byteCount; i += NUM_4) {
dst[NUM_0] = src[NUM_3];
dst[NUM_1] = src[NUM_2];
dst[NUM_2] = src[NUM_1];
dst[NUM_3] = src[NUM_0];
src += NUM_4;
dst += NUM_4;
}
}
void ImageUtils::BGRAToARGB(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)
{
ImageTrace imageTrace("BGRAToARGB");
ReversePixels(srcPixels, dstPixels, byteCount);
}
void ImageUtils::ARGBToBGRA(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)
{
ReversePixels(srcPixels, dstPixels, byteCount);
}
int32_t ImageUtils::SurfaceBuffer_Reference(void* buffer)
{
if (buffer == nullptr) {
IMAGE_LOGE("input parameter error");
return ERR_SURFACEBUFFER_REFERENCE_FAILED;
}
OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(buffer);
ref->IncStrongRef(ref);
return SUCCESS;
}
int32_t ImageUtils::SurfaceBuffer_Unreference(void* buffer)
{
if (buffer == nullptr) {
IMAGE_LOGE("input parameter error");
return ERR_SURFACEBUFFER_UNREFERENCE_FAILED;
}
OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(buffer);
ref->DecStrongRef(ref);
return SUCCESS;
}
#if !defined(CROSS_PLATFORM)
bool ImageUtils::GetYuvInfoFromSurfaceBuffer(YUVDataInfo &yuvInfo, sptr<SurfaceBuffer> surfaceBuffer)
{
bool cond = surfaceBuffer == nullptr;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "%{public}s, surfaceBuffer is nullptr", __func__);
OH_NativeBuffer_Planes* planes = nullptr;
GSError retVal = surfaceBuffer->GetPlanesInfo(reinterpret_cast<void**>(&planes));
cond = retVal != OHOS::GSERROR_OK || planes == nullptr || planes->planeCount <= NUM_1;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "%{public}s, get planesInfo failed, retVal:%{public}d", __func__, retVal);
int32_t width = surfaceBuffer->GetWidth();
int32_t height = surfaceBuffer->GetHeight();
yuvInfo.imageSize = { width, height };
yuvInfo.yWidth = static_cast<uint32_t>(width);
yuvInfo.uvWidth = static_cast<uint32_t>((width + NUM_1) / NUM_2);
yuvInfo.yHeight = static_cast<uint32_t>(height);
yuvInfo.uvHeight = static_cast<uint32_t>((height + NUM_1) / NUM_2);
if (planes->planeCount >= NUM_2) {
int32_t pixelFmt = surfaceBuffer->GetFormat();
bool isYuvP010 = (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010 || pixelFmt == GRAPHIC_PIXEL_FMT_YCRCB_P010);
int uvPlaneIndex = (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_420_SP ||
pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010) ? NUM_1 : NUM_2;
yuvInfo.yStride = isYuvP010 ?
(planes->planes[NUM_0].columnStride / NUM_2) : (planes->planes[NUM_0].columnStride);
yuvInfo.uvStride = isYuvP010 ?
(planes->planes[uvPlaneIndex].columnStride / NUM_2) : (planes->planes[uvPlaneIndex].columnStride);
yuvInfo.yOffset = isYuvP010 ?
(planes->planes[NUM_0].offset / NUM_2) : (planes->planes[NUM_0].offset);
yuvInfo.uvOffset = isYuvP010 ?
(planes->planes[uvPlaneIndex].offset / NUM_2) : (planes->planes[uvPlaneIndex].offset);
return true;
}
return false;
}
bool ImageUtils::CopyYuvPixelMapToSurfaceBuffer(PixelMap* pixelmap,
sptr<SurfaceBuffer> surfaceBuffer)
{
CHECK_ERROR_RETURN_RET(pixelmap == nullptr || surfaceBuffer == nullptr, false);
uint8_t* srcBase = const_cast<uint8_t*>(pixelmap->GetPixels());
uint8_t* dst = static_cast<uint8_t*>(surfaceBuffer->GetVirAddr());
uint32_t dstSize = surfaceBuffer->GetSize();
YUVDataInfo yuvDstInfo;
YUVDataInfo yuvSrcInfo;
ImageUtils::UpdateYUVDataInfo(*pixelmap);
pixelmap->GetImageYUVInfo(yuvSrcInfo);
bool cond = !ImageUtils::GetYuvInfoFromDmaBuffer(surfaceBuffer, yuvDstInfo);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "Get YUVInfo from SurfaceBuffer failed");
uint64_t yPlaneEnd = static_cast<uint64_t>(yuvDstInfo.yStride) * yuvDstInfo.yHeight;
uint64_t uvPlaneEnd = static_cast<uint64_t>(yuvDstInfo.uvOffset) +
static_cast<uint64_t>(yuvDstInfo.uvStride) * yuvDstInfo.uvHeight;
cond = static_cast<uint64_t>(dstSize) < yPlaneEnd || static_cast<uint64_t>(dstSize) < uvPlaneEnd;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "SurfaceBuffer capacity insufficient.");
uint8_t* src = srcBase + yuvSrcInfo.yOffset;
for (uint32_t i = 0; i < yuvSrcInfo.yHeight; ++i) {
cond = memcpy_s(dst, dstSize, src, yuvSrcInfo.yWidth) != EOK;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "CopyYuvPixelMapToSurfaceBuffer Y plane memcpy failed");
dst += yuvDstInfo.yStride;
dstSize -= yuvDstInfo.yStride;
src += yuvSrcInfo.yStride;
}
dst = static_cast<uint8_t*>(surfaceBuffer->GetVirAddr()) + yuvDstInfo.uvOffset;
for (uint32_t i = 0; i < yuvSrcInfo.uvHeight; ++i) {
cond = memcpy_s(dst, dstSize, src, yuvSrcInfo.uvWidth * NUM_2) != EOK;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "CopyYuvPixelMapToSurfaceBuffer UV plane memcpy failed");
dst += yuvDstInfo.uvStride;
dstSize -= yuvDstInfo.uvStride;
src += yuvSrcInfo.uvStride;
}
return true;
}
#endif
void ImageUtils::DumpPixelMap(PixelMap* pixelMap, std::string customFileName, uint64_t imageId)
{
IMAGE_LOGI("ImageUtils::DumpPixelMap start");
std::string fileName = FILE_DIR_IN_THE_SANDBOX + GetLocalTime() + customFileName + std::to_string(imageId) +
GetPixelMapName(pixelMap) + ".dat";
int32_t totalSize = pixelMap->GetRowStride() * pixelMap->GetHeight();
PixelFormat pixelFormat = pixelMap->GetPixelFormat();
if (pixelFormat == PixelFormat::NV12 || pixelFormat == PixelFormat::NV21 ||
pixelFormat == PixelFormat::YCBCR_P010 || pixelFormat == PixelFormat::YCRCB_P010) {
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
if (pixelMap->GetAllocatorType() == AllocatorType::DMA_ALLOC) {
auto sbBuffer = reinterpret_cast<SurfaceBuffer*>(pixelMap->GetFd());
if (!sbBuffer) {
return;
}
totalSize = static_cast<int32_t>(sbBuffer->GetSize());
} else {
totalSize = static_cast<int32_t>(pixelMap->GetCapacity());
}
#else
totalSize = static_cast<int32_t>(pixelMap->GetCapacity());
#endif
IMAGE_LOGI("ImageUtils::DumpPixelMapIfDumpEnabled YUV420 totalSize is %{public}d", totalSize);
}
if (SUCCESS != SaveDataToFile(fileName, reinterpret_cast<const char*>(pixelMap->GetPixels()), totalSize)) {
IMAGE_LOGI("ImageUtils::DumpPixelMap failed");
return;
}
IMAGE_LOGI("ImageUtils::DumpPixelMap success, path = %{public}s", fileName.c_str());
}
void ImageUtils::DumpPixelMapIfDumpEnabled(std::unique_ptr<PixelMap>& pixelMap, uint64_t imageId)
{
if (!ImageSystemProperties::GetDumpImageEnabled()) {
return;
}
if (pixelMap == nullptr) {
IMAGE_LOGI("ImageUtils::DumpPixelMapIfDumpEnabled pixelMap is null");
return;
}
DumpPixelMap(pixelMap.get(), "_imageId", imageId);
}
void ImageUtils::DumpPixelMapIfDumpEnabled(PixelMap& pixelMap, std::string func)
{
if (!ImageSystemProperties::GetDumpImageEnabled()) {
return;
}
DumpPixelMap(&pixelMap, "_imageId_" + func + "_");
}
void ImageUtils::DumpPixelMapBeforeEncode(PixelMap& pixelMap)
{
if (!ImageSystemProperties::GetDumpImageEnabled()) {
return;
}
DumpPixelMap(&pixelMap, "_beforeEncode");
}
void ImageUtils::DumpData(const char* data, const size_t& totalSize,
const std::string& fileSuffix, uint64_t imageId)
{
std::string fileName = FILE_DIR_IN_THE_SANDBOX + GetLocalTime() + "_imageId" + std::to_string(imageId) +
"_data_total" + std::to_string(totalSize) + "." + fileSuffix;
if (SUCCESS != SaveDataToFile(fileName, data, totalSize)) {
IMAGE_LOGI("ImageUtils::DumpData failed");
return;
}
IMAGE_LOGI("ImageUtils::DumpData success, path = %{public}s", fileName.c_str());
}
void ImageUtils::DumpDataIfDumpEnabled(const char* data, const size_t& totalSize,
const std::string& fileSuffix, uint64_t imageId)
{
if (!ImageSystemProperties::GetDumpImageEnabled()) {
return;
}
DumpData(data, totalSize, fileSuffix, imageId);
}
#if !defined(CROSS_PLATFORM)
void ImageUtils::DumpHdrBufferEnabled(sptr<SurfaceBuffer>& buffer, const std::string& fileName)
{
bool cond = !ImageSystemProperties::GetDumpHdrEnabled() || buffer == nullptr;
CHECK_ERROR_RETURN(cond);
uint32_t bufferSize = buffer->GetSize();
std::string fileSuffix = fileName + "-format-" + std::to_string(buffer->GetFormat()) + "-Width-"
+ std::to_string(buffer->GetWidth()) + "-Height-" + std::to_string(buffer->GetHeight()) + "-Stride-"
+ std::to_string(buffer->GetStride()) + ".dat";
std::vector<uint8_t> staticMetadata;
std::vector<uint8_t> dynamicMetadata;
buffer->GetMetadata(HDI::Display::Graphic::Common::V1_0::ATTRKEY_HDR_STATIC_METADATA, staticMetadata);
buffer->GetMetadata(HDI::Display::Graphic::Common::V1_0::ATTRKEY_HDR_DYNAMIC_METADATA, dynamicMetadata);
uint64_t bufferId = buffer->GetBufferId();
DumpData(reinterpret_cast<const char*>(buffer->GetVirAddr()), bufferSize, fileSuffix, bufferId);
DumpData(reinterpret_cast<const char*>(staticMetadata.data()), staticMetadata.size(), fileSuffix, bufferId);
DumpData(reinterpret_cast<const char*>(dynamicMetadata.data()), dynamicMetadata.size(), fileSuffix, bufferId);
}
template <typename T>
static void AppendStringifyPropToStream(int intend, std::stringstream& ss, std::string varName, T arr,
size_t length)
{
ss << std::string(intend, ' ') << varName << "[" << length << "]:";
for (size_t i = 0; i < length; ++i) {
ss << " " << static_cast<double>(arr[i]);
}
ss << "\n";
}
template <typename T>
static void AppendStringifyPropToStream(int intend, std::stringstream& ss, std::string varName, T value)
{
ss << std::string(intend, ' ') << varName << ": " << static_cast<double>(value) << "\n";
}
static void AppendISOMetadataToStream(int intend, std::stringstream& ss, const ISOMetadata& iso)
{
ss << std::string(intend, ' ') << "ISOMetadata" << " {\n";
int nextIntend = intend + 1;
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.writeVersion), iso.writeVersion);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.miniVersion), iso.miniVersion);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.gainmapChannelNum), iso.gainmapChannelNum);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.useBaseColorFlag), iso.useBaseColorFlag);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.baseHeadroom), iso.baseHeadroom);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.alternateHeadroom), iso.alternateHeadroom);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.enhanceClippedThreholdMaxGainmap),
iso.enhanceClippedThreholdMaxGainmap, std::size(iso.enhanceClippedThreholdMaxGainmap));
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.enhanceClippedThreholdMinGainmap),
iso.enhanceClippedThreholdMinGainmap, std::size(iso.enhanceClippedThreholdMaxGainmap));
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.enhanceMappingGamma),
iso.enhanceMappingGamma, std::size(iso.enhanceClippedThreholdMaxGainmap));
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.enhanceMappingBaselineOffset),
iso.enhanceMappingBaselineOffset, std::size(iso.enhanceClippedThreholdMaxGainmap));
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(iso.enhanceMappingAlternateOffset),
iso.enhanceMappingAlternateOffset, std::size(iso.enhanceClippedThreholdMaxGainmap));
ss << std::string(intend, ' ') << "}\n";
}
static void AppendGainmapColorMetadataToStream(int intend, std::stringstream& ss, const GainmapColorMetadata& gcm)
{
ss << std::string(intend, ' ') << "GainmapColorMetadata" << " {\n";
int nextIntend = intend + 1;
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.enhanceDataColorPrimary), gcm.enhanceDataColorPrimary);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.enhanceDataTransFunction),
gcm.enhanceDataTransFunction);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.enhanceDataColorModel), gcm.enhanceDataColorModel);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.combineColorPrimary), gcm.combineColorPrimary);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.combineTransFunction), gcm.combineTransFunction);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.combineColorModel), gcm.combineColorModel);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.alternateColorPrimary), gcm.alternateColorPrimary);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.alternateTransFunction), gcm.alternateTransFunction);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.alternateColorModel), gcm.alternateColorModel);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.enhanceICCSize), gcm.enhanceICCSize);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.enhanceICC), gcm.enhanceICC, gcm.enhanceICC.size());
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.combineMappingFlag), gcm.combineMappingFlag);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.combineMappingSize), gcm.combineMappingSize);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.combineMappingMatrix), gcm.combineMappingMatrix,
std::size(gcm.combineMappingMatrix));
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(gcm.combineMapping), gcm.combineMapping,
gcm.combineMapping.size());
ss << std::string(intend, ' ') << "}\n";
}
static void AppendBaseColorMetadataToStream(int intend, std::stringstream& ss, const BaseColorMetadata& bcm)
{
ss << std::string(intend, ' ') << "BaseColorMetadata" << " {\n";
int nextIntend = intend + 1;
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(bcm.baseColorPrimary), bcm.baseColorPrimary);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(bcm.baseTransFunction), bcm.baseTransFunction);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(bcm.baseColorModel), bcm.baseColorModel);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(bcm.baseIccSize), bcm.baseIccSize);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(bcm.baseICC), bcm.baseICC, bcm.baseICC.size());
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(bcm.baseMappingFlag), bcm.baseMappingFlag);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(bcm.baseMappingSize), bcm.baseMappingSize);
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(bcm.baseMappingMatrix), bcm.baseMappingMatrix,
std::size(bcm.baseMappingMatrix));
AppendStringifyPropToStream(nextIntend, ss, GET_VAR_NAME(bcm.baseMapping), bcm.baseMapping, bcm.baseMapping.size());
ss << std::string(intend, ' ') << "}\n";
}
static std::string StringifyHDRVividExtendMetadata(const HDRVividExtendMetadata& meta)
{
std::stringstream ss;
int intend = 0;
ss << "HDRVividExtendMetadata {\n";
AppendISOMetadataToStream(intend + 1, ss, meta.metaISO);
AppendGainmapColorMetadataToStream(intend + 1, ss, meta.gainmapColorMeta);
AppendBaseColorMetadataToStream(intend + 1, ss, meta.baseColorMeta);
ss << "}\n";
std::string hdrExtendMetadataStr = ss.str();
return hdrExtendMetadataStr;
}
void ImageUtils::DumpHdrExtendMetadataEnabled(sptr<SurfaceBuffer>& buffer, const std::string& fileName)
{
bool cond = !ImageSystemProperties::GetDumpHdrEnabled() || buffer == nullptr;
CHECK_ERROR_RETURN(cond);
std::string fileSuffix = fileName + "-format-" + std::to_string(buffer->GetFormat()) + "-Width-"
+ std::to_string(buffer->GetWidth()) + "-Height-" + std::to_string(buffer->GetHeight()) + "-Stride-"
+ std::to_string(buffer->GetStride()) + ".dat";
std::vector<uint8_t> dynamicMetadata;
buffer->GetMetadata(HDI::Display::Graphic::Common::V1_0::ATTRKEY_HDR_DYNAMIC_METADATA, dynamicMetadata);
HDRVividExtendMetadata extendMetadata = {};
size_t copySize = std::min(sizeof(HDRVividExtendMetadata), dynamicMetadata.size());
int32_t memCpyRes = memcpy_s(&extendMetadata, sizeof(HDRVividExtendMetadata),
dynamicMetadata.data(), copySize);
if (memCpyRes != EOK) {
IMAGE_LOGE("%{public}s memcpy_s extendMetadata fail, error: %{public}d", __func__, memCpyRes);
return;
}
std::string hdrExtendMetadataStr = StringifyHDRVividExtendMetadata(extendMetadata);
DumpData(reinterpret_cast<const char*>(hdrExtendMetadataStr.data()), hdrExtendMetadataStr.size(), fileSuffix,
buffer->GetBufferId());
}
void ImageUtils::DumpSurfaceBufferAllKeysEnabled(sptr<SurfaceBuffer>& buffer, const std::string& fileName)
{
bool cond = !ImageSystemProperties::GetDumpHdrEnabled() || buffer == nullptr;
CHECK_ERROR_RETURN(cond);
std::string filePrefix = fileName + "-format-" + std::to_string(buffer->GetFormat()) + "-Width-"
+ std::to_string(buffer->GetWidth()) + "-Height-" + std::to_string(buffer->GetHeight()) + "-Stride-"
+ std::to_string(buffer->GetStride());
uint64_t bufferId = buffer->GetBufferId();
std::vector<uint8_t> attrInfo{};
std::vector<uint32_t> keys{};
if (buffer->ListMetadataKeys(keys) == GSERROR_OK && !keys.empty()) {
for (size_t i = 0; i < keys.size(); i++) {
if (buffer->GetMetadata(keys[i], attrInfo) == GSERROR_OK && !attrInfo.empty()) {
IMAGE_LOGD("%{public}s dump SurfaceBufferInfo metadata key:%{public}d", __func__, keys[i]);
std::string fileSuffix = filePrefix + "-key-" + std::to_string(keys[i]) + ".dat";
DumpData(reinterpret_cast<const char*>(attrInfo.data()), attrInfo.size(), fileSuffix, bufferId);
}
attrInfo.clear();
}
}
}
ColorManager::ColorSpaceName ImageUtils::SbCMColorSpaceType2ColorSpaceName(
HDI::Display::Graphic::Common::V1_0::CM_ColorSpaceType type)
{
auto iter = CM_COLORSPACE_NAME_MAP.find(type);
CHECK_ERROR_RETURN_RET(iter == CM_COLORSPACE_NAME_MAP.end(), ColorManager::NONE);
return iter->second;
}
static bool IsAlphaFormat(PixelFormat format)
{
return format == PixelFormat::RGBA_8888 || format == PixelFormat::BGRA_8888 ||
format == PixelFormat::RGBA_1010102 || format == PixelFormat::RGBA_F16 ||
format == PixelFormat::ALPHA_F16;
}
PixelFormat ImageUtils::SbFormat2PixelFormat(int32_t sbFormat)
{
auto iter = PIXEL_FORMAT_MAP.find(sbFormat);
if (iter == PIXEL_FORMAT_MAP.end()) {
return PixelFormat::UNKNOWN;
}
return iter->second;
}
int32_t ImageUtils::PixelFormat2GraphicFormat(PixelFormat pixelFormat)
{
auto iter = PIXEL_FORMAT_TO_GRAPHIC_MAP.find(pixelFormat);
if (iter == PIXEL_FORMAT_TO_GRAPHIC_MAP.end()) {
return GRAPHIC_PIXEL_FMT_RGBA_8888;
}
return iter->second;
}
static CM_ColorSpaceType GetCMColorSpaceType(sptr<SurfaceBuffer>& buffer)
{
CHECK_ERROR_RETURN_RET(buffer == nullptr, CM_ColorSpaceType::CM_COLORSPACE_NONE);
CM_ColorSpaceType type;
MetadataHelper::GetColorSpaceType(buffer, type);
return type;
}
static ColorSpace CMColorSpaceType2ColorSpace(CM_ColorSpaceType type)
{
auto iter = CM_COLORSPACE_MAP.find(type);
CHECK_ERROR_RETURN_RET(iter == CM_COLORSPACE_MAP.end(), ColorSpace::UNKNOWN);
return iter->second;
}
#ifdef IMAGE_COLORSPACE_FLAG
static ColorManager::ColorSpaceName CMColorSpaceType2ColorSpaceName(CM_ColorSpaceType type)
{
auto iter = CM_COLORSPACE_NAME_MAP.find(type);
CHECK_ERROR_RETURN_RET(iter == CM_COLORSPACE_NAME_MAP.end(), ColorManager::NONE);
return iter->second;
}
#endif
static ImageInfo MakeImageInfo(int width, int height, PixelFormat pf, AlphaType at, ColorSpace cs)
{
ImageInfo info;
info.size.width = width;
info.size.height = height;
info.pixelFormat = pf;
info.alphaType = at;
info.colorSpace = cs;
return info;
}
void ImageUtils::GetYuvInfoFromNonDmaBuffer(int32_t width, int32_t height, PixelFormat format, YUVDataInfo &yuvInfo)
{
yuvInfo.imageSize.width = width;
yuvInfo.imageSize.height = height;
yuvInfo.yWidth = static_cast<uint32_t>(width);
yuvInfo.yHeight = static_cast<uint32_t>(height);
yuvInfo.yStride = static_cast<uint32_t>(width);
if (format != PixelFormat::Y8) {
yuvInfo.uvWidth = static_cast<uint32_t>((width + 1) / NUM_2);
yuvInfo.uvHeight = static_cast<uint32_t>((height + 1) / NUM_2);
yuvInfo.uvStride = static_cast<uint32_t>(((width + 1) / NUM_2) * NUM_2);
yuvInfo.uvOffset = static_cast<uint32_t>(width) * static_cast<uint32_t>(height);
}
}
bool ImageUtils::GetYuvInfoFromDmaBuffer(sptr<SurfaceBuffer> surfaceBuffer, YUVDataInfo &yuvInfo)
{
bool cond = surfaceBuffer == nullptr;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "%{public}s, surfaceBuffer is nullptr", __func__);
OH_NativeBuffer_Planes* planes = nullptr;
GSError retVal = surfaceBuffer->GetPlanesInfo(reinterpret_cast<void**>(&planes));
cond = retVal != OHOS::GSERROR_OK || planes == nullptr || planes->planeCount <= NUM_1;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "%{public}s, get planesInfo failed, retVal:%{public}d", __func__, retVal);
int32_t width = surfaceBuffer->GetWidth();
int32_t height = surfaceBuffer->GetHeight();
yuvInfo.imageSize = { width, height };
yuvInfo.yWidth = static_cast<uint32_t>(width);
yuvInfo.uvWidth = static_cast<uint32_t>((width + NUM_1) / NUM_2);
yuvInfo.yHeight = static_cast<uint32_t>(height);
yuvInfo.uvHeight = static_cast<uint32_t>((height + NUM_1) / NUM_2);
if (planes->planeCount >= NUM_2) {
int32_t pixelFmt = surfaceBuffer->GetFormat();
bool isYuvP010 = (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010 || pixelFmt == GRAPHIC_PIXEL_FMT_YCRCB_P010);
int uvPlaneIndex = (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_420_SP ||
pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010) ? NUM_1 : NUM_2;
yuvInfo.yStride = isYuvP010 ?
(planes->planes[NUM_0].columnStride / NUM_2) : (planes->planes[NUM_0].columnStride);
yuvInfo.uvStride = isYuvP010 ?
(planes->planes[uvPlaneIndex].columnStride / NUM_2) : (planes->planes[uvPlaneIndex].columnStride);
yuvInfo.yOffset = isYuvP010 ?
(planes->planes[NUM_0].offset / NUM_2) : (planes->planes[NUM_0].offset);
yuvInfo.uvOffset = isYuvP010 ?
(planes->planes[uvPlaneIndex].offset / NUM_2) : (planes->planes[uvPlaneIndex].offset);
return true;
}
return false;
}
void ImageUtils::UpdateYUVDataInfo(PixelMap &pixelMap)
{
PixelFormat format = pixelMap.GetPixelFormat();
if (!IsYuvFormat(format)) {
return;
}
YUVDataInfo info;
if (pixelMap.GetAllocatorType() == AllocatorType::DMA_ALLOC && pixelMap.GetFd() != nullptr) {
SurfaceBuffer *surfaceBuffer = reinterpret_cast<SurfaceBuffer *>(pixelMap.GetFd());
GetYuvInfoFromDmaBuffer(surfaceBuffer, info);
} else {
GetYuvInfoFromNonDmaBuffer(pixelMap.GetWidth(), pixelMap.GetHeight(), pixelMap.GetPixelFormat(), info);
}
pixelMap.SetImageYUVInfo(info);
}
void ImageUtils::UpdateYUVDataInfo(std::unique_ptr<PixelMap> &pixelMap)
{
if (pixelMap == nullptr) {
IMAGE_LOGE("%{public}s pixelMap is nullptr", __func__);
return;
}
UpdateYUVDataInfo(*pixelMap);
}
void ImageUtils::SetYuvDataInfo(std::unique_ptr<PixelMap> &pixelMap, sptr<OHOS::SurfaceBuffer> &sBuffer)
{
bool cond = pixelMap == nullptr || sBuffer == nullptr;
CHECK_ERROR_RETURN(cond);
int32_t width = sBuffer->GetWidth();
int32_t height = sBuffer->GetHeight();
OH_NativeBuffer_Planes *planes = nullptr;
GSError retVal = sBuffer->GetPlanesInfo(reinterpret_cast<void**>(&planes));
YUVDataInfo info;
info.imageSize = { width, height };
cond = retVal != OHOS::GSERROR_OK || planes == nullptr || planes->planeCount <= NUM_1;
CHECK_ERROR_RETURN_LOG(cond, "Get planesInfo failed, retVal:%{public}d", retVal);
info.yWidth = static_cast<uint32_t>(width);
info.uvWidth = static_cast<uint32_t>(width / NUM_2);
info.yHeight = static_cast<uint32_t>(height);
info.uvHeight = static_cast<uint32_t>(height / NUM_2);
if (planes->planeCount >= NUM_2) {
int32_t pixelFmt = sBuffer->GetFormat();
bool isYuvP010 = (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010 || pixelFmt == GRAPHIC_PIXEL_FMT_YCRCB_P010);
int uvPlaneOffset = (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_420_SP ||
pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010) ? NUM_1 : NUM_2;
info.yStride = isYuvP010 ? (planes->planes[NUM_0].columnStride / NUM_2) : (planes->planes[NUM_0].columnStride);
info.uvStride = isYuvP010 ? (planes->planes[uvPlaneOffset].columnStride / NUM_2) :
(planes->planes[uvPlaneOffset].columnStride);
info.yOffset = isYuvP010 ? (planes->planes[NUM_0].offset / NUM_2) : (planes->planes[NUM_0].offset);
info.uvOffset =
isYuvP010 ? (planes->planes[uvPlaneOffset].offset / NUM_2) : (planes->planes[uvPlaneOffset].offset);
}
pixelMap->SetImageYUVInfo(info);
}
bool ImageUtils::SurfaceBuffer2PixelMap(sptr<OHOS::SurfaceBuffer> &surfaceBuffer, std::unique_ptr<PixelMap> &Pixelmap)
{
if (surfaceBuffer == nullptr || Pixelmap == nullptr) {
return false;
}
PixelFormat pixelFormat = ImageUtils::SbFormat2PixelFormat(surfaceBuffer->GetFormat());
ColorSpace colorSpace = CMColorSpaceType2ColorSpace(GetCMColorSpaceType(surfaceBuffer));
AlphaType alphaType = IsAlphaFormat(pixelFormat) ?
AlphaType::IMAGE_ALPHA_TYPE_PREMUL : AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
void* nativeBuffer = surfaceBuffer.GetRefPtr();
int32_t err = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
CHECK_ERROR_RETURN_RET_LOG(err != OHOS::GSERROR_OK, false, "NativeBufferReference failed");
ImageInfo imageInfo = MakeImageInfo(surfaceBuffer->GetWidth(),
surfaceBuffer->GetHeight(), pixelFormat, alphaType, colorSpace);
Pixelmap->SetImageInfo(imageInfo, true);
Pixelmap->SetPixelsAddr(surfaceBuffer->GetVirAddr(),
nativeBuffer, Pixelmap->GetRowBytes() * Pixelmap->GetHeight(),
AllocatorType::DMA_ALLOC, nullptr);
#ifdef IMAGE_COLORSPACE_FLAG
ColorManager::ColorSpaceName colorSpaceName =
CMColorSpaceType2ColorSpaceName(GetCMColorSpaceType(surfaceBuffer));
Pixelmap->InnerSetColorSpace(ColorManager::ColorSpace(colorSpaceName));
#endif
if (ImageUtils::IsYuvFormat(pixelFormat)) {
SetYuvDataInfo(Pixelmap, surfaceBuffer);
}
return true;
}
#endif
uint64_t ImageUtils::GetNowTimeMilliSeconds()
{
auto now = std::chrono::system_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
}
uint64_t ImageUtils::GetNowTimeMicroSeconds()
{
auto now = std::chrono::system_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
}
std::string ImageUtils::GetCurrentProcessName()
{
std::string processName;
std::ifstream cmdlineFile("/proc/self/cmdline");
if (cmdlineFile.is_open()) {
std::ostringstream oss;
oss << cmdlineFile.rdbuf();
cmdlineFile.close();
std::string cmdline = oss.str();
size_t pos = cmdline.find_first_of('\0');
if (pos != std::string::npos) {
processName = cmdline.substr(0, pos);
}
}
return processName;
}
bool ImageUtils::SetInitializationOptionAutoMem(InitializationOptions &option)
{
if (option.pixelFormat == PixelFormat::RGBA_1010102||
option.pixelFormat == PixelFormat::YCBCR_P010||
option.pixelFormat == PixelFormat::YCRCB_P010) {
option.allocatorType = AllocatorType::DMA_ALLOC;
option.useDMA = true;
return true;
}
if (option.size.width * option.size.height >= DMA_SIZE) {
if (SetInitializationOptionDmaMem(option)) {
return true;
}
}
option.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
option.useDMA = false;
return true;
}
bool ImageUtils::SetInitializationOptionDmaMem(InitializationOptions &option)
{
switch (option.pixelFormat) {
case PixelFormat::RGB_565:
case PixelFormat::ALPHA_F16:
case PixelFormat::RGBA_8888:
case PixelFormat::BGRA_8888:
case PixelFormat::RGBA_F16:
case PixelFormat::RGBA_1010102:
case PixelFormat::YCBCR_P010:
case PixelFormat::YCRCB_P010:
option.allocatorType = AllocatorType::DMA_ALLOC;
option.useDMA = true;
return true;
default:
IMAGE_LOGE("pixelFormat (%{public}d) does not support DMA", option.pixelFormat);
return false;
}
return false;
}
bool ImageUtils::SetInitializationOptionAllocatorType(InitializationOptions &option, int32_t allocatorType)
{
if (allocatorType > NUM_2 || allocatorType < 0) {
IMAGE_LOGE("allocatorType is invalid");
return false;
}
switch (allocatorType) {
case MEM_DMA:
return SetInitializationOptionDmaMem(option);
case MEM_SHARE:
if (option.pixelFormat == PixelFormat::RGBA_1010102 ||
option.pixelFormat == PixelFormat::YCBCR_P010 ||
option.pixelFormat == PixelFormat::YCRCB_P010) {
IMAGE_LOGE("pixelFormat is unsupported: %{public}d", option.pixelFormat);
return false;
}
option.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
option.useDMA = false;
return true;
default:
return SetInitializationOptionAutoMem(option);
}
return true;
}
uint32_t ImageUtils::SaveDataToFile(const std::string& fileName, const char* data, const size_t& totalSize)
{
std::ofstream outFile(fileName, std::ofstream::out);
if (!outFile.is_open()) {
IMAGE_LOGI("ImageUtils::SaveDataToFile write error, path=%{public}s", fileName.c_str());
return IMAGE_RESULT_SAVE_DATA_TO_FILE_FAILED;
}
if (data == nullptr) {
IMAGE_LOGE("ImageUtils::SaveDataToFile data is nullptr");
return IMAGE_RESULT_SAVE_DATA_TO_FILE_FAILED;
}
outFile.write(data, totalSize);
return SUCCESS;
}
std::string ImageUtils::GetLocalTime()
{
auto now = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
std::time_t t = std::chrono::system_clock::to_time_t(now);
std::tm* tm = std::localtime(&t);
if (tm == nullptr) {
IMAGE_LOGE("ImageUtils::GetLocalTime error, returned nullptr");
return "";
}
std::stringstream ss;
int millSecondWidth = 3;
ss << std::put_time(tm, "%Y-%m-%d %H_%M_%S.") << std::setfill('0') << std::setw(millSecondWidth) << ms.count();
return ss.str();
}
std::string ImageUtils::GetPixelMapName(PixelMap* pixelMap)
{
if (!pixelMap) {
IMAGE_LOGE("ImageUtils::GetPixelMapName error, pixelMap is null");
return "";
}
#ifdef IOS_PLATFORM
std::string pixelMapStr = "_pixelMap_w" + std::to_string(pixelMap->GetWidth()) +
"_h" + std::to_string(pixelMap->GetHeight()) +
"_rowStride" + std::to_string(pixelMap->GetRowStride()) +
"_pixelFormat" + std::to_string((int32_t)pixelMap->GetPixelFormat()) +
"_total" + std::to_string(pixelMap->GetRowStride() * pixelMap->GetHeight()) +
"_pid" + std::to_string(getpid()) +
"_tid" + std::to_string(syscall(SYS_thread_selfid)) +
"_uniqueId" + std::to_string(pixelMap->GetUniqueId());
#else
std::string yuvInfoStr = "";
if (pixelMap->GetPixelFormat() == PixelFormat::NV12 || pixelMap->GetPixelFormat() == PixelFormat::NV21) {
YUVDataInfo yuvInfo;
pixelMap->GetImageYUVInfo(yuvInfo);
yuvInfoStr += "_yWidth" + std::to_string(yuvInfo.yWidth) +
"_yHeight" + std::to_string(yuvInfo.yHeight) +
"_yStride" + std::to_string(yuvInfo.yStride) +
"_yOffset" + std::to_string(yuvInfo.yOffset) +
"_uvWidth" + std::to_string(yuvInfo.uvWidth) +
"_uvHeight" + std::to_string(yuvInfo.uvHeight) +
"_uvStride" + std::to_string(yuvInfo.uvStride) +
"_uvOffset" + std::to_string(yuvInfo.uvOffset);
}
std::string pixelMapStr = "_pixelMap_w" + std::to_string(pixelMap->GetWidth()) +
"_h" + std::to_string(pixelMap->GetHeight()) +
"_rowStride" + std::to_string(pixelMap->GetRowStride()) +
"_pixelFormat" + std::to_string((int32_t)pixelMap->GetPixelFormat()) +
"_total" + std::to_string(pixelMap->GetRowStride() * pixelMap->GetHeight()) +
"_pid" + std::to_string(getpid()) +
"_tid" + std::to_string(gettid()) +
"_uniqueId" + std::to_string(pixelMap->GetUniqueId());
#endif
return pixelMapStr;
}
uint8_t ImageUtils::BytesToUint8(uint8_t* bytes, uint32_t& offset, uint32_t size)
{
uint8_t data = 0;
if (bytes == nullptr || offset >= size || offset + NUM_1 > size) {
return data;
}
data = bytes[offset];
offset += NUM_1;
return data;
}
uint8_t ImageUtils::BytesToUint8(const uint8_t* bytes, uint32_t& offset, uint32_t size)
{
uint8_t data = 0;
if (bytes == nullptr || offset >= size || offset + NUM_1 > size) {
return data;
}
data = bytes[offset];
offset += NUM_1;
return data;
}
uint16_t ImageUtils::BytesToUint16(uint8_t* bytes, uint32_t& offset, uint32_t size, bool isBigEndian)
{
uint16_t data = 0;
if (offset > UINT32_MAX - NUM_2) {
return data;
}
if (bytes == nullptr || offset + NUM_2 > size) {
return data;
}
if (isBigEndian) {
data = (bytes[offset] << MOVE_BITS_8) | bytes[offset + NUM_1];
} else {
data = (bytes[offset + NUM_1] << MOVE_BITS_8) | bytes[offset];
}
offset += NUM_2;
return data;
}
uint32_t ImageUtils::BytesToUint32(uint8_t* bytes, uint32_t& offset, uint32_t size, bool isBigEndian)
{
uint32_t data = 0;
if (offset > UINT32_MAX - NUM_4) {
return data;
}
if (bytes == nullptr || offset + NUM_4 > size) {
return data;
}
if (isBigEndian) {
data = (bytes[offset] << MOVE_BITS_24) | (bytes[offset + NUM_1] << MOVE_BITS_16) |
(bytes[offset + NUM_2] << MOVE_BITS_8) | (bytes[offset + NUM_3]);
} else {
data = (bytes[offset + NUM_3] << MOVE_BITS_24) | (bytes[offset + NUM_2] << MOVE_BITS_16) |
(bytes[offset + NUM_1] << MOVE_BITS_8) | bytes[offset];
}
offset += NUM_4;
return data;
}
int32_t ImageUtils::BytesToInt32(uint8_t* bytes, uint32_t& offset, uint32_t size, bool isBigEndian)
{
int32_t data = 0;
if (offset > UINT32_MAX - NUM_4) {
return data;
}
if (bytes == nullptr || offset + NUM_4 > size) {
return data;
}
if (isBigEndian) {
data = (bytes[offset] << MOVE_BITS_24) | (bytes[offset + NUM_1] << MOVE_BITS_16) |
(bytes[offset + NUM_2] << MOVE_BITS_8) | (bytes[offset + NUM_3]);
} else {
data = (bytes[offset + NUM_3] << MOVE_BITS_24) | (bytes[offset + NUM_2] << MOVE_BITS_16) |
(bytes[offset + NUM_1] << MOVE_BITS_8) | bytes[offset];
}
offset += NUM_4;
return data;
}
float ImageUtils::BytesToFloat(uint8_t* bytes, uint32_t& offset, uint32_t size, bool isBigEndian)
{
uint32_t data = BytesToUint32(bytes, offset, size, isBigEndian);
union {
uint32_t i;
float f;
} u;
u.i = data;
return u.f;
}
void ImageUtils::Uint16ToBytes(uint16_t data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)
{
uint8_t BYTE_ONE = (data >> MOVE_BITS_8) & 0xFF;
uint8_t BYTE_TWO = data & 0xFF;
if (isBigEndian) {
bytes[offset++] = BYTE_ONE;
bytes[offset++] = BYTE_TWO;
} else {
bytes[offset++] = BYTE_TWO;
bytes[offset++] = BYTE_ONE;
}
}
void ImageUtils::Uint32ToBytes(uint32_t data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)
{
uint8_t BYTE_ONE = (data >> MOVE_BITS_24) & 0xFF;
uint8_t BYTE_TWO = (data >> MOVE_BITS_16) & 0xFF;
uint8_t BYTE_THREE = (data >> MOVE_BITS_8) & 0xFF;
uint8_t BYTE_FOUR = data & 0xFF;
if (isBigEndian) {
bytes[offset++] = BYTE_ONE;
bytes[offset++] = BYTE_TWO;
bytes[offset++] = BYTE_THREE;
bytes[offset++] = BYTE_FOUR;
} else {
bytes[offset++] = BYTE_FOUR;
bytes[offset++] = BYTE_THREE;
bytes[offset++] = BYTE_TWO;
bytes[offset++] = BYTE_ONE;
}
}
void ImageUtils::FloatToBytes(float data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)
{
union {
uint32_t i;
float f;
} u;
u.f = data;
Uint32ToBytes(u.i, bytes, offset, isBigEndian);
}
void ImageUtils::Int32ToBytes(int32_t data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)
{
union {
uint32_t uit;
int32_t it;
} u;
u.it = data;
Uint32ToBytes(u.uit, bytes, offset, isBigEndian);
}
void ImageUtils::ArrayToBytes(const uint8_t* data, uint32_t length, vector<uint8_t>& bytes, uint32_t& offset)
{
for (uint32_t i = 0; i < length; i++) {
bytes[offset++] = data[i] & 0xFF;
}
}
#if !defined(CROSS_PLATFORM)
void ImageUtils::FlushSurfaceBuffer(sptr<SurfaceBuffer>& surfaceBuffer)
{
if (surfaceBuffer && (surfaceBuffer->GetUsage() & BUFFER_USAGE_MEM_MMZ_CACHE)) {
GSError err = surfaceBuffer->FlushCache();
bool cond = err != GSERROR_OK;
CHECK_ERROR_PRINT_LOG(cond, "ImageUtils FlushCache failed, GSError=%{public}d", err);
}
}
#endif
void ImageUtils::FlushSurfaceBuffer(PixelMap* pixelMap)
{
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
if (!pixelMap || pixelMap->GetAllocatorType() != AllocatorType::DMA_ALLOC) {
return;
}
SurfaceBuffer* surfaceBuffer = static_cast<SurfaceBuffer*>(pixelMap->GetFd());
if (surfaceBuffer && (surfaceBuffer->GetUsage() & BUFFER_USAGE_MEM_MMZ_CACHE)) {
GSError err = surfaceBuffer->Map();
if (err != GSERROR_OK) {
IMAGE_LOGE("ImageUtils Map failed, GSError=%{public}d", err);
return;
}
err = surfaceBuffer->FlushCache();
if (err != GSERROR_OK) {
IMAGE_LOGE("ImageUtils FlushCache failed, GSError=%{public}d", err);
}
}
#else
return;
#endif
}
void ImageUtils::FlushContextSurfaceBuffer(ImagePlugin::DecodeContext& context)
{
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
if (context.pixelsBuffer.context == nullptr || context.allocatorType != AllocatorType::DMA_ALLOC) {
return;
}
SurfaceBuffer* surfaceBuffer = static_cast<SurfaceBuffer*>(context.pixelsBuffer.context);
if (surfaceBuffer && (surfaceBuffer->GetUsage() & BUFFER_USAGE_MEM_MMZ_CACHE)) {
GSError err = surfaceBuffer->Map();
if (err != GSERROR_OK) {
IMAGE_LOGE("ImageUtils Map failed, GSError=%{public}d", err);
return;
}
err = surfaceBuffer->FlushCache();
if (err != GSERROR_OK) {
IMAGE_LOGE("ImageUtils FlushCache failed, GSError=%{public}d", err);
}
}
#else
return;
#endif
}
void ImageUtils::InvalidateContextSurfaceBuffer(ImagePlugin::DecodeContext& context)
{
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
bool cond = context.pixelsBuffer.context == nullptr || context.allocatorType != AllocatorType::DMA_ALLOC;
CHECK_ERROR_RETURN(cond);
SurfaceBuffer* surfaceBuffer = static_cast<SurfaceBuffer*>(context.pixelsBuffer.context);
if (surfaceBuffer && (surfaceBuffer->GetUsage() & BUFFER_USAGE_MEM_MMZ_CACHE)) {
GSError err = surfaceBuffer->InvalidateCache();
cond = err != GSERROR_OK;
CHECK_ERROR_PRINT_LOG(cond, "ImageUtils FlushCache failed, GSError=%{public}d", err);
}
#else
return;
#endif
}
bool ImageUtils::IsAuxiliaryPictureTypeSupported(AuxiliaryPictureType type)
{
auto auxTypes = GetAllAuxiliaryPictureType();
return (auxTypes.find(type) != auxTypes.end());
}
bool ImageUtils::IsAuxiliaryPictureEncoded(AuxiliaryPictureType type)
{
return AuxiliaryPictureType::GAINMAP == type || AuxiliaryPictureType::UNREFOCUS_MAP == type ||
AuxiliaryPictureType::FRAGMENT_MAP == type || AuxiliaryPictureType::SNAP_MAP == type ||
AuxiliaryPictureType::SNAP_GAINMAP == type || AuxiliaryPictureType::PAN_MAP== type ||
AuxiliaryPictureType::PAN_GAINMAP == type || AuxiliaryPictureType::LHDR_GAINMAP == type;
}
bool ImageUtils::IsMetadataTypeSupported(MetadataType metadataType)
{
auto metaTypes = GetAllMetadataType();
return (metaTypes.find(metadataType) != metaTypes.end());
}
bool ImageUtils::isBlobMetadataType(MetadataType type)
{
for (const auto& iter: BLOB_METADATA_TAG_MAP) {
if (iter.first == type) {
return true;
}
}
return false;
}
const std::set<AuxiliaryPictureType> &ImageUtils::GetAllAuxiliaryPictureType()
{
static const std::set<AuxiliaryPictureType> auxTypes = {
AuxiliaryPictureType::GAINMAP,
AuxiliaryPictureType::DEPTH_MAP,
AuxiliaryPictureType::UNREFOCUS_MAP,
AuxiliaryPictureType::LINEAR_MAP,
AuxiliaryPictureType::FRAGMENT_MAP,
AuxiliaryPictureType::SNAP_MAP,
AuxiliaryPictureType::SNAP_GAINMAP,
AuxiliaryPictureType::PAN_MAP,
AuxiliaryPictureType::PAN_GAINMAP,
AuxiliaryPictureType::LHDR_GAINMAP,
};
return auxTypes;
}
const std::set<MetadataType> &ImageUtils::GetAllMetadataType()
{
static const std::set<MetadataType> metadataTypes = {
MetadataType::EXIF,
MetadataType::FRAGMENT,
MetadataType::XTSTYLE,
MetadataType::RFDATAB,
MetadataType::GIF,
MetadataType::STDATA,
MetadataType::RESMAP,
MetadataType::XDRAW4K,
MetadataType::PRIVATE,
MetadataType::RFDATAN,
MetadataType::RFDATAS,
MetadataType::HDRSNAP,
MetadataType::DFXDATA,
MetadataType::HEIFS,
MetadataType::DNG,
MetadataType::WEBP,
MetadataType::HW_MAKER_NOTE,
MetadataType::AVIS,
MetadataType::JFIF,
MetadataType::XMP,
MetadataType::PNG,
MetadataType::TIFF,
};
return metadataTypes;
}
static inline bool IsSizeValid(const Size &size)
{
return (size.width > NUM_0 && size.height > NUM_0);
}
uint32_t ImageUtils::GetThumbnailScaleTargetSize(const Size &sourceSize, const int32_t &maxPixelSize, Size &dstSize,
float &scale)
{
bool cond = (maxPixelSize <= 0);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_INVALID_PARAMETER, "%{public}s: invalid maxPixelSize: %{public}d",
__func__, maxPixelSize);
cond = !IsSizeValid(sourceSize);
const auto [originalWidth, originalHeight] = sourceSize;
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_DATA_ABNORMAL, "%{public}s: source size is invalid,"
"size: (%{public}d,%{public}d)", __func__, originalWidth, originalHeight);
Calculate the scaling factor: take the smaller value of (maxPixelSize / original width) and
(maxPixelSize / original height), and ensure it does not exceed 1 (only shrinking without enlarging)
*/
float scaleX = static_cast<float>(maxPixelSize) / originalWidth;
float scaleY = static_cast<float>(maxPixelSize) / originalHeight;
scale = std::min({scaleX, scaleY, 1.0f});
if (ImageUtils::FloatCompareZero(1.0f - scale)) {
dstSize.width = originalWidth;
dstSize.height = originalHeight;
return SUCCESS;
}
cond = ImageUtils::CheckFloatMulOverflow(originalWidth, scale);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_INVALID_PARAMETER, "%{public}s: originalWidth * scale overflow",
__func__);
cond = ImageUtils::CheckFloatMulOverflow(originalHeight, scale);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_INVALID_PARAMETER, "%{public}s: originalHeight * scale overflow",
__func__);
float scaledWidth = std::round(originalWidth * scale);
float scaledHeight = std::round(originalHeight * scale);
cond = ImageUtils::CheckFloatToInt32Overflow(scaledWidth);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_INVALID_PARAMETER, "%{public}s: scaledWidth overflow int32_t",
__func__);
cond = ImageUtils::CheckFloatToInt32Overflow(scaledHeight);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_INVALID_PARAMETER, "%{public}s: scaledHeight overflow int32_t",
__func__);
dstSize.width = static_cast<int32_t>(scaledWidth);
dstSize.height = static_cast<int32_t>(scaledHeight);
cond = (dstSize.width == 0 || dstSize.height == 0);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_INVALID_PARAMETER,
"%{public}s: scaled size has zero dimension: (%{public}d,%{public}d)", __func__, dstSize.width, dstSize.height);
return SUCCESS;
}
uint32_t ImageUtils::ScaleThumbnailWithAspectRatio(std::unique_ptr<PixelMap> &pixelMap, const int32_t &maxPixelSize)
{
bool cond = (pixelMap == nullptr);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_DATA_ABNORMAL, "%{public}s: pixelMap is nullptr!", __func__);
ImageInfo imageInfo;
pixelMap->GetImageInfo(imageInfo);
Size &scaledSize = imageInfo.size;
Size dstSize;
float scale = 1.0f;
uint32_t ret = GetThumbnailScaleTargetSize(scaledSize, maxPixelSize, dstSize, scale);
CHECK_ERROR_RETURN_RET_LOG(ret != SUCCESS, ret, "%{public}s: get thumbnail scale target size failed", __func__);
if (dstSize.width == scaledSize.width && dstSize.height == scaledSize.height) {
IMAGE_LOGI("%{public}s: no need to scale, originalSize:(%{public}d,%{public}d)",
__func__, scaledSize.width, scaledSize.height);
return SUCCESS;
}
pixelMap->scale(scale, scale, AntiAliasingOption::HIGH);
pixelMap->GetImageInfo(imageInfo);
IMAGE_LOGI("%{public}s: maxPixelSize: %{public}d, scaledSize: (%{public}d,%{public}d)",
__func__, maxPixelSize, scaledSize.width, scaledSize.height);
return SUCCESS;
}
size_t ImageUtils::GetAstcBytesCount(const ImageInfo& imageInfo)
{
size_t astcBytesCount = 0;
uint32_t blockWidth = 0;
uint32_t blockHeight = 0;
switch (imageInfo.pixelFormat) {
case PixelFormat::ASTC_4x4:
blockWidth = ASTC_4X4_BLOCK;
blockHeight = ASTC_4X4_BLOCK;
break;
case PixelFormat::ASTC_6x6:
blockWidth = ASTC_6X6_BLOCK;
blockHeight = ASTC_6X6_BLOCK;
break;
case PixelFormat::ASTC_8x8:
blockWidth = ASTC_8X8_BLOCK;
blockHeight = ASTC_8X8_BLOCK;
break;
default:
IMAGE_LOGE("ImageUtils GetAstcBytesCount failed, format is not supported %{public}d",
imageInfo.pixelFormat);
return 0;
}
if ((blockWidth >= ASTC_4X4_BLOCK) && (blockHeight >= ASTC_4X4_BLOCK)) {
uint64_t blocksX = (static_cast<uint64_t>(imageInfo.size.width) + blockWidth - 1) / blockWidth;
uint64_t blocksY = (static_cast<uint64_t>(imageInfo.size.height) + blockHeight - 1) / blockHeight;
uint64_t totalSize = blocksX * blocksY * ASTC_BLOCK_SIZE + ASTC_HEADER_SIZE;
if (totalSize > INT32_MAX) {
IMAGE_LOGE("ImageUtils GetAstcBytesCount overflow, width:%{public}d, height:%{public}d",
imageInfo.size.width, imageInfo.size.height);
return 0;
}
astcBytesCount = static_cast<size_t>(totalSize);
}
return astcBytesCount;
}
bool ImageUtils::StrToUint32(const std::string& str, uint32_t& value)
{
if (str.empty() || !isdigit(str.front())) {
return false;
}
char* end = nullptr;
errno = 0;
auto addr = str.c_str();
auto result = strtoul(addr, &end, 10);
if ((end == addr) || (end[0] != '\0') || (errno == ERANGE) ||
(result > UINT32_MAX)) {
return false;
}
value = static_cast<uint32_t>(result);
return true;
}
bool ImageUtils::IsInRange(uint32_t value, uint32_t minValue, uint32_t maxValue)
{
return (value >= minValue) && (value <= maxValue);
}
bool ImageUtils::IsInRange(int32_t value, int32_t minValue, int32_t maxValue)
{
return (value >= minValue) && (value <= maxValue);
}
bool ImageUtils::IsEven(int32_t value)
{
return value % BASE_EVEN_DIVISOR == 0;
}
bool ImageUtils::HasOverflowed(uint32_t num1, uint32_t num2)
{
return num1 > std::numeric_limits<uint32_t>::max() - num2;
}
bool ImageUtils::HasOverflowed64(uint64_t num1, uint64_t num2)
{
return num1 > std::numeric_limits<uint64_t>::max() - num2;
}
std::string ImageUtils::GetEncodedHeifFormat()
{
if (GetAPIVersion() > APIVERSION_13) {
return "image/heic";
} else {
return "image/heif";
}
}
std::string ImageUtils::GetEncodedHeifsFormat()
{
return "image/heif-sequence";
}
int32_t ImageUtils::GetAPIVersion()
{
#if !defined(CROSS_PLATFORM)
static std::atomic<int32_t> apiVersion = GetAPIVersionInner();
if (apiVersion.load() <= 0) {
apiVersion.store(GetAPIVersionInner());
}
return apiVersion.load();
#else
return FAULT_API_VERSION;
#endif
}
int32_t ImageUtils::GetAPIVersionInner()
{
#if !defined(CROSS_PLATFORM)
uint32_t targetVersion = 0;
auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (samgr == nullptr) {
IMAGE_LOGE("Get ability manager failed");
return FAULT_API_VERSION;
}
sptr<IRemoteObject> object = samgr->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
if (object == nullptr) {
IMAGE_LOGE("Object is NULL");
return FAULT_API_VERSION;
}
sptr<OHOS::AppExecFwk::IBundleMgr> bms = iface_cast<OHOS::AppExecFwk::IBundleMgr>(object);
if (bms == nullptr) {
IMAGE_LOGE("Bundle manager service is NULL.");
return FAULT_API_VERSION;
}
AppExecFwk::BundleInfo bundleInfo;
if (bms->GetBundleInfoForSelf(0, bundleInfo) != ERR_OK) {
IMAGE_LOGE("Get bundle info for self failed");
return FAULT_API_VERSION;
}
targetVersion = bundleInfo.targetVersion;
int32_t apiVersionResult = static_cast<int32_t>(targetVersion % 100);
return apiVersionResult;
#else
return FAULT_API_VERSION;
#endif
}
void ImageUtils::UpdateSdrYuvStrides(const ImageInfo &imageInfo, YUVStrideInfo &dstStrides,
void *context, AllocatorType dstType)
{
int32_t dstWidth = imageInfo.size.width;
int32_t dstHeight = imageInfo.size.height;
int32_t dstYStride = dstWidth;
int32_t dstUvStride = (dstWidth + 1) / NUM_2 * NUM_2;
int32_t dstYOffset = 0;
int32_t dstUvOffset = dstYStride * dstHeight;
dstStrides = {dstYStride, dstUvStride, dstYOffset, dstUvOffset};
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
if (context == nullptr) {
return;
}
if (dstType == AllocatorType::DMA_ALLOC) {
auto sb = static_cast<SurfaceBuffer*>(context);
if (sb == nullptr) {
IMAGE_LOGE("get SurfaceBuffer failed");
return;
}
GetYUVStrideInfo(sb, dstStrides);
}
#endif
}
uint16_t ImageUtils::GetReusePixelRefCount(const std::shared_ptr<PixelMap> &reusePixelmap)
{
#if !defined(CROSS_PLATFORM)
if (reusePixelmap->GetAllocatorType() != AllocatorType::DMA_ALLOC) {
return 0;
}
void* sbBuffer = reusePixelmap->GetFd();
if (sbBuffer != nullptr) {
OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(sbBuffer);
uint16_t reusePixelRefCount = static_cast<uint16_t>(ref->GetSptrRefCount());
return reusePixelRefCount;
}
return 0;
#else
return 0;
#endif
}
bool ImageUtils::CanReusePixelMap(ImagePlugin::DecodeContext& context, int width,
int height, const std::shared_ptr<PixelMap> &reusePixelmap)
{
if (reusePixelmap == nullptr) {
IMAGE_LOGD("reusePixelmap is nullptr");
return false;
}
bool cond = GetReusePixelRefCount(reusePixelmap) != 1;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "reusePixelmap reference count is not equal to 1");
cond = ((width != reusePixelmap->GetWidth()) || (height != reusePixelmap->GetHeight()));
CHECK_ERROR_RETURN_RET_LOG(cond, false, "The height or width of image is not equal to reusePixelmap");
cond = ((reusePixelmap->GetAllocatorType() != AllocatorType::DMA_ALLOC) ||
(context.allocatorType != AllocatorType::DMA_ALLOC));
CHECK_ERROR_RETURN_RET_LOG(cond, false, "Image allocatortype is not DMA");
return true;
}
bool ImageUtils::CanReusePixelMapHdr(ImagePlugin::DecodeContext& context, int width,
int height, const std::shared_ptr<PixelMap> &reusePixelmap)
{
#if !defined(CROSS_PLATFORM)
if (!CanReusePixelMap(context, width, height, reusePixelmap)) {
return false;
}
auto hdrPixelFormat = GRAPHIC_PIXEL_FMT_RGBA_1010102;
if (context.photoDesiredPixelFormat == PixelFormat::YCBCR_P010) {
hdrPixelFormat = GRAPHIC_PIXEL_FMT_YCBCR_P010;
}
SetContextHdr(context, hdrPixelFormat);
bool cond = (reusePixelmap->GetPixelFormat() != context.info.pixelFormat);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "PixelFormat of Hdrimage is not equal to reusePixelmap");
return true;
#else
return false;
#endif
}
bool ImageUtils::CanReusePixelMapSdr(ImagePlugin::DecodeContext& context, int width,
int height, const std::shared_ptr<PixelMap> &reusePixelmap)
{
if (!CanReusePixelMap(context, width, height, reusePixelmap)) {
return false;
}
bool cond = ((reusePixelmap->GetPixelFormat() == PixelFormat::RGBA_1010102) ||
(context.info.pixelFormat == PixelFormat::RGBA_1010102));
CHECK_ERROR_RETURN_RET_LOG(cond, false, "Sdr image is not RGBA 10bit");
cond = (reusePixelmap->GetPixelFormat() != context.info.pixelFormat);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "PixelFormat of Sdrimage is not equal to reusePixelmap");
return true;
}
bool CanApplyMemForReusePixel(ImagePlugin::DecodeContext& context,
const std::shared_ptr<PixelMap> &reusePixelmap)
{
#if !defined(CROSS_PLATFORM)
uint8_t *reusePixelBuffer = const_cast<uint8_t *>(reusePixelmap->GetPixels());
int32_t err = ImageUtils::SurfaceBuffer_Reference(reusePixelmap->GetFd());
bool cond = err != OHOS::GSERROR_OK;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "reusePixelmapBuffer Reference failed");
ImageUtils::SetReuseContextBuffer(context, AllocatorType::DMA_ALLOC, reusePixelBuffer,
reusePixelmap->GetCapacity(), reusePixelmap->GetFd());
return true;
#else
return false;
#endif
}
bool ImageUtils::IsSdrPixelMapReuseSuccess(ImagePlugin::DecodeContext& context, int width,
int height, const std::shared_ptr<PixelMap> &reusePixelmap)
{
#if !defined(CROSS_PLATFORM)
if (!CanReusePixelMapSdr(context, width, height, reusePixelmap)) {
return false;
}
return CanApplyMemForReusePixel(context, reusePixelmap);
#else
return false;
#endif
}
bool ImageUtils::IsHdrPixelMapReuseSuccess(ImagePlugin::DecodeContext& context, int width,
int height, const std::shared_ptr<PixelMap> &reusePixelmap)
{
#if !defined(CROSS_PLATFORM)
if (!CanReusePixelMapHdr(context, width, height, reusePixelmap)) {
return false;
}
return CanApplyMemForReusePixel(context, reusePixelmap);
#else
return false;
#endif
}
void ImageUtils::SetContextHdr(ImagePlugin::DecodeContext& context, uint32_t format)
{
#if !defined(CROSS_PLATFORM)
context.info.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
if (format == GRAPHIC_PIXEL_FMT_RGBA_1010102) {
context.pixelFormat = PixelFormat::RGBA_1010102;
context.info.pixelFormat = PixelFormat::RGBA_1010102;
context.grColorSpaceName = ColorManager::BT2020_HLG;
} else if (format == GRAPHIC_PIXEL_FMT_YCBCR_P010) {
context.pixelFormat = PixelFormat::YCBCR_P010;
context.info.pixelFormat = PixelFormat::YCBCR_P010;
context.grColorSpaceName = ColorManager::BT2020_HLG;
}
#endif
}
void ImageUtils::SetReuseContextBuffer(ImagePlugin::DecodeContext& context,
AllocatorType type, uint8_t* ptr, uint64_t count, void* fd)
{
context.allocatorType = type;
context.freeFunc = nullptr;
context.pixelsBuffer.buffer = ptr;
context.pixelsBuffer.bufferSize = count;
context.pixelsBuffer.context = fd;
}
bool ImageUtils::CheckRowDataSizeIsVaild(int32_t &rowDataSize, ImageInfo &imgInfo)
{
int32_t bytesPerPixel = ImageUtils::GetPixelBytes(imgInfo.pixelFormat);
if (bytesPerPixel == 0 || rowDataSize <=0 ||
rowDataSize != ImageUtils::GetRowDataSizeByPixelFormat(imgInfo.size.width, imgInfo.pixelFormat)) {
IMAGE_LOGE("[ImageUtils] RowDataSizeIsVaild: bytesPerPixel or rowDataSize:%{public}d", rowDataSize);
return false;
}
return true;
}
bool ImageUtils::CheckBufferSizeIsValid(int32_t &bufferSize, uint64_t &expectedBufferSize, AllocatorType &allocatorType)
{
if (bufferSize <= 0 ||
expectedBufferSize > (allocatorType == AllocatorType::HEAP_ALLOC ? PIXEL_MAP_MAX_RAM_SIZE : INT_MAX) ||
expectedBufferSize != static_cast<uint64_t>(bufferSize)) {
IMAGE_LOGE("[ImageUtils] BufferSizeIsVaild: bufferSize invalid, expect:%{public}llu, actual:%{public}d",
static_cast<unsigned long long>(expectedBufferSize), bufferSize);
return false;
}
return true;
}
bool ImageUtils::CheckSizeValid(const ImageInfo &imgInfo, const YUVDataInfo& yDataInfo)
{
if (yDataInfo.imageSize.width != imgInfo.size.width || yDataInfo.imageSize.height != imgInfo.size.height) {
IMAGE_LOGE("Invalid YUVDataInfo: imageSize(%{public}d, %{public}d) mismatch ImageInfo(%{public}d, %{public}d)",
yDataInfo.imageSize.width, yDataInfo.imageSize.height, imgInfo.size.width, imgInfo.size.height);
return false;
}
const uint32_t yExpectedWidth = static_cast<uint32_t>(yDataInfo.imageSize.width);
const uint32_t yExpectedHeight = static_cast<uint32_t>(yDataInfo.imageSize.height);
if (yDataInfo.yWidth != yExpectedWidth || yDataInfo.yHeight != yExpectedHeight) {
IMAGE_LOGE("Invalid Y plane size: Y(%{public}u, %{public}u) mismatch expected(%{public}u, %{public}u)",
yDataInfo.yWidth, yDataInfo.yHeight, yExpectedWidth, yExpectedHeight);
return false;
}
if (imgInfo.pixelFormat == PixelFormat::Y8 && yDataInfo.uvWidth == 0 && yDataInfo.uvHeight == 0) {
return true;
}
const uint32_t uvExpectedWidth = (yDataInfo.yWidth + NUM_1) / NUM_2;
const uint32_t uvExpectedHeight = (yDataInfo.yHeight + NUM_1) / NUM_2;
if (yDataInfo.uvWidth != uvExpectedWidth || yDataInfo.uvHeight != uvExpectedHeight) {
IMAGE_LOGE("Invalid UV plane size: UV(%{public}u, %{public}u) mismatch expected(%{public}u, %{public}u)",
yDataInfo.uvWidth, yDataInfo.uvHeight, uvExpectedWidth, uvExpectedHeight);
return false;
}
return true;
}
bool ImageUtils::CheckStrideValid(const YUVDataInfo& yDataInfo)
{
if (yDataInfo.yStride < yDataInfo.yWidth) {
IMAGE_LOGE("Invalid Y stride: %{public}u < width=%{public}u", yDataInfo.yStride, yDataInfo.yWidth);
return false;
}
if (yDataInfo.uvStride < yDataInfo.uvWidth) {
IMAGE_LOGE("Invalid UV stride: %{public}u < width=%{public}u", yDataInfo.uvStride, yDataInfo.uvWidth);
return false;
}
if (yDataInfo.yStride >= yDataInfo.yWidth * NUM_2 || yDataInfo.uvStride >= yDataInfo.yWidth * NUM_2) {
IMAGE_LOGW("Possible invalid stride as byte value: Stride=(%{public}u, %{public}u), Width=%{public}u",
yDataInfo.yStride, yDataInfo.uvStride, yDataInfo.yWidth);
}
if (yDataInfo.uStride != 0 && yDataInfo.uStride < yDataInfo.uvWidth) {
IMAGE_LOGW("Invalid U stride: %{public}u < uvWidth=%{public}u", yDataInfo.uStride, yDataInfo.uvWidth);
}
if (yDataInfo.vStride != 0 && yDataInfo.vStride < yDataInfo.uvWidth) {
IMAGE_LOGW("Invalid V stride: %{public}u < uvWidth=%{public}u", yDataInfo.vStride, yDataInfo.uvWidth);
}
return true;
}
bool ImageUtils::CheckOffsetValid(const YUVDataInfo& yDataInfo)
{
if (yDataInfo.yOffset != 0) {
IMAGE_LOGE("Invalid Y offset: %{public}u (expected 0)", yDataInfo.yOffset);
return false;
}
const uint64_t yPlaneSize = static_cast<uint64_t>(yDataInfo.yStride) * yDataInfo.yHeight;
const uint64_t uvPlaneSize = static_cast<uint64_t>(yDataInfo.uvStride) * yDataInfo.uvHeight;
const uint64_t bufferSize = yPlaneSize + uvPlaneSize;
if (yDataInfo.uvOffset == 0 && yDataInfo.uvStride == 0 && yDataInfo.uvHeight == 0 && yDataInfo.uvWidth == 0) {
if (yPlaneSize > UINT32_MAX) {
IMAGE_LOGE("Invalid YUV buffer size: overflow (exceeds UINT32_MAX)");
return false;
}
return true;
}
if (static_cast<uint64_t>(yDataInfo.uvOffset) < yPlaneSize) {
IMAGE_LOGE("Invalid UV offset: %{public}u less than Y plane size", yDataInfo.uvOffset);
return false;
}
if (yPlaneSize > UINT32_MAX || uvPlaneSize > UINT32_MAX || bufferSize > UINT32_MAX) {
IMAGE_LOGE("Invalid YUV buffer size: overflow (exceeds UINT32_MAX)");
return false;
}
if (yDataInfo.uOffset != 0) {
if (static_cast<uint64_t>(yDataInfo.uOffset) < yPlaneSize) {
IMAGE_LOGW("Invalid U offset: %{public}u less than Y plane size", yDataInfo.uOffset);
}
if (static_cast<uint64_t>(yDataInfo.uOffset) >= bufferSize) {
IMAGE_LOGW("Invalid U offset: uOffset exceeds buffer size");
}
}
if (yDataInfo.vOffset != 0) {
if (static_cast<uint64_t>(yDataInfo.vOffset) < yPlaneSize) {
IMAGE_LOGW("Invalid V offset: %{public}u less than Y plane size", yDataInfo.vOffset);
}
if (static_cast<uint64_t>(yDataInfo.vOffset) >= bufferSize) {
IMAGE_LOGW("Invalid V offset: vOffset exceeds buffer size");
}
}
return true;
}
bool ImageUtils::CheckYuvDataInfoValid(PixelMap *pixelMap, YUVDataInfo& yDataInfo)
{
CHECK_ERROR_RETURN_RET_LOG(pixelMap == nullptr, false, "pixelMap is nullptr");
ImageInfo imageInfo;
pixelMap->GetImageInfo(imageInfo);
if (!CheckSizeValid(imageInfo, yDataInfo)) {
yDataInfo.imageSize = imageInfo.size;
yDataInfo.yWidth = static_cast<uint32_t>(yDataInfo.imageSize.width);
yDataInfo.yHeight = static_cast<uint32_t>(yDataInfo.imageSize.height);
yDataInfo.uvWidth = (yDataInfo.yWidth + NUM_1) / NUM_2;
yDataInfo.uvHeight = (yDataInfo.yHeight + NUM_1) / NUM_2;
IMAGE_LOGI("YUVDataInfo size has been corrected, YUVDataInfo: %{public}s", yDataInfo.ToString().c_str());
}
if (!CheckStrideValid(yDataInfo)) {
IMAGE_LOGE("Invalid Yuvdatainfo Stride, YUVDataInfo: %{public}s", yDataInfo.ToString().c_str());
return false;
}
if (!CheckOffsetValid(yDataInfo)) {
IMAGE_LOGE("Invalid Yuvdatainfo Offset, YUVDataInfo: %{public}s", yDataInfo.ToString().c_str());
return false;
}
return true;
}
bool ImageUtils::GetAlignedNumber(int32_t& number, int32_t align)
{
if (number < 0 || align <= 0) {
return false;
}
int64_t res = number;
res = (res + align - 1) / align * align;
if (res > INT32_MAX) {
return false;
}
number = static_cast<int32_t>(res);
return true;
}
uint16_t ImageUtils::GetRGBA1010102ColorR(uint32_t color)
{
return (color >> RGBA1010102_R_SHIFT) & RGBA1010102_RGB_MASK;
}
uint16_t ImageUtils::GetRGBA1010102ColorG(uint32_t color)
{
return (color >> RGBA1010102_G_SHIFT) & RGBA1010102_RGB_MASK;
}
uint16_t ImageUtils::GetRGBA1010102ColorB(uint32_t color)
{
return (color >> RGBA1010102_B_SHIFT) & RGBA1010102_RGB_MASK;
}
uint16_t ImageUtils::GetRGBA1010102ColorA(uint32_t color)
{
return (color >> RGBA1010102_A_SHIFT) & RGBA1010102_ALPHA_MASK;
}
bool ImageUtils::CheckPixelsInput(PixelMap* pixelMap, const RWPixelsOptions &opts)
{
const Rect& rect = opts.region;
if (opts.bufferSize == 0 || opts.pixels == nullptr) {
IMAGE_LOGE("CheckPixelsInput bufferSize or dst address invalid, bufferSize: %{public}" PRIu64, opts.bufferSize);
return false;
}
if (rect.left < 0 || rect.top < 0 || opts.stride > numeric_limits<int32_t>::max() ||
static_cast<uint64_t>(opts.offset) > opts.bufferSize) {
IMAGE_LOGE("CheckPixelsInput left(%{public}d) or top(%{public}d) or stride(%{public}u) or offset(%{public}u) "
"is invalid.", rect.left, rect.top, opts.stride, opts.offset);
return false;
}
if (rect.width <= 0 || rect.height <= 0 || rect.width > MAX_DIMENSION || rect.height > MAX_DIMENSION) {
IMAGE_LOGE("CheckPixelsInput width(%{public}d) or height(%{public}d) is < 0.", rect.width, rect.height);
return false;
}
if (rect.left > pixelMap->GetWidth() - rect.width) {
IMAGE_LOGE("CheckPixelsInput left(%{public}d) + width(%{public}d) is > pixelmap width(%{public}d).",
rect.left, rect.width, pixelMap->GetWidth());
return false;
}
if (rect.top > pixelMap->GetHeight() - rect.height) {
IMAGE_LOGE("CheckPixelsInput top(%{public}d) + height(%{public}d) is > pixelmap height(%{public}d).",
rect.top, rect.height, pixelMap->GetHeight());
return false;
}
int32_t pixelBytes = ImageUtils::GetPixelBytes(opts.pixelFormat);
if (pixelBytes <= 0) {
IMAGE_LOGE("CheckPixelsInput invalid pixel format: %{public}d", opts.pixelFormat);
return false;
}
uint32_t regionStride = static_cast<uint32_t>(rect.width) * static_cast<uint32_t>(pixelBytes);
if (opts.stride < regionStride || opts.bufferSize < regionStride) {
IMAGE_LOGE("CheckPixelsInput input stride (%{public}u) or input buffer size (%{public}" PRIu64
") is less than regionStride (%{public}u).", opts.stride, opts.bufferSize, regionStride);
return false;
}
uint64_t lastLinePos = opts.offset + static_cast<uint64_t>(rect.height - NUM_1) * opts.stride;
if (static_cast<uint64_t>(opts.offset) > (opts.bufferSize - regionStride) ||
lastLinePos > (opts.bufferSize - regionStride)) {
IMAGE_LOGE("CheckPixelsInput fail, height(%{public}d), width(%{public}d), lastLine(%{public}" PRIu64
"), offset(%{public}u), bufferSize:%{public}" PRIu64 ".", rect.height, rect.width, lastLinePos, opts.offset,
opts.bufferSize);
return false;
}
return true;
}
bool ImageUtils::FloatEqual(float a, float b)
{
return std::fabs(a - b) < EPSILON;
}
void ImageUtils::WriteUint8(std::vector<uint8_t> &buff, uint8_t value)
{
buff.push_back(value);
}
void ImageUtils::WriteVarint(std::vector<uint8_t> &buff, int32_t value)
{
uint32_t uValue = uint32_t(value);
while (uValue > TLV_VARINT_MASK) {
buff.push_back(TLV_VARINT_MORE | uint8_t(uValue & TLV_VARINT_MASK));
uValue >>= TLV_VARINT_BITS;
}
buff.push_back(uint8_t(uValue));
}
uint8_t ImageUtils::GetVarintLen(int32_t value)
{
uint32_t uValue = static_cast<uint32_t>(value);
uint8_t len = 1;
while (uValue > TLV_VARINT_MASK) {
len++;
uValue >>= TLV_VARINT_BITS;
}
return len;
}
void ImageUtils::TlvWriteSurfaceInfo(const PixelMap* pixelMap, vector<uint8_t>& buff)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
sptr<SurfaceBuffer> surfaceBuffer(reinterpret_cast<SurfaceBuffer*>(pixelMap->GetFd()));
CM_ColorSpaceType colorSpaceType;
if (VpeUtils::GetSbColorSpaceType(surfaceBuffer, colorSpaceType)) {
WriteUint8(buff, TLV_IMAGE_COLORTYPE);
WriteVarint(buff, GetVarintLen(static_cast<int32_t>(colorSpaceType)));
WriteVarint(buff, static_cast<int32_t>(colorSpaceType));
}
CM_HDR_Metadata_Type metadataType;
if (VpeUtils::GetSbMetadataType(surfaceBuffer, metadataType)) {
WriteUint8(buff, TLV_IMAGE_METADATATYPE);
WriteVarint(buff, GetVarintLen(static_cast<int32_t>(metadataType)));
WriteVarint(buff, static_cast<int32_t>(metadataType));
}
vector<uint8_t> staticMetadata;
if (VpeUtils::GetSbStaticMetadata(surfaceBuffer, staticMetadata)) {
WriteUint8(buff, TLV_IMAGE_STATICMETADATA);
WriteVarint(buff, static_cast<int32_t>(staticMetadata.size()));
buff.insert(buff.end(), staticMetadata.begin(), staticMetadata.end());
}
vector<uint8_t> dynamicMetadata;
if (VpeUtils::GetSbDynamicMetadata(surfaceBuffer, dynamicMetadata)) {
WriteUint8(buff, TLV_IMAGE_DYNAMICMETADATA);
WriteVarint(buff, static_cast<int32_t>(dynamicMetadata.size()));
buff.insert(buff.end(), dynamicMetadata.begin(), dynamicMetadata.end());
}
#endif
return;
}
bool ImageUtils::ReadVarint(std::vector<uint8_t> &buff, int32_t &cursor, int32_t &result)
{
if (cursor < 0) {
IMAGE_LOGE("ReadVarint invalid cursor");
return false;
}
size_t readPos = static_cast<size_t>(cursor);
uint32_t value = 0;
constexpr uint8_t maxVarintBytes = 5;
for (uint8_t byteIndex = 0; byteIndex < maxVarintBytes; ++byteIndex) {
if (readPos >= buff.size()) {
IMAGE_LOGE("ReadVarint out of range");
return false;
}
uint8_t item = buff[readPos++];
if (byteIndex == maxVarintBytes - 1 && (item & 0xF0) != 0) {
IMAGE_LOGE("ReadVarint value overflow");
return false;
}
value |= static_cast<uint32_t>(item & TLV_VARINT_MASK) << (byteIndex * TLV_VARINT_BITS);
if ((item & TLV_VARINT_MORE) == 0) {
if (readPos > static_cast<size_t>(INT32_MAX)) {
IMAGE_LOGE("ReadVarint cursor overflow");
return false;
}
cursor = static_cast<int32_t>(readPos);
result = static_cast<int32_t>(value);
return true;
}
}
IMAGE_LOGE("ReadVarint too long");
return false;
}
int32_t ImageUtils::AllocPixelMapMemory(std::unique_ptr<AbsMemory> &dstMemory, int32_t &dstRowStride,
const ImageInfo &dstImageInfo, const InitializationOptions &opts)
{
int64_t rowDataSize = ImageUtils::GetRowDataSizeByPixelFormat(dstImageInfo.size.width, dstImageInfo.pixelFormat);
if (rowDataSize <= 0) {
IMAGE_LOGE("[PixelMap] AllocPixelMapMemory: Get row data size failed");
return -1;
}
int64_t bufferSize = rowDataSize * dstImageInfo.size.height;
if (bufferSize > UINT32_MAX) {
IMAGE_LOGE("[PixelMap]Create: pixelmap size too large: width = %{public}d, height = %{public}d",
dstImageInfo.size.width, dstImageInfo.size.height);
return -1;
}
if (IsYuvFormat(dstImageInfo.pixelFormat)) {
bufferSize = GetYUVByteCount(dstImageInfo);
}
MemoryData memoryData = {nullptr, static_cast<size_t>(bufferSize), "Create PixelMap", dstImageInfo.size,
dstImageInfo.pixelFormat};
AllocatorType allocType = opts.allocatorType == AllocatorType::DEFAULT ?
ImageUtils::GetPixelMapAllocatorType(dstImageInfo.size, dstImageInfo.pixelFormat, opts.useDMA,
memoryData.usage) :
opts.allocatorType;
dstMemory = MemoryManager::CreateMemory(allocType, memoryData);
if (dstMemory == nullptr) {
IMAGE_LOGE("[PixelMap]Create: allocate memory failed");
return -1;
}
dstRowStride = dstImageInfo.size.width * ImageUtils::GetPixelBytes(dstImageInfo.pixelFormat);
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
if (dstMemory->GetType() == AllocatorType::DMA_ALLOC) {
SurfaceBuffer* sbBuffer = static_cast<SurfaceBuffer*>(dstMemory->extend.data);
if (sbBuffer == nullptr) {
IMAGE_LOGE("get SurfaceBuffer failed");
return -1;
}
dstRowStride = sbBuffer->GetStride();
}
#endif
return SUCCESS;
}
std::unique_ptr<AbsMemory> ImageUtils::ReadData(std::vector<uint8_t> &buff, int32_t size, int32_t &cursor,
AllocatorType allocType, ImageInfo imageInfo)
{
if (size <= 0 || static_cast<size_t>(size) > MAX_TLV_HEAP_SIZE) {
IMAGE_LOGE("[PixelMap] tlv read data fail: invalid size[%{public}d]", size);
return nullptr;
}
if (imageInfo.size.width <= 0 || imageInfo.size.height <= 0 || imageInfo.size.width > MAX_DIMENSION ||
imageInfo.size.height > MAX_DIMENSION) {
IMAGE_LOGE("[PixelMap] tlv read data fail: invalid image size");
return nullptr;
}
int32_t rowDataSize = ImageUtils::GetRowDataSizeByPixelFormat(imageInfo.size.width, imageInfo.pixelFormat);
int64_t expectedSize = static_cast<int64_t>(rowDataSize) * static_cast<int64_t>(imageInfo.size.height);
if (rowDataSize <= 0 || expectedSize <= 0 || expectedSize > INT32_MAX ||
static_cast<size_t>(expectedSize) > MAX_TLV_HEAP_SIZE || size != expectedSize) {
IMAGE_LOGE("[PixelMap] tlv read data fail: data size does not match image info");
return nullptr;
}
int64_t allocationSize = expectedSize;
if (IsYuvFormat(imageInfo.pixelFormat)) {
allocationSize = GetYUVByteCount(imageInfo);
}
if (allocationSize <= 0 || static_cast<size_t>(allocationSize) > MAX_TLV_HEAP_SIZE) {
IMAGE_LOGE("[PixelMap] tlv read data fail: allocation size out of range");
return nullptr;
}
if (cursor < 0 || static_cast<size_t>(cursor) > buff.size() ||
static_cast<size_t>(size) > buff.size() - static_cast<size_t>(cursor)) {
IMAGE_LOGE("[PixelMap] ReadData out of range");
return nullptr;
}
std::unique_ptr<AbsMemory> dstMemory = nullptr;
int32_t dstRowStride = 0;
InitializationOptions opts;
opts.allocatorType = allocType;
int32_t errorCode = AllocPixelMapMemory(dstMemory, dstRowStride, imageInfo, opts);
if (dstMemory == nullptr || dstMemory->data.data == nullptr || errorCode != SUCCESS) {
IMAGE_LOGE("[PixelMap] tlv read data fail: alloc memory failed");
return nullptr;
}
uint8_t* addr = static_cast<uint8_t*>(dstMemory->data.data);
uint8_t* srcAddr = buff.data() + cursor;
#if !defined(CROSS_PLATFORM)
if (allocType == AllocatorType::DMA_ALLOC) {
if (dstRowStride == 0 || dstRowStride < rowDataSize ||
static_cast<uint32_t>(size) > static_cast<SurfaceBuffer*>(dstMemory->extend.data)->GetSize()) {
IMAGE_LOGE("[PixelMap] tlv check dma size failed");
dstMemory->Release();
return nullptr;
}
for (int i = 0; i < imageInfo.size.height; i++) {
if (memcpy_s(addr + i * dstRowStride, rowDataSize, srcAddr + i * rowDataSize, rowDataSize) != 0) {
IMAGE_LOGE("[PixelMap] tlv copy dma data failed");
dstMemory->Release();
return nullptr;
}
}
} else {
#endif
if (rowDataSize != dstRowStride) {
IMAGE_LOGE("[PixelMap] tlv check heap size failed");
dstMemory->Release();
return nullptr;
}
if (memcpy_s(addr, size, srcAddr, size) != 0) {
IMAGE_LOGE("[PixelMap] tlv copy heap data failed");
dstMemory->Release();
return nullptr;
}
#if !defined(CROSS_PLATFORM)
}
#endif
return dstMemory;
}
PixelFormat ImageUtils::ConvertTo10BitPixelFormat(PixelFormat pixelFormat)
{
PixelFormat hdrAllocFormat = PixelFormat::UNKNOWN;
switch (pixelFormat) {
case PixelFormat::RGBA_8888:
hdrAllocFormat = PixelFormat::RGBA_1010102;
break;
case PixelFormat::NV21:
hdrAllocFormat = PixelFormat::YCRCB_P010;
break;
case PixelFormat::NV12:
hdrAllocFormat = PixelFormat::YCBCR_P010;
break;
case PixelFormat::RGBA_1010102:
hdrAllocFormat = PixelFormat::RGBA_1010102;
break;
case PixelFormat::YCRCB_P010:
hdrAllocFormat = PixelFormat::YCRCB_P010;
break;
case PixelFormat::YCBCR_P010:
hdrAllocFormat = PixelFormat::YCBCR_P010;
break;
default:
IMAGE_LOGE("ConvertTo10BitPixleFormat failed, format: %{public}d", pixelFormat);
break;
}
return hdrAllocFormat;
}
bool ImageUtils::IsSystemApp()
{
#if !defined(CROSS_PLATFORM)
static bool isSys = Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(IPCSkeleton::GetSelfTokenID());
return isSys;
#else
return false;
#endif
}
bool ImageUtils::CalcRGBStride(PixelFormat format, uint32_t width, int &stride)
{
uint32_t pixelBytes = 0;
switch (format) {
case PixelFormat::RGB_565:
pixelBytes = RGB565_BYTES;
break;
case PixelFormat::BGRA_8888:
case PixelFormat::RGBA_8888:
case PixelFormat::RGBA_1010102:
pixelBytes = ARGB8888_BYTES;
break;
case PixelFormat::RGBA_F16:
pixelBytes = RGBA_F16_BYTES;
break;
case PixelFormat::ALPHA_F16:
pixelBytes = ALPHA_F16_BYTES;
break;
case PixelFormat::RGB_888:
pixelBytes = RGB888_BYTES;
break;
default:
IMAGE_LOGE("CalcRGBStride error: unsupported pixel format:%{public}d", format);
return false;
}
if (width > INT_MAX / pixelBytes) {
IMAGE_LOGE("CalcRGBStride error: overflow! format=%{public}d, width=%{public}u", format, width);
return false;
}
stride = static_cast<int>(width * pixelBytes);
return true;
}
#if !defined(CROSS_PLATFORM)
void ImageUtils::GetYUVStrideInfo(SurfaceBuffer* surfaceBuffer, YUVStrideInfo &dstStrides)
{
int32_t pixelFmt = surfaceBuffer->GetFormat();
OH_NativeBuffer_Planes *planes = nullptr;
GSError retVal = surfaceBuffer->GetPlanesInfo(reinterpret_cast<void**>(&planes));
if (retVal != OHOS::GSERROR_OK || planes == nullptr) {
IMAGE_LOGE("%{public}s Get planesInfo failed, retVal:%{public}d", __func__, retVal);
return;
} else if (planes->planeCount < NUM_2) {
IMAGE_LOGE("%{public}s Planes->planeCount: %{public}d, less than two", __func__, planes->planeCount);
return;
}
if (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_420_SP) {
auto yStride = planes->planes[PLANE_Y].columnStride;
auto uvStride = planes->planes[PLANE_U].columnStride;
auto yOffset = planes->planes[PLANE_Y].offset;
auto uvOffset = planes->planes[PLANE_U].offset;
dstStrides = {yStride, uvStride, yOffset, uvOffset};
} else if (pixelFmt == GRAPHIC_PIXEL_FMT_YCRCB_420_SP) {
auto yStride = planes->planes[PLANE_Y].columnStride;
auto uvStride = planes->planes[PLANE_V].columnStride;
auto yOffset = planes->planes[PLANE_Y].offset;
auto uvOffset = planes->planes[PLANE_V].offset;
dstStrides = {yStride, uvStride, yOffset, uvOffset};
} else if (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010) {
auto yStride = planes->planes[PLANE_Y].columnStride / NUM_2;
auto uvStride = planes->planes[PLANE_U].columnStride / NUM_2;
auto yOffset = planes->planes[PLANE_Y].offset / NUM_2;
auto uvOffset = planes->planes[PLANE_U].offset / NUM_2;
dstStrides = {yStride, uvStride, yOffset, uvOffset};
} else if (pixelFmt == GRAPHIC_PIXEL_FMT_YCRCB_P010) {
auto yStride = planes->planes[PLANE_Y].columnStride / NUM_2;
auto uvStride = planes->planes[PLANE_V].columnStride / NUM_2;
auto yOffset = planes->planes[PLANE_Y].offset / NUM_2;
auto uvOffset = planes->planes[PLANE_V].offset / NUM_2;
dstStrides = {yStride, uvStride, yOffset, uvOffset};
}
}
static sptr<SurfaceBuffer> CreateRGBA1010102SurfaceBuffer(int32_t width, int32_t height)
{
sptr<SurfaceBuffer> dstSb = SurfaceBuffer::Create();
CHECK_ERROR_RETURN_RET_LOG(dstSb == nullptr, nullptr, "create dstSb failed");
BufferRequestConfig dstConfig = {
.width = width,
.height = height,
.strideAlignment = 0x8,
.format = GRAPHIC_PIXEL_FMT_RGBA_1010102,
.usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE,
.timeout = 0,
};
GSError ret = dstSb->Alloc(dstConfig);
CHECK_ERROR_RETURN_RET_LOG(ret != GSERROR_OK, nullptr, "alloc dstSb failed, error: %{public}s",
GSErrorStr(ret).c_str());
return dstSb;
}
static void SetupConversionColorSpace(sptr<SurfaceBuffer>& srcSb, sptr<SurfaceBuffer>& dstSb)
{
CM_ColorSpaceInfo ColorSpace_Info_SRGB_FULL = {
.primaries = COLORPRIMARIES_SRGB,
.transfunc = TRANSFUNC_SRGB,
.matrix = MATRIX_BT601_N,
.range = RANGE_FULL,
};
VpeUtils::SetSbMetadataType(srcSb, CM_IMAGE_HDR_VIVID_SINGLE);
MetadataHelper::SetColorSpaceInfo(srcSb, ColorSpace_Info_SRGB_FULL);
CM_ColorSpaceInfo COLORSPACE_INFO_BT2020_HLG_FULL = {
.primaries = COLORPRIMARIES_BT2020,
.transfunc = TRANSFUNC_HLG,
.matrix = MATRIX_BT2020,
.range = RANGE_FULL
};
VpeUtils::SetSbMetadataType(dstSb, CM_IMAGE_HDR_VIVID_SINGLE);
MetadataHelper::SetColorSpaceInfo(dstSb, COLORSPACE_INFO_BT2020_HLG_FULL);
}
bool ImageUtils::ConvertRGBAF16ToRGBA1010102(
const std::shared_ptr<PixelMap>& srcPixelMap, std::unique_ptr<PixelMap>& dstPixelMap)
{
CHECK_ERROR_RETURN_RET_LOG(srcPixelMap == nullptr, false, "srcPixelMap is nullptr");
ImageInfo srcImageInfo;
srcPixelMap->GetImageInfo(srcImageInfo);
CHECK_ERROR_RETURN_RET_LOG(srcImageInfo.pixelFormat != PixelFormat::RGBA_F16, false,
"srcPixelMap format is not RGBA_F16");
int32_t width = srcImageInfo.size.width;
int32_t height = srcImageInfo.size.height;
CHECK_ERROR_RETURN_RET_LOG(srcPixelMap->GetAllocatorType() != AllocatorType::DMA_ALLOC, false,
"srcPixelMap is not DMA memory");
sptr<SurfaceBuffer> dstSb = CreateRGBA1010102SurfaceBuffer(width, height);
CHECK_ERROR_RETURN_RET_LOG(dstSb == nullptr, false, "create dstSb failed");
sptr<SurfaceBuffer> srcSb = sptr<SurfaceBuffer>(
reinterpret_cast<SurfaceBuffer*>(srcPixelMap->GetFd()));
CHECK_ERROR_RETURN_RET_LOG(srcSb == nullptr, false, "get srcSb from srcPixelMap failed");
SetupConversionColorSpace(srcSb, dstSb);
std::unique_ptr<VpeUtils> utils = std::make_unique<VpeUtils>();
int32_t res = utils->ColorSpaceConverterImageProcess(srcSb, dstSb);
CHECK_ERROR_RETURN_RET_LOG(res != VPE_ERROR_OK, false,
"ColorSpaceConverterImageProcess failed, res = %{public}d", res);
CHECK_ERROR_RETURN_RET_LOG(!ImageUtils::SurfaceBuffer2PixelMap(dstSb, dstPixelMap), false,
"SurfaceBuffer2PixelMap failed");
return true;
}
#endif
}
}