* Copyright (C) 2024 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 "vpe_utils.h"
#include <dlfcn.h>
#include "hilog/log.h"
#include "log_tags.h"
#include "image_log.h"
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
#include "v1_0/buffer_handle_meta_key_type.h"
#include "metadata_convertor.h"
#include "external_window.h"
#include "native_window.h"
#endif
#undef LOG_DOMAIN
#define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
#undef LOG_TAG
#define LOG_TAG "VpeUtils"
namespace OHOS {
namespace Media {
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
using namespace OHOS::HDI::Display::Graphic::Common::V1_0;
static constexpr uint32_t TRANSFUNC_OFFSET = 8;
static constexpr uint32_t MATRIX_OFFSET = 16;
static constexpr uint32_t RANGE_OFFSET = 21;
static constexpr uint32_t RGBA1010102_G_SHIFT = 10;
static constexpr uint32_t RGBA1010102_B_SHIFT = 20;
static constexpr uint32_t RGBA8888_G_SHIFT = 8;
static constexpr uint32_t RGBA8888_B_SHIFT = 16;
static constexpr uint32_t RGBA8888_A_SHIFT = 24;
static constexpr uint32_t TRUNCAT_BIT = 2;
static constexpr uint8_t P010_TO_YUV420_SHIFT = 8;
static constexpr uint8_t YUV420_CHROMA_DIVIDER = 2;
static constexpr uint8_t CHROMA_V_INDEX = 1;
constexpr uint8_t INDEX_ZERO = 0;
constexpr uint8_t INDEX_ONE = 1;
constexpr uint8_t INDEX_TWO = 2;
static constexpr int32_t PLANE_U = 1;
static constexpr int32_t PLANE_V = 2;
#endif
std::unique_ptr<VpeSoHelper> VpeUtils::dlHandler_ = nullptr;
using CreateT = int32_t (*)(int32_t*);
using DestoryT = int32_t (*)(int32_t*);
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
using ComposeImageT =
int32_t (*)(int32_t, OHNativeWindowBuffer*, OHNativeWindowBuffer*, OHNativeWindowBuffer*, bool);
using DecomposeImageT =
int32_t (*)(int32_t, OHNativeWindowBuffer*, OHNativeWindowBuffer*, OHNativeWindowBuffer*);
using HdrProcessImageT =
int32_t (*)(int32_t, OHNativeWindowBuffer*, OHNativeWindowBuffer*);
using SrProcessImageT =
int32_t (*)(int32_t, OHNativeWindowBuffer*, OHNativeWindowBuffer*, int32_t);
using CalGainmapImageT =
int32_t (*)(int32_t, OHNativeWindowBuffer*, OHNativeWindowBuffer*, OHNativeWindowBuffer*);
#endif
VpeUtils::VpeUtils()
{
static std::once_flag flag;
std::function<void()> func = []() {
VpeUtils::dlHandler_ = std::make_unique<VpeSoHelper>();
};
std::call_once(flag, func);
}
VpeUtils::~VpeUtils()
{
}
int32_t VpeUtils::ColorSpaceConverterCreate(void* handle, int32_t* instanceId)
{
if (handle == nullptr) {
return VPE_ERROR_FAILED;
}
CreateT create = (CreateT)dlsym(handle, "ColorSpaceConverterCreate");
if (!create) {
return VPE_ERROR_FAILED;
}
return create(instanceId);
}
int32_t VpeUtils::ColorSpaceConverterDestory(void* handle, int32_t* instanceId)
{
if (*instanceId == VPE_ERROR_FAILED || handle == nullptr) {
return VPE_ERROR_FAILED;
}
DestoryT destory = (DestoryT)dlsym(handle, "ColorSpaceConverterDestroy");
CHECK_ERROR_RETURN_RET(!destory, VPE_ERROR_FAILED);
return destory(instanceId);
}
int32_t VpeUtils::DetailEnhancerCreate(void* handle, int32_t* instanceId)
{
if (handle == nullptr) {
return VPE_ERROR_FAILED;
}
CreateT create = (CreateT)dlsym(handle, "DetailEnhancerCreate");
if (!create) {
return VPE_ERROR_FAILED;
}
return create(instanceId);
}
int32_t VpeUtils::DetailEnhancerDestory(void* handle, int32_t* instanceId)
{
if (*instanceId == VPE_ERROR_FAILED || handle == nullptr) {
return VPE_ERROR_FAILED;
}
DestoryT destory = (DestoryT)dlsym(handle, "DetailEnhancerDestroy");
CHECK_ERROR_RETURN_RET(!destory, VPE_ERROR_FAILED);
return destory(instanceId);
}
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
int32_t VpeUtils::ColorSpaceConverterComposeImage(VpeSurfaceBuffers& sb, bool legacy)
{
std::lock_guard<std::mutex> lock(vpeMtx_);
CHECK_ERROR_RETURN_RET((dlHandler_ == nullptr || dlHandler_->GetSoHandle() == nullptr), VPE_ERROR_FAILED);
int32_t instanceId = VPE_ERROR_FAILED;
int32_t res = ColorSpaceConverterCreate(dlHandler_->GetSoHandle(), &instanceId);
CHECK_ERROR_RETURN_RET((instanceId == VPE_ERROR_FAILED || res != VPE_ERROR_OK), VPE_ERROR_FAILED);
ComposeImageT composeImage = (ComposeImageT)dlsym(dlHandler_->GetSoHandle(), "ColorSpaceConverterComposeImage");
CHECK_ERROR_RETURN_RET(!composeImage, VPE_ERROR_FAILED);
CHECK_ERROR_RETURN_RET((sb.sdr == nullptr || sb.gainmap == nullptr || sb.hdr == nullptr), VPE_ERROR_FAILED);
OHNativeWindowBuffer* sdr = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&sb.sdr);
OHNativeWindowBuffer* gainmap = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&sb.gainmap);
OHNativeWindowBuffer* hdr = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&sb.hdr);
res = composeImage(instanceId, sdr, gainmap, hdr, legacy);
OH_NativeWindow_DestroyNativeWindowBuffer(sdr);
OH_NativeWindow_DestroyNativeWindowBuffer(gainmap);
OH_NativeWindow_DestroyNativeWindowBuffer(hdr);
ColorSpaceConverterDestory(dlHandler_->GetSoHandle(), &instanceId);
return res;
}
int32_t VpeUtils::ColorSpaceConverterDecomposeImage(VpeSurfaceBuffers& sb)
{
std::lock_guard<std::mutex> lock(vpeMtx_);
CHECK_ERROR_RETURN_RET((dlHandler_ == nullptr || dlHandler_->GetSoHandle() == nullptr), VPE_ERROR_FAILED);
int32_t res;
int32_t instanceId = VPE_ERROR_FAILED;
res = ColorSpaceConverterCreate(dlHandler_->GetSoHandle(), &instanceId);
CHECK_ERROR_RETURN_RET((instanceId == VPE_ERROR_FAILED || res != VPE_ERROR_OK), VPE_ERROR_FAILED);
DecomposeImageT decomposeImage = (DecomposeImageT)dlsym(dlHandler_->GetSoHandle(),
"ColorSpaceConverterDecomposeImage");
CHECK_ERROR_RETURN_RET(!decomposeImage, VPE_ERROR_FAILED);
CHECK_ERROR_RETURN_RET((sb.sdr == nullptr || sb.gainmap == nullptr || sb.hdr == nullptr), VPE_ERROR_FAILED);
OHNativeWindowBuffer* sdr = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&sb.sdr);
OHNativeWindowBuffer* gainmap = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&sb.gainmap);
OHNativeWindowBuffer* hdr = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&sb.hdr);
res = decomposeImage(instanceId, hdr, sdr, gainmap);
OH_NativeWindow_DestroyNativeWindowBuffer(sdr);
OH_NativeWindow_DestroyNativeWindowBuffer(gainmap);
OH_NativeWindow_DestroyNativeWindowBuffer(hdr);
ColorSpaceConverterDestory(dlHandler_->GetSoHandle(), &instanceId);
return res;
}
static bool CheckYUVBufferSize(const SurfaceBufferInfo& srcInfo, const SurfaceBufferInfo& dstInfo)
{
int32_t uvHeight = srcInfo.height / YUV420_CHROMA_DIVIDER;
const int32_t srcYStride = srcInfo.yStride > 0 ? srcInfo.yStride : srcInfo.stride;
const int32_t srcUVStride = srcInfo.uvStride > 0 ? srcInfo.uvStride : srcInfo.stride;
const int32_t dstYStride = dstInfo.yStride > 0 ? dstInfo.yStride : dstInfo.stride;
const int32_t dstUVStride = dstInfo.uvStride > 0 ? dstInfo.uvStride : dstInfo.stride;
uint64_t srcYEnd = static_cast<uint64_t>(srcInfo.height) * srcYStride;
uint64_t srcUVEnd = static_cast<uint64_t>(srcInfo.uvOffset) + static_cast<uint64_t>(uvHeight) * srcUVStride;
uint64_t dstYEnd = static_cast<uint64_t>(srcInfo.height) * dstYStride;
uint64_t dstUVEnd = static_cast<uint64_t>(dstInfo.uvOffset) + static_cast<uint64_t>(uvHeight) * dstUVStride;
bool cond = (srcYEnd > UINT32_MAX || srcUVEnd > UINT32_MAX || dstYEnd > UINT32_MAX || dstUVEnd > UINT32_MAX);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "[VpeUtils] CheckYUVBufferSize overflow");
if (srcYEnd > static_cast<uint64_t>(srcInfo.uvOffset) || srcUVEnd > static_cast<uint64_t>(srcInfo.bufferSize) ||
dstYEnd > static_cast<uint64_t>(dstInfo.uvOffset) || dstUVEnd > static_cast<uint64_t>(dstInfo.bufferSize)) {
IMAGE_LOGE("[VpeUtils] CheckYUVBufferSize buffer size exceeded");
return false;
}
return true;
}
void DoTruncateP010ToYUV420(const SurfaceBufferInfo& srcInfo, const SurfaceBufferInfo& outInfo)
{
bool cond = srcInfo.buffer == nullptr || outInfo.buffer == nullptr;
CHECK_ERROR_RETURN(cond);
uint8_t* srcY = srcInfo.buffer + srcInfo.yOffset;
uint8_t* srcUV = srcInfo.buffer + srcInfo.uvOffset;
uint8_t* dstY = outInfo.buffer + outInfo.yOffset;
uint8_t* dstUV = outInfo.buffer + outInfo.uvOffset;
const int32_t srcYStride = srcInfo.yStride > 0 ? srcInfo.yStride : srcInfo.stride;
const int32_t srcUVStride = srcInfo.uvStride > 0 ? srcInfo.uvStride : srcInfo.stride;
const int32_t dstYStride = outInfo.yStride > 0 ? outInfo.yStride : outInfo.stride;
const int32_t dstUVStride = outInfo.uvStride > 0 ? outInfo.uvStride : outInfo.stride;
cond = !CheckYUVBufferSize(srcInfo, outInfo);
CHECK_ERROR_RETURN_LOG(cond, "[VpeUtils] DoTruncateP010ToYUV420 buffer size invalid");
for (int32_t y = 0; y < srcInfo.height; y++) {
const uint16_t* srcYLine = reinterpret_cast<const uint16_t*>(srcY + y * srcYStride);
uint8_t* dstYLine = dstY + y * dstYStride;
for (int32_t x = 0; x < srcInfo.width; x++) {
uint16_t p010Pixel = srcYLine[x];
uint8_t yuv420Pixel = static_cast<uint8_t>((p010Pixel >> P010_TO_YUV420_SHIFT) & 0xFF);
dstYLine[x] = yuv420Pixel;
}
}
const int32_t uvWidth = srcInfo.width / YUV420_CHROMA_DIVIDER;
const int32_t uvHeight = srcInfo.height / YUV420_CHROMA_DIVIDER;
for (int32_t y = 0; y < uvHeight; y++) {
const uint16_t* srcUVLine = reinterpret_cast<const uint16_t*>(srcUV + y * srcUVStride);
uint8_t* dstUVLine = dstUV + y * dstUVStride;
for (int32_t x = 0; x < uvWidth; x++) {
uint16_t p010U = srcUVLine[YUV420_CHROMA_DIVIDER * x];
uint8_t yuv420U = static_cast<uint8_t>((p010U >> P010_TO_YUV420_SHIFT) & 0xFF);
uint16_t p010V = srcUVLine[YUV420_CHROMA_DIVIDER * x + CHROMA_V_INDEX];
uint8_t yuv420V = static_cast<uint8_t>((p010V >> P010_TO_YUV420_SHIFT) & 0xFF);
dstUVLine[YUV420_CHROMA_DIVIDER * x] = yuv420U;
dstUVLine[YUV420_CHROMA_DIVIDER * x + CHROMA_V_INDEX] = yuv420V;
}
}
}
void DoTruncateRGBA1010102ToRGBA8888(const SurfaceBufferInfo& srcInfo, const SurfaceBufferInfo& dstInfo)
{
bool cond = srcInfo.buffer == nullptr || dstInfo.buffer == nullptr;
CHECK_ERROR_RETURN(cond);
uint64_t srcPlaneEnd = static_cast<uint64_t>(srcInfo.height) * srcInfo.stride;
uint64_t dstPlaneEnd = static_cast<uint64_t>(dstInfo.height) * dstInfo.stride;
cond = (srcPlaneEnd > srcInfo.bufferSize) || (dstPlaneEnd > dstInfo.bufferSize);
CHECK_ERROR_RETURN_LOG(cond, "[VpeUtils] DoTruncateRGBA1010102ToRGBA8888 buffer size invalid");
for (int32_t y = 0; y < dstInfo.height; ++y) {
const uint32_t* srcRow = reinterpret_cast<const uint32_t*>(
srcInfo.buffer + y * srcInfo.stride);
uint32_t* dstRow = reinterpret_cast<uint32_t*>(
dstInfo.buffer + y * dstInfo.stride);
for (int x = 0; x < dstInfo.width; ++x) {
uint32_t pixel = srcRow[x];
uint32_t rPixel = (pixel & 0x3FF);
uint32_t gPixel = ((pixel >> RGBA1010102_G_SHIFT) & 0x3FF);
uint32_t bPixel = ((pixel >> RGBA1010102_B_SHIFT) & 0x3FF);
uint32_t aPixel = 0xFF;
dstRow[x] = (rPixel >> TRUNCAT_BIT) | ((gPixel >> TRUNCAT_BIT) << RGBA8888_G_SHIFT)
| ((bPixel >> TRUNCAT_BIT) << RGBA8888_B_SHIFT) | (aPixel << RGBA8888_A_SHIFT);
}
}
}
SurfaceBufferInfo GetSurfaceBufferInfo(sptr<SurfaceBuffer>& buffer)
{
SurfaceBufferInfo info;
bool cond = buffer == nullptr;
CHECK_ERROR_RETURN_RET_LOG(cond, info, "buffer get null source buffer");
OH_NativeBuffer_Planes *planes = nullptr;
info = {buffer->GetWidth(), buffer->GetHeight(), buffer->GetStride(),
static_cast<uint8_t*>(buffer->GetVirAddr()), buffer->GetSize(), buffer->GetStride(),
buffer->GetStride()};
auto pixelFmt = buffer->GetFormat();
uint32_t uvPlaneOffset = (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_420_SP || pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010) ?
PLANE_U : PLANE_V;
if ((buffer->GetPlanesInfo(reinterpret_cast<void**>(&planes)) == OHOS::SURFACE_ERROR_OK) &&
(planes != nullptr)) {
if (planes->planeCount > 1) {
info.uvOffset = planes->planes[uvPlaneOffset].offset;
}
}
return info;
}
void TruncateRGBA1010102ToRGBA8888(VpeSurfaceBuffers& buffers)
{
bool cond = buffers.hdr == nullptr || buffers.sdr == nullptr;
CHECK_ERROR_RETURN(cond);
SurfaceBufferInfo srcInfo = GetSurfaceBufferInfo(buffers.hdr);
SurfaceBufferInfo dstInfo = GetSurfaceBufferInfo(buffers.sdr);
IMAGE_LOGD("do TruncateRGBA1010102ToRGBA8888 srcInfo %{public}s", srcInfo.ToString().c_str());
IMAGE_LOGD("do TruncateRGBA1010102ToRGBA8888 outInfo %{public}s", dstInfo.ToString().c_str());
DoTruncateRGBA1010102ToRGBA8888(srcInfo, dstInfo);
}
void TruncateP010ToYUV420(VpeSurfaceBuffers& buffers)
{
SurfaceBufferInfo srcInfo = GetSurfaceBufferInfo(buffers.hdr);
SurfaceBufferInfo dstInfo = GetSurfaceBufferInfo(buffers.sdr);
IMAGE_LOGD("do TruncateP010ToYUV420 srcInfo %{public}s", srcInfo.ToString().c_str());
IMAGE_LOGD("do TruncateP010ToYUV420 outInfo %{public}s", dstInfo.ToString().c_str());
bool cond = buffers.hdr == nullptr || buffers.sdr == nullptr;
CHECK_ERROR_RETURN(cond);
DoTruncateP010ToYUV420(srcInfo, dstInfo);
}
int32_t VpeUtils::TruncateBuffer(VpeSurfaceBuffers& buffers, bool shouldCalDiff)
{
#ifdef IMAGE_VPE_FLAG
bool cond = buffers.hdr == nullptr || buffers.sdr == nullptr;
CHECK_ERROR_RETURN_RET(cond, VPE_ERROR_FAILED);
cond = buffers.hdr->GetWidth() != buffers.sdr->GetWidth() || buffers.hdr->GetHeight() != buffers.sdr->GetHeight();
CHECK_ERROR_RETURN_RET_LOG(cond, VPE_ERROR_FAILED, "TruncateBuffer get input of different sizes");
GraphicPixelFormat srcPixelFormat = static_cast<GraphicPixelFormat>(buffers.hdr->GetFormat());
if (shouldCalDiff) {
IMAGE_LOGE("do TruncateBuffer with unsupported format");
return VPE_ERROR_FAILED;
}
if (srcPixelFormat == GRAPHIC_PIXEL_FMT_YCRCB_P010 || srcPixelFormat == GRAPHIC_PIXEL_FMT_YCBCR_P010) {
TruncateP010ToYUV420(buffers);
} else if (srcPixelFormat == GRAPHIC_PIXEL_FMT_RGBA_1010102) {
TruncateRGBA1010102ToRGBA8888(buffers);
} else {
return VPE_ERROR_FAILED;
}
#endif
return VPE_ERROR_OK;
}
int32_t VpeUtils::ColorSpaceCalGainmap(VpeSurfaceBuffers& sb)
{
int32_t res = VPE_ERROR_OK;
#ifdef IMAGE_VPE_FLAG
std::lock_guard<std::mutex> lock(vpeMtx_);
CHECK_ERROR_RETURN_RET((dlHandler_ == nullptr || dlHandler_->GetSoHandle() == nullptr), VPE_ERROR_FAILED);
int32_t instanceId = VPE_ERROR_FAILED;
res = ColorSpaceConverterCreate(dlHandler_->GetSoHandle(), &instanceId);
CHECK_ERROR_RETURN_RET((instanceId == VPE_ERROR_FAILED || res != VPE_ERROR_OK), VPE_ERROR_FAILED);
CalGainmapImageT calGainmapImage = (CalGainmapImageT)dlsym(dlHandler_->GetSoHandle(),
"ColorSpaceConverterCalGainmap");
CHECK_ERROR_RETURN_RET(!calGainmapImage, VPE_ERROR_FAILED);
CHECK_ERROR_RETURN_RET((sb.sdr == nullptr || sb.gainmap == nullptr || sb.hdr == nullptr), VPE_ERROR_FAILED);
OHNativeWindowBuffer* sdr = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&sb.sdr);
OHNativeWindowBuffer* gainmap = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&sb.gainmap);
OHNativeWindowBuffer* hdr = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&sb.hdr);
res = calGainmapImage(instanceId, hdr, sdr, gainmap);
OH_NativeWindow_DestroyNativeWindowBuffer(sdr);
OH_NativeWindow_DestroyNativeWindowBuffer(gainmap);
OH_NativeWindow_DestroyNativeWindowBuffer(hdr);
ColorSpaceConverterDestory(dlHandler_->GetSoHandle(), &instanceId);
#endif
return res;
}
static GSError SetColorSpaceInfo(sptr<SurfaceBuffer>& buffer, const CM_ColorSpaceInfo& colorSpaceInfo)
{
if (buffer == nullptr) {
IMAGE_LOGE("%{public}s failed, buffer is nullptr", __func__);
return GSERROR_INVALID_ARGUMENTS;
}
std::vector<uint8_t> colorSpaceInfoVec;
auto ret = MetadataManager::ConvertMetadataToVec(colorSpaceInfo, colorSpaceInfoVec);
CHECK_ERROR_RETURN_RET(ret != GSERROR_OK, ret);
return buffer->SetMetadata(ATTRKEY_COLORSPACE_INFO, colorSpaceInfoVec);
}
bool VpeUtils::GetColorSpaceInfo(const sptr<SurfaceBuffer>& buffer, CM_ColorSpaceInfo& colorSpaceInfo)
{
std::vector<uint8_t> colorSpaceInfoVec;
auto ret = buffer->GetMetadata(ATTRKEY_COLORSPACE_INFO, colorSpaceInfoVec);
if (ret != GSERROR_OK) {
IMAGE_LOGD("GetColorSpaceInfo GetMetadata failed, return value is %{public}d", ret);
return false;
}
return MetadataManager::ConvertVecToMetadata(colorSpaceInfoVec, colorSpaceInfo) == GSERROR_OK;
}
bool VpeUtils::SetSbColorSpaceType(sptr<SurfaceBuffer>& buffer, const CM_ColorSpaceType& colorSpaceType)
{
CM_ColorSpaceInfo colorSpaceInfo;
uint32_t colorSpace = static_cast<uint32_t>(colorSpaceType);
colorSpaceInfo.primaries = static_cast<CM_ColorPrimaries>(colorSpace & CM_PRIMARIES_MASK);
colorSpaceInfo.transfunc = static_cast<CM_TransFunc>((colorSpace & CM_TRANSFUNC_MASK) >> TRANSFUNC_OFFSET);
colorSpaceInfo.matrix = static_cast<CM_Matrix>((colorSpace & CM_MATRIX_MASK) >> MATRIX_OFFSET);
colorSpaceInfo.range = static_cast<CM_Range>((colorSpace & CM_RANGE_MASK) >> RANGE_OFFSET);
auto ret = SetColorSpaceInfo(buffer, colorSpaceInfo);
if (ret != GSERROR_OK) {
IMAGE_LOGE("SetColorSpaceInfo GetMetadata failed, return value is %{public}d", ret);
return false;
}
return true;
}
bool VpeUtils::GetSbColorSpaceType(const sptr<SurfaceBuffer>& buffer, CM_ColorSpaceType& colorSpaceType)
{
CM_ColorSpaceInfo colorSpaceInfo;
if (!GetColorSpaceInfo(buffer, colorSpaceInfo)) {
return false;
}
uint32_t primaries = static_cast<uint32_t>(colorSpaceInfo.primaries);
uint32_t transfunc = static_cast<uint32_t>(colorSpaceInfo.transfunc);
uint32_t matrix = static_cast<uint32_t>(colorSpaceInfo.matrix);
uint32_t range = static_cast<uint32_t>(colorSpaceInfo.range);
colorSpaceType = static_cast<CM_ColorSpaceType>(primaries | (transfunc << TRANSFUNC_OFFSET) |
(matrix << MATRIX_OFFSET) | (range << RANGE_OFFSET));
return true;
}
bool VpeUtils::SetSbMetadataType(sptr<SurfaceBuffer>& buffer, const CM_HDR_Metadata_Type& metadataType)
{
if (buffer == nullptr) {
IMAGE_LOGE("%{public}s failed, buffer is nullptr", __func__);
return false;
}
std::vector<uint8_t> hdrMetadataTypeVec;
auto ret = MetadataManager::ConvertMetadataToVec(metadataType, hdrMetadataTypeVec);
CHECK_ERROR_RETURN_RET(ret != GSERROR_OK, false);
ret = buffer->SetMetadata(ATTRKEY_HDR_METADATA_TYPE, hdrMetadataTypeVec);
CHECK_ERROR_RETURN_RET(ret != GSERROR_OK, false);
return true;
}
bool VpeUtils::SetSbMetadataType(
sptr<SurfaceBuffer> &buffer, const HDI::Display::Graphic::Common::V2_2::CM_HDR_Metadata_Type &metadataType)
{
uint32_t outputMetadataType = static_cast<uint32_t>(metadataType);
IMAGE_LOGI("SetSbMetadataType outputMetadataType = %{public}d", outputMetadataType);
if (buffer == nullptr) {
IMAGE_LOGE("%{public}s failed, buffer is nullptr", __func__);
return false;
}
std::vector<uint8_t> hdrMetadataTypeVec;
auto ret = MetadataManager::ConvertMetadataToVec(metadataType, hdrMetadataTypeVec);
if (ret != GSERROR_OK) {
return false;
}
ret = buffer->SetMetadata(ATTRKEY_HDR_METADATA_TYPE, hdrMetadataTypeVec);
if (ret != GSERROR_OK) {
return false;
}
return true;
}
bool VpeUtils::GetSbMetadataType(const sptr<SurfaceBuffer>& buffer, CM_HDR_Metadata_Type& metadataType)
{
std::vector<uint8_t> hdrMetadataTypeVec;
auto ret = buffer->GetMetadata(ATTRKEY_HDR_METADATA_TYPE, hdrMetadataTypeVec);
CHECK_ERROR_RETURN_RET_LOG(ret != GSERROR_OK, false,
"HdrUtils::GetHDRMetadataType GetMetadata failed, return value is %{public}d", ret);
return MetadataManager::ConvertVecToMetadata(hdrMetadataTypeVec, metadataType) == GSERROR_OK;
}
bool VpeUtils::SetSbDynamicMetadata(sptr<SurfaceBuffer>& buffer, const std::vector<uint8_t>& dynamicMetadata)
{
return buffer->SetMetadata(ATTRKEY_HDR_DYNAMIC_METADATA, dynamicMetadata) == GSERROR_OK;
}
bool VpeUtils::GetSbDynamicMetadata(const sptr<SurfaceBuffer>& buffer, std::vector<uint8_t>& dynamicMetadata)
{
return buffer->GetMetadata(ATTRKEY_HDR_DYNAMIC_METADATA, dynamicMetadata) == GSERROR_OK;
}
bool VpeUtils::SetSbStaticMetadata(sptr<SurfaceBuffer>& buffer, const std::vector<uint8_t>& staticMetadata)
{
return buffer->SetMetadata(ATTRKEY_HDR_STATIC_METADATA, staticMetadata) == GSERROR_OK;
}
bool VpeUtils::GetSbStaticMetadata(const sptr<SurfaceBuffer>& buffer, std::vector<uint8_t>& staticMetadata)
{
return buffer->GetMetadata(ATTRKEY_HDR_STATIC_METADATA, staticMetadata) == GSERROR_OK;
}
static HDRVividExtendMetadata GetDefaultGainmapMetadata()
{
const float gainmapMax = 1.0f;
const float gainmapMin = 0.0f;
const float gamma = 1.0f;
const float offsetDenominator = 64.0;
const float baseOffset = 1.0 / offsetDenominator;
const float alternateOffset = 1.0 / offsetDenominator;
HDRVividExtendMetadata extendMetadata;
extendMetadata.metaISO.enhanceClippedThreholdMaxGainmap[INDEX_ZERO] = gainmapMax;
extendMetadata.metaISO.enhanceClippedThreholdMaxGainmap[INDEX_ONE] = gainmapMax;
extendMetadata.metaISO.enhanceClippedThreholdMaxGainmap[INDEX_TWO] = gainmapMax;
extendMetadata.metaISO.enhanceClippedThreholdMinGainmap[INDEX_ZERO] = gainmapMin;
extendMetadata.metaISO.enhanceClippedThreholdMinGainmap[INDEX_ONE] = gainmapMin;
extendMetadata.metaISO.enhanceClippedThreholdMinGainmap[INDEX_TWO] = gainmapMin;
extendMetadata.metaISO.enhanceMappingGamma[INDEX_ZERO] = gamma;
extendMetadata.metaISO.enhanceMappingGamma[INDEX_ONE] = gamma;
extendMetadata.metaISO.enhanceMappingGamma[INDEX_TWO] = gamma;
extendMetadata.metaISO.enhanceMappingBaselineOffset[INDEX_ZERO] = baseOffset;
extendMetadata.metaISO.enhanceMappingBaselineOffset[INDEX_ONE] = baseOffset;
extendMetadata.metaISO.enhanceMappingBaselineOffset[INDEX_TWO] = baseOffset;
extendMetadata.metaISO.enhanceMappingAlternateOffset[INDEX_ZERO] = alternateOffset;
extendMetadata.metaISO.enhanceMappingAlternateOffset[INDEX_ONE] = alternateOffset;
extendMetadata.metaISO.enhanceMappingAlternateOffset[INDEX_TWO] = alternateOffset;
extendMetadata.metaISO.gainmapChannelNum = 0x01;
extendMetadata.metaISO.useBaseColorFlag = 0x00;
extendMetadata.baseColorMeta.baseColorPrimary = COLORPRIMARIES_SRGB;
extendMetadata.gainmapColorMeta.combineColorPrimary = COLORPRIMARIES_BT2020;
extendMetadata.gainmapColorMeta.enhanceDataColorModel = COLORPRIMARIES_BT2020;
extendMetadata.gainmapColorMeta.alternateColorPrimary = COLORPRIMARIES_BT2020;
return extendMetadata;
}
static CM_HDR_Metadata_Type ConvertHdrType(ImageHdrType hdrType, bool isGainmap)
{
switch (hdrType) {
case ImageHdrType::HDR_VIVID_DUAL :
case ImageHdrType::HDR_CUVA :
return CM_IMAGE_HDR_VIVID_DUAL;
case ImageHdrType::HDR_ISO_DUAL :
return CM_IMAGE_HDR_ISO_DUAL;
default:
return CM_METADATA_NONE;
}
return CM_METADATA_NONE;
}
void VpeUtils::SetSurfaceBufferInfo(sptr<SurfaceBuffer>& buffer, bool isGainmap, ImageHdrType type,
CM_ColorSpaceType color, HdrMetadata& metadata)
{
CM_HDR_Metadata_Type cmHdrType = ConvertHdrType(type, isGainmap);
VpeUtils::SetSbMetadataType(buffer, cmHdrType);
VpeUtils::SetSbColorSpaceType(buffer, color);
if (type == ImageHdrType::HDR_CUVA) {
return;
}
if (!isGainmap) {
VpeUtils::SetSbDynamicMetadata(buffer, metadata.dynamicMetadata);
VpeUtils::SetSbStaticMetadata(buffer, metadata.staticMetadata);
return;
}
std::vector<uint8_t> extendMetadataVec(sizeof(HDRVividExtendMetadata));
int memCpyRes = 0;
if (metadata.extendMetaFlag) {
memCpyRes = memcpy_s(extendMetadataVec.data(), extendMetadataVec.size(),
&metadata.extendMeta, sizeof(HDRVividExtendMetadata));
} else {
HDRVividExtendMetadata defaultExtendMetadata = GetDefaultGainmapMetadata();
memCpyRes = memcpy_s(extendMetadataVec.data(), extendMetadataVec.size(),
&defaultExtendMetadata, sizeof(HDRVividExtendMetadata));
}
CHECK_ERROR_RETURN_LOG(memCpyRes != EOK, "SetSurfaceBufferInfo failed, memcpy_s error:%{public}d", memCpyRes);
VpeUtils::SetSbDynamicMetadata(buffer, extendMetadataVec);
}
int32_t VpeUtils::ColorSpaceConverterImageProcess(sptr<SurfaceBuffer> &input, sptr<SurfaceBuffer> &output)
{
std::lock_guard<std::mutex> lock(vpeMtx_);
CHECK_ERROR_RETURN_RET((dlHandler_ == nullptr || dlHandler_->GetSoHandle() == nullptr), VPE_ERROR_FAILED);
int32_t res;
int32_t instanceId = VPE_ERROR_FAILED;
res = ColorSpaceConverterCreate(dlHandler_->GetSoHandle(), &instanceId);
CHECK_ERROR_RETURN_RET((instanceId == VPE_ERROR_FAILED || res != VPE_ERROR_OK), VPE_ERROR_FAILED);
HdrProcessImageT hdrProcessImage = (HdrProcessImageT)dlsym(dlHandler_->GetSoHandle(),
"ColorSpaceConverterProcessImage");
CHECK_ERROR_RETURN_RET(!hdrProcessImage, VPE_ERROR_FAILED);
CHECK_ERROR_RETURN_RET((input == nullptr || output == nullptr), VPE_ERROR_FAILED);
OHNativeWindowBuffer* sdr = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&input);
OHNativeWindowBuffer* hdr = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&output);
res = hdrProcessImage(instanceId, sdr, hdr);
OH_NativeWindow_DestroyNativeWindowBuffer(sdr);
OH_NativeWindow_DestroyNativeWindowBuffer(hdr);
ColorSpaceConverterDestory(dlHandler_->GetSoHandle(), &instanceId);
return res;
}
int32_t VpeUtils::DetailEnhancerImageProcess(sptr<SurfaceBuffer> &input, sptr<SurfaceBuffer> &output, int32_t level)
{
std::lock_guard<std::mutex> lock(vpeMtx_);
CHECK_ERROR_RETURN_RET((dlHandler_ == nullptr || dlHandler_->GetSoHandle() == nullptr), VPE_ERROR_FAILED);
int32_t res;
int32_t instanceId = VPE_ERROR_FAILED;
res = DetailEnhancerCreate(dlHandler_->GetSoHandle(), &instanceId);
CHECK_ERROR_RETURN_RET((instanceId == VPE_ERROR_FAILED || res != VPE_ERROR_OK), VPE_ERROR_FAILED);
SrProcessImageT srProcessImage = (SrProcessImageT)dlsym(dlHandler_->GetSoHandle(), "DetailEnhancerProcessImage");
CHECK_ERROR_RETURN_RET(!srProcessImage, VPE_ERROR_FAILED);
CHECK_ERROR_RETURN_RET((input == nullptr || output == nullptr), VPE_ERROR_FAILED);
OHNativeWindowBuffer* inBuffer = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&input);
OHNativeWindowBuffer* outBuffer = OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer(&output);
res = srProcessImage(instanceId, inBuffer, outBuffer, level);
OH_NativeWindow_DestroyNativeWindowBuffer(inBuffer);
OH_NativeWindow_DestroyNativeWindowBuffer(outBuffer);
DetailEnhancerDestory(dlHandler_->GetSoHandle(), &instanceId);
return res;
}
bool VpeUtils::SetSbColorSpaceDefault(sptr<SurfaceBuffer>& buffer)
{
constexpr CM_ColorSpaceInfo outputColorSpaceInfo = {
COLORPRIMARIES_BT2020, TRANSFUNC_HLG, MATRIX_BT2020, RANGE_FULL
};
auto ret = SetColorSpaceInfo(buffer, outputColorSpaceInfo);
CHECK_ERROR_RETURN_RET_LOG(ret != GSERROR_OK, false,
"SetSbColorSpaceDefault GetMetadata failed, return value is %{public}d", ret);
return true;
}
void VpeUtils::SetSurfaceBufferInfo(sptr<SurfaceBuffer>& buffer, CM_ColorSpaceType color)
{
VpeUtils::SetSbColorSpaceType(buffer, color);
}
void VpeUtils::CopySurfaceBufferInfo(sptr<SurfaceBuffer>& source, sptr<SurfaceBuffer>& dst)
{
CHECK_ERROR_RETURN_LOG(source == nullptr || dst == nullptr,
"VpeUtils CopySurfaceBufferInfo failed, source or dst is nullptr");
std::vector<uint8_t> attrInfo{};
std::vector<uint32_t> keys{};
if (source->ListMetadataKeys(keys) == GSERROR_OK && !keys.empty()) {
for (size_t i = 0; i < keys.size(); i++) {
if (source->GetMetadata(keys[i], attrInfo) == GSERROR_OK && !attrInfo.empty()) {
IMAGE_LOGD("VpeUtils CopySurfaceBufferInfo Metadata key:%{public}d", keys[i]);
dst->SetMetadata(keys[i], attrInfo);
}
attrInfo.clear();
}
}
}
#endif
}
}