* Copyright (C) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "post_proc.h"
#include <memory>
#include <unistd.h>
#include "basic_transformer.h"
#include "image_log.h"
#include "image_system_properties.h"
#include "image_trace.h"
#include "image_type.h"
#include "image_utils.h"
#include "media_errors.h"
#include "memory_manager.h"
#include "pixel_yuv_utils.h"
#include "pixel_convert_adapter.h"
#ifndef _WIN32
#include "securec.h"
#else
#include "memory.h"
#endif
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
#include <sys/mman.h>
#include "ashmem.h"
#include "surface_buffer.h"
#include "vpe_utils.h"
#include "pixel_map_gl_utils.h"
#include "pixel_map_program_manager.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "libswscale/swscale.h"
#ifdef __cplusplus
};
#endif
#endif
#undef LOG_DOMAIN
#define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
#undef LOG_TAG
#define LOG_TAG "PostProc"
namespace OHOS {
namespace Media {
using namespace std;
constexpr uint32_t NEED_NEXT = 1;
constexpr float EPSILON = 1e-6;
constexpr uint8_t HALF = 2;
constexpr float HALF_F = 2;
constexpr int FFMPEG_NUM = 8;
constexpr int SLR_CACHE_CAPACITY = 256;
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
static const map<PixelFormat, AVPixelFormat> PIXEL_FORMAT_MAP = {
{ PixelFormat::ALPHA_8, AVPixelFormat::AV_PIX_FMT_GRAY8 },
{ PixelFormat::RGB_565, AVPixelFormat::AV_PIX_FMT_RGB565BE },
{ PixelFormat::RGB_888, AVPixelFormat::AV_PIX_FMT_RGB24 },
{ PixelFormat::RGBA_8888, AVPixelFormat::AV_PIX_FMT_RGBA },
{ PixelFormat::ARGB_8888, AVPixelFormat::AV_PIX_FMT_ARGB },
{ PixelFormat::BGRA_8888, AVPixelFormat::AV_PIX_FMT_BGRA },
{ PixelFormat::RGBA_F16, AVPixelFormat::AV_PIX_FMT_RGBA64BE },
{ PixelFormat::NV21, AVPixelFormat::AV_PIX_FMT_NV21 },
{ PixelFormat::NV12, AVPixelFormat::AV_PIX_FMT_NV12 },
};
#endif
uint32_t PostProc::DecodePostProc(const DecodeOptions &opts, PixelMap &pixelMap, FinalOutputStep finalOutputStep)
{
if (opts.cropAndScaleStrategy == CropAndScaleStrategy::SCALE_FIRST && opts.desiredSize.height > 0 &&
opts.desiredSize.width > 0) {
CHECK_ERROR_RETURN_RET_LOG(!ScalePixelMap(opts.desiredSize, pixelMap), ERR_IMAGE_TRANSFORM,
"[PostProc]scale:transform pixelMap failed");
CHECK_ERROR_RETURN_RET_LOG(pixelMap.crop(opts.CropRect) != SUCCESS, ERR_IMAGE_TRANSFORM,
"[PostProc]crop:transform pixelMap failed");
} else {
ImageInfo srcImageInfo;
pixelMap.GetImageInfo(srcImageInfo);
ImageInfo dstImageInfo;
GetDstImageInfo(opts, pixelMap, srcImageInfo, dstImageInfo);
uint32_t errorCode = ConvertProc(opts.CropRect, dstImageInfo, pixelMap, srcImageInfo);
CHECK_ERROR_RETURN_RET_LOG(errorCode != SUCCESS, errorCode,
"[PostProc]crop pixel map failed, errcode:%{public}u", errorCode);
}
bool cond = false;
decodeOpts_.allocatorType = opts.allocatorType;
bool isNeedRotate = !ImageUtils::FloatCompareZero(opts.rotateDegrees);
if (isNeedRotate) {
cond = !RotatePixelMap(opts.rotateDegrees, pixelMap);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_TRANSFORM, "[PostProc]rotate:transform pixel map failed");
}
decodeOpts_.allocatorType = opts.allocatorType;
if (opts.desiredSize.height > 0 && opts.desiredSize.width > 0 &&
opts.cropAndScaleStrategy != CropAndScaleStrategy::SCALE_FIRST) {
cond = !ScalePixelMap(opts.desiredSize, pixelMap);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_TRANSFORM, "[PostProc]scale:transform pixel map failed");
} else if (opts.cropAndScaleStrategy != CropAndScaleStrategy::SCALE_FIRST) {
ImageInfo info;
pixelMap.GetImageInfo(info);
if ((finalOutputStep == FinalOutputStep::DENSITY_CHANGE) && (info.baseDensity != 0)) {
int targetWidth = (pixelMap.GetWidth() * opts.fitDensity + (info.baseDensity >> 1)) / info.baseDensity;
int targetHeight = (pixelMap.GetHeight() * opts.fitDensity + (info.baseDensity >> 1)) / info.baseDensity;
Size size;
size.height = targetHeight;
size.width = targetWidth;
cond = !ScalePixelMap(size, pixelMap);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_TRANSFORM,
"[PostProc]density scale:transform pixel map failed");
info.baseDensity = opts.fitDensity;
pixelMap.SetImageInfo(info, true);
}
}
return SUCCESS;
}
void PostProc::GetDstImageInfo(const DecodeOptions &opts, PixelMap &pixelMap,
ImageInfo srcImageInfo, ImageInfo &dstImageInfo)
{
dstImageInfo.size = opts.desiredSize;
dstImageInfo.pixelFormat = opts.desiredPixelFormat;
dstImageInfo.baseDensity = srcImageInfo.baseDensity;
dstImageInfo.encodedFormat = srcImageInfo.encodedFormat;
decodeOpts_ = opts;
if (opts.desiredPixelFormat == PixelFormat::UNKNOWN) {
if (opts.preference == MemoryUsagePreference::LOW_RAM &&
srcImageInfo.alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) {
dstImageInfo.pixelFormat = PixelFormat::RGB_565;
} else {
dstImageInfo.pixelFormat = PixelFormat::RGBA_8888;
}
}
if (pixelMap.GetAlphaType() == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL) {
dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
} else {
dstImageInfo.alphaType = pixelMap.GetAlphaType();
}
}
bool PostProc::CenterScale(const Size &size, PixelMap &pixelMap)
{
int32_t srcWidth = pixelMap.GetWidth();
int32_t srcHeight = pixelMap.GetHeight();
int32_t targetWidth = size.width;
int32_t targetHeight = size.height;
bool cond = targetWidth <= 0 || targetHeight <= 0 || srcWidth <= 0 || srcHeight <= 0;
CHECK_ERROR_RETURN_RET_LOG(cond, false,
"[PostProc]params invalid, targetWidth:%{public}d, targetHeight:%{public}d, "
"srcWidth:%{public}d, srcHeight:%{public}d", targetWidth, targetHeight, srcWidth, srcHeight);
float widthScale = static_cast<float>(targetWidth) / static_cast<float>(srcWidth);
float heightScale = static_cast<float>(targetHeight) / static_cast<float>(srcHeight);
float scale = max(widthScale, heightScale);
if (pixelMap.IsAstc() && scale > 0) {
TransformData transformData;
pixelMap.GetTransformData(transformData);
transformData.scaleX *= scale;
transformData.scaleY *= scale;
transformData.cropLeft = (srcWidth - targetWidth / scale) / HALF_F;
transformData.cropTop = (srcHeight - targetHeight / scale) / HALF_F;
transformData.cropWidth = targetWidth / scale;
transformData.cropHeight = targetHeight / scale;
pixelMap.SetTransformData(transformData);
ImageInfo imageInfo;
pixelMap.GetImageInfo(imageInfo);
imageInfo.size.width = targetWidth;
imageInfo.size.height = targetHeight;
pixelMap.SetImageInfo(imageInfo, true);
return true;
}
cond = !ScalePixelMap(scale, scale, pixelMap);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "[PostProc]center scale pixelmap %{public}f fail", scale);
srcWidth = pixelMap.GetWidth();
srcHeight = pixelMap.GetHeight();
cond = srcWidth == targetWidth && srcHeight == targetHeight;
CHECK_ERROR_RETURN_RET(cond, true);
cond = srcWidth < targetWidth || srcHeight < targetHeight;
CHECK_ERROR_RETURN_RET_LOG(cond, false,
"[PostProc]src size [%{public}d, %{public}d] must less than dst size [%{public}d, %{public}d]",
srcWidth, srcHeight, targetWidth, targetHeight);
return CenterDisplay(pixelMap, srcWidth, srcHeight, targetWidth, targetHeight);
}
bool PostProc::CopyPixels(PixelMap& pixelMap, uint8_t* dstPixels, const Size& dstSize,
const int32_t srcWidth, const int32_t srcHeight,
int32_t srcRowStride, int32_t targetRowStride)
{
int32_t targetWidth = dstSize.width;
int32_t targetHeight = dstSize.height;
int32_t left = max(0, srcWidth - targetWidth) / HALF;
int32_t top = max(0, srcHeight - targetHeight) / HALF;
int32_t pixelBytes = pixelMap.GetPixelBytes();
uint8_t *dstStartPixel = nullptr;
uint8_t *srcStartPixel = nullptr;
int32_t targetRowBytes = targetWidth * pixelBytes;
if (targetRowStride <= 0) {
targetRowStride = targetRowBytes;
}
int32_t srcRowBytes = srcWidth * pixelBytes;
if (srcRowStride <= 0) {
srcRowStride = srcRowBytes;
}
uint8_t *srcPixels = const_cast<uint8_t *>(pixelMap.GetPixels());
bool cond = (srcPixels == nullptr);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "[PostProc]pixelMap data_ is nullptr");
srcPixels = srcPixels + top * srcRowStride + left * pixelBytes;
cond = std::min(srcWidth, targetWidth) != 0 &&
ImageUtils::CheckMulOverflow(std::min(srcWidth, targetWidth), pixelBytes);
CHECK_ERROR_RETURN_RET_LOG(cond, false,
"[PostProc]invalid params, srcWidth:%{public}d, targetWidth:%{public}d, pixelBytes:%{public}d",
srcWidth, targetWidth, pixelBytes);
uint32_t copyRowBytes = static_cast<uint32_t>(std::min(srcWidth, targetWidth) * pixelBytes);
for (int32_t scanLine = 0; scanLine < std::min(srcHeight, targetHeight); scanLine++) {
dstStartPixel = dstPixels + scanLine * targetRowStride;
srcStartPixel = srcPixels + scanLine * srcRowStride;
errno_t errRet = memcpy_s(dstStartPixel, static_cast<size_t>(targetRowBytes), srcStartPixel, copyRowBytes);
CHECK_ERROR_RETURN_RET_LOG(errRet != EOK, false,
"[PostProc]memcpy scanline %{public}d fail, errorCode = %{public}d", scanLine, errRet);
}
return true;
}
static int32_t GetUVStride(int32_t width)
{
return (width + 1) / HALF * HALF;
}
bool PostProc::CenterDisplayYuv(PixelMap &pixelMap, int32_t srcWidth, int32_t srcHeight,
int32_t targetWidth, int32_t targetHeight)
{
YUVDataInfo yuvInfo;
#if !defined(CROSS_PLATFORM)
ImageUtils::UpdateYUVDataInfo(pixelMap);
#endif
pixelMap.GetImageYUVInfo(yuvInfo);
ImageInfo imgInfo;
pixelMap.GetImageInfo(imgInfo);
YUVStrideInfo dstStrides;
void *srcBuffer = nullptr;
#if !defined(CROSS_PLATFORM)
if (pixelMap.GetAllocatorType() == AllocatorType::DMA_ALLOC) {
srcBuffer = reinterpret_cast<void *>(pixelMap.GetFd());
}
#endif
auto dstMemory = PixelYuvUtils::CreateYuvMemory(imgInfo.pixelFormat, "CenterDisplayYuv ImageData",
targetWidth, targetHeight, pixelMap.GetAllocatorType(), pixelMap.GetNoPaddingUsage(), srcBuffer, dstStrides);
bool cond = (dstMemory == nullptr) || (dstMemory->data.data == nullptr);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "CenterDisplayYuv CreateYuvMemory failed");
uint8_t *dstPixels = reinterpret_cast<uint8_t *>(dstMemory->data.data);
const uint8_t *srcPixels = const_cast<uint8_t *>(pixelMap.GetPixels());
int32_t left = max(0, srcWidth - targetWidth) / HALF;
int32_t top = max(0, srcHeight - targetHeight) / HALF;
int32_t dstYStride = static_cast<int32_t>(dstStrides.yStride);
int32_t srcYStride = static_cast<int32_t>(yuvInfo.yStride);
int32_t yCopyBytes = targetWidth;
for (int32_t row = 0; row < targetHeight; row++) {
uint8_t *dstRow = dstPixels + row * dstYStride;
const uint8_t *srcRow = srcPixels + yuvInfo.yOffset + (top + row) * srcYStride + left;
cond = memcpy_s(dstRow, dstYStride, srcRow, yCopyBytes) != EOK;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "[PostProc]CenterDisplayYuv Y memcpy failed at row %{public}d", row);
}
int32_t leftAligned = (left / HALF) * HALF;
int32_t topUV = top / HALF;
int32_t dstUvStride = static_cast<int32_t>(dstStrides.uvStride);
int32_t srcUVStride = static_cast<int32_t>(yuvInfo.uvStride);
int32_t uvCopyBytes = GetUVStride(targetWidth);
for (int32_t row = 0; row < (targetHeight + 1) / HALF; row++) {
uint8_t *dstRow = dstPixels + dstStrides.uvOffset + row * dstUvStride;
const uint8_t *srcRow = srcPixels + yuvInfo.uvOffset + (topUV + row) * srcUVStride + leftAligned;
cond = memcpy_s(dstRow, dstUvStride, srcRow, uvCopyBytes) != EOK;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "[PostProc]CenterDisplayYuv UV memcpy failed at row %{public}d", row);
}
pixelMap.SetPixelsAddr(dstMemory->data.data, dstMemory->extend.data, dstMemory->data.size,
dstMemory->GetType(), nullptr);
imgInfo.size.width = targetWidth;
imgInfo.size.height = targetHeight;
CHECK_ERROR_RETURN_RET_LOG(pixelMap.SetImageInfo(imgInfo, true) != SUCCESS, false, "update ImageInfo failed");
#if !defined(CROSS_PLATFORM)
ImageUtils::UpdateYUVDataInfo(pixelMap);
#endif
ImageUtils::FlushSurfaceBuffer(&pixelMap);
return true;
}
bool PostProc::CenterDisplay(PixelMap &pixelMap, int32_t srcWidth, int32_t srcHeight, int32_t targetWidth,
int32_t targetHeight)
{
ImageInfo dstImageInfo;
pixelMap.GetImageInfo(dstImageInfo);
if (dstImageInfo.pixelFormat == PixelFormat::NV12 || dstImageInfo.pixelFormat == PixelFormat::NV21) {
return CenterDisplayYuv(pixelMap, srcWidth, srcHeight, targetWidth, targetHeight);
}
int32_t srcRowStride = pixelMap.GetAllocatorType() == AllocatorType::DMA_ALLOC ? pixelMap.GetRowStride() : 0;
dstImageInfo.size.width = targetWidth;
dstImageInfo.size.height = targetHeight;
bool cond = false;
CHECK_ERROR_RETURN_RET_LOG(pixelMap.SetImageInfo(dstImageInfo, true) != SUCCESS, false, "update ImageInfo failed");
int32_t bufferSize = pixelMap.GetByteCount();
uint8_t *dstPixels = nullptr;
void *nativeBuffer = nullptr;
int fd = 0;
int targetRowStride = 0;
if (pixelMap.GetAllocatorType() == AllocatorType::HEAP_ALLOC) {
cond = !AllocHeapBuffer(bufferSize, &dstPixels);
CHECK_ERROR_RETURN_RET(cond, false);
} else if (pixelMap.GetAllocatorType() == AllocatorType::DMA_ALLOC) {
dstPixels = AllocDmaMemory(dstImageInfo, bufferSize, &nativeBuffer, targetRowStride);
} else {
dstPixels = AllocSharedMemory(dstImageInfo.size, bufferSize, fd, pixelMap.GetUniqueId());
}
cond = dstPixels == nullptr;
CHECK_ERROR_RETURN_RET_LOG(cond, false,
"[PostProc]CenterDisplay AllocMemory[%{public}d] failed", pixelMap.GetAllocatorType());
if (!CopyPixels(pixelMap, dstPixels, dstImageInfo.size, srcWidth, srcHeight, srcRowStride, targetRowStride)) {
IMAGE_LOGE("[PostProc]CopyPixels failed");
ReleaseBuffer(pixelMap.GetAllocatorType(), fd, bufferSize, &dstPixels, nativeBuffer);
return false;
}
void *fdBuffer = nullptr;
if (pixelMap.GetAllocatorType() == AllocatorType::HEAP_ALLOC) {
pixelMap.SetPixelsAddr(dstPixels, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr);
} else if (pixelMap.GetAllocatorType() == AllocatorType::DMA_ALLOC) {
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
sptr<SurfaceBuffer> sourceSurfaceBuffer(reinterpret_cast<SurfaceBuffer*> (pixelMap.GetFd()));
sptr<SurfaceBuffer> dstSurfaceBuffer(reinterpret_cast<SurfaceBuffer*> (nativeBuffer));
VpeUtils::CopySurfaceBufferInfo(sourceSurfaceBuffer, dstSurfaceBuffer);
#endif
pixelMap.SetPixelsAddr(dstPixels, nativeBuffer, bufferSize, AllocatorType::DMA_ALLOC, nullptr);
} else {
fdBuffer = new int32_t();
*static_cast<int32_t *>(fdBuffer) = fd;
pixelMap.SetPixelsAddr(dstPixels, fdBuffer, bufferSize, AllocatorType::SHARE_MEM_ALLOC, nullptr);
}
ImageUtils::FlushSurfaceBuffer(&pixelMap);
return true;
}
bool PostProc::ProcessScanlineFilter(ScanlineFilter &scanlineFilter, const Rect &cropRect, PixelMap &pixelMap,
uint8_t *resultData, uint32_t rowBytes)
{
auto srcData = pixelMap.GetPixels();
int32_t scanLine = 0;
while (scanLine < pixelMap.GetHeight()) {
FilterRowType filterRow = scanlineFilter.GetFilterRowType(scanLine);
if (filterRow == FilterRowType::NON_REFERENCE_ROW) {
scanLine++;
continue;
}
if (filterRow == FilterRowType::LAST_REFERENCE_ROW) {
break;
}
uint32_t ret = scanlineFilter.FilterLine(resultData + ((scanLine - cropRect.top) * rowBytes), rowBytes,
srcData + (scanLine * pixelMap.GetRowBytes()));
bool cond = ret != SUCCESS;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "[PostProc]scan line failed, ret:%{public}u", ret);
scanLine++;
}
return true;
}
uint32_t PostProc::CheckScanlineFilter(const Rect &cropRect, ImageInfo &dstImageInfo, PixelMap &pixelMap,
int32_t pixelBytes, ScanlineFilter &scanlineFilter)
{
bool cond = ImageUtils::CheckMulOverflow(dstImageInfo.size.width, dstImageInfo.size.height, pixelBytes);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_CROP,
"[PostProc]size is too large, width:%{public}d, height:%{public}d",
dstImageInfo.size.width, dstImageInfo.size.height);
uint64_t bufferSize = static_cast<uint64_t>(dstImageInfo.size.width) *
static_cast<uint64_t>(dstImageInfo.size.height) *
static_cast<uint64_t>(pixelBytes);
uint8_t *resultData = nullptr;
int fd = 0;
if (decodeOpts_.allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
resultData = AllocSharedMemory(dstImageInfo.size, bufferSize, fd, pixelMap.GetUniqueId());
bool cond = resultData == nullptr;
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_CROP, "[PostProc]AllocSharedMemory failed");
} else {
cond = !AllocHeapBuffer(bufferSize, &resultData);
CHECK_ERROR_RETURN_RET(cond, ERR_IMAGE_CROP);
}
if (ImageUtils::CheckMulOverflow(dstImageInfo.size.width, pixelBytes)) {
IMAGE_LOGE("[PostProc]size.width:%{public}d, is too large",
dstImageInfo.size.width);
ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
return ERR_IMAGE_CROP;
}
uint32_t rowBytes = pixelBytes * dstImageInfo.size.width;
if (!ProcessScanlineFilter(scanlineFilter, cropRect, pixelMap, resultData, rowBytes)) {
IMAGE_LOGE("[PostProc]ProcessScanlineFilter failed");
ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
return ERR_IMAGE_CROP;
}
uint32_t result = pixelMap.SetImageInfo(dstImageInfo);
if (result != SUCCESS) {
ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
return result;
}
if (decodeOpts_.allocatorType == AllocatorType::HEAP_ALLOC) {
pixelMap.SetPixelsAddr(resultData, nullptr, bufferSize, decodeOpts_.allocatorType, nullptr);
return result;
}
void *fdBuffer = new int32_t();
*static_cast<int32_t *>(fdBuffer) = fd;
pixelMap.SetPixelsAddr(resultData, fdBuffer, bufferSize, decodeOpts_.allocatorType, nullptr);
return result;
}
uint32_t PostProc::ConvertProc(const Rect &cropRect, ImageInfo &dstImageInfo, PixelMap &pixelMap,
ImageInfo &srcImageInfo)
{
bool hasPixelConvert = HasPixelConvert(srcImageInfo, dstImageInfo);
uint32_t ret = NeedScanlineFilter(cropRect, srcImageInfo.size, hasPixelConvert);
bool cond = ret != NEED_NEXT;
CHECK_ERROR_RETURN_RET(cond, ret);
if (GetCropValue(cropRect, srcImageInfo.size) == CropValue::NOCROP &&
dstImageInfo.pixelFormat == PixelFormat::ARGB_8888 && hasPixelConvert) {
IMAGE_LOGI("[PostProc]no need crop, only pixel convert.");
return PixelConvertProc(dstImageInfo, pixelMap, srcImageInfo);
}
ScanlineFilter scanlineFilter(srcImageInfo.pixelFormat);
SetScanlineCropAndConvert(cropRect, dstImageInfo, srcImageInfo, scanlineFilter, hasPixelConvert);
int32_t pixelBytes = ImageUtils::GetPixelBytes(dstImageInfo.pixelFormat);
cond = pixelBytes == 0;
CHECK_ERROR_RETURN_RET(cond, ERR_IMAGE_CROP);
cond = ImageUtils::CheckMulOverflow(dstImageInfo.size.width, dstImageInfo.size.height, pixelBytes);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_CROP,
"[PostProc]size.width:%{public}d, size.height:%{public}d is too large",
dstImageInfo.size.width, dstImageInfo.size.height);
return CheckScanlineFilter(cropRect, dstImageInfo, pixelMap, pixelBytes, scanlineFilter);
}
uint32_t PostProc::PixelConvertProc(ImageInfo &dstImageInfo, PixelMap &pixelMap,
ImageInfo &srcImageInfo)
{
uint32_t ret;
int fd = 0;
uint64_t bufferSize = 0;
uint8_t *resultData = nullptr;
dstImageInfo.size = srcImageInfo.size;
if (AllocBuffer(dstImageInfo, &resultData, bufferSize, fd, pixelMap.GetUniqueId()) != SUCCESS) {
ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
return ERR_IMAGE_CROP;
}
int32_t pixelBytes = ImageUtils::GetPixelBytes(srcImageInfo.pixelFormat);
if (pixelBytes == 0) {
ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
return ERR_IMAGE_CROP;
}
ret = pixelMap.SetImageInfo(dstImageInfo);
if (ret != SUCCESS) {
ReleaseBuffer(decodeOpts_.allocatorType, fd, bufferSize, &resultData);
return ret;
}
if (decodeOpts_.allocatorType == AllocatorType::HEAP_ALLOC) {
pixelMap.SetPixelsAddr(resultData, nullptr, bufferSize, decodeOpts_.allocatorType, nullptr);
return ret;
}
void *fdBuffer = new int32_t();
*static_cast<int32_t *>(fdBuffer) = fd;
pixelMap.SetPixelsAddr(resultData, fdBuffer, bufferSize, decodeOpts_.allocatorType, nullptr);
return ret;
}
uint32_t PostProc::AllocBuffer(ImageInfo imageInfo, uint8_t **resultData, uint64_t &bufferSize, int &fd, uint32_t id)
{
int32_t pixelBytes = ImageUtils::GetPixelBytes(imageInfo.pixelFormat);
bool cond = pixelBytes == 0;
CHECK_ERROR_RETURN_RET(cond, ERR_IMAGE_CROP);
cond = ImageUtils::CheckMulOverflow(imageInfo.size.width, imageInfo.size.height, pixelBytes);
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_CROP,
"[PostProc]size.width:%{public}d, size.height:%{public}d is too large",
imageInfo.size.width, imageInfo.size.height);
bufferSize = static_cast<uint64_t>(imageInfo.size.width) *
static_cast<uint64_t>(imageInfo.size.height) *
static_cast<uint64_t>(pixelBytes);
IMAGE_LOGD("[PostProc]size.width:%{public}d, size.height:%{public}d, bufferSize:%{public}lld",
imageInfo.size.width, imageInfo.size.height, static_cast<long long>(bufferSize));
if (decodeOpts_.allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
*resultData = AllocSharedMemory(imageInfo.size, bufferSize, fd, id);
cond = *resultData == nullptr;
CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_CROP, "[PostProc]AllocSharedMemory failed");
} else {
cond = !AllocHeapBuffer(bufferSize, resultData);
CHECK_ERROR_RETURN_RET(cond, ERR_IMAGE_CROP);
}
return SUCCESS;
}
bool PostProc::AllocHeapBuffer(uint64_t bufferSize, uint8_t **buffer)
{
bool cond = bufferSize == 0 || bufferSize > MALLOC_MAX_LENTH;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "[PostProc]Invalid value of bufferSize");
*buffer = static_cast<uint8_t *>(malloc(bufferSize));
CHECK_ERROR_RETURN_RET_LOG(*buffer == nullptr, false,
"[PostProc]alloc covert color buffersize[%{public}llu] failed.", static_cast<unsigned long long>(bufferSize));
#ifdef _WIN32
errno_t backRet = memset_s(*buffer, bufferSize, 0, bufferSize);
if (backRet != EOK) {
IMAGE_LOGE("[PostProc]memset convertData fail, errorCode = %{public}d", backRet);
ReleaseBuffer(AllocatorType::HEAP_ALLOC, 0, 0, buffer);
return false;
}
return true;
#else
errno_t errRet = memset_s(*buffer, bufferSize, 0, bufferSize);
if (errRet != EOK) {
IMAGE_LOGE("[PostProc]memset convertData fail, errorCode = %{public}d", errRet);
ReleaseBuffer(AllocatorType::HEAP_ALLOC, 0, 0, buffer);
return false;
}
return true;
#endif
}
uint8_t *PostProc::AllocSharedMemory(const Size &size, const uint64_t bufferSize, int &fd, uint32_t uniqueId)
{
#if defined(_WIN32) || defined(_APPLE) || defined(IOS_PLATFORM) || defined(ANDROID_PLATFORM)
return nullptr;
#else
std::string name = "Parcel RawData, uniqueId: " + std::to_string(getpid()) + '_' + std::to_string(uniqueId);
fd = AshmemCreate(name.c_str(), bufferSize);
CHECK_ERROR_RETURN_RET_LOG(fd < 0, nullptr, "[PostProc]AllocSharedMemory fd error, bufferSize %{public}lld",
static_cast<long long>(bufferSize));
int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
if (result < 0) {
IMAGE_LOGE("[PostProc]AshmemSetProt error");
::close(fd);
return nullptr;
}
void* ptr = ::mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) {
IMAGE_LOGE("[PostProc]mmap error, errno: %{public}s, fd %{public}d, bufferSize %{public}lld",
strerror(errno), fd, (long long)bufferSize);
::close(fd);
return nullptr;
}
return reinterpret_cast<uint8_t *>(ptr);
#endif
}
uint8_t *PostProc::AllocDmaMemory(ImageInfo info, const uint64_t bufferSize,
void **nativeBuffer, int &targetRowStride)
{
#if defined(_WIN32) || defined(_APPLE) || defined(IOS_PLATFORM) || defined(ANDROID_PLATFORM)
return nullptr;
#else
MemoryData memoryData = {nullptr, (uint32_t)bufferSize, "PostProc", {info.size.width, info.size.height}};
memoryData.format = info.pixelFormat;
auto dstMemory = MemoryManager::CreateMemory(AllocatorType::DMA_ALLOC, memoryData);
bool cond = dstMemory == nullptr;
CHECK_ERROR_RETURN_RET(cond, nullptr);
*nativeBuffer = dstMemory->extend.data;
auto sbBuffer = reinterpret_cast<SurfaceBuffer *>(dstMemory->extend.data);
targetRowStride = sbBuffer->GetStride();
return (uint8_t *)dstMemory->data.data;
#endif
}
void PostProc::ReleaseBuffer(AllocatorType allocatorType, int fd,
uint64_t dataSize, uint8_t **buffer, void *nativeBuffer)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
if (allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
if (*buffer != nullptr) {
::munmap(*buffer, dataSize);
::close(fd);
}
return;
}
if (allocatorType == AllocatorType::DMA_ALLOC) {
if (nativeBuffer != nullptr) {
int32_t err = ImageUtils::SurfaceBuffer_Unreference(static_cast<SurfaceBuffer*>(nativeBuffer));
CHECK_ERROR_PRINT_LOG(err != OHOS::GSERROR_OK, "PostProc NativeBufferReference failed");
}
return;
}
#endif
if (allocatorType == AllocatorType::HEAP_ALLOC) {
if (*buffer != nullptr) {
free(*buffer);
*buffer = nullptr;
}
return;
}
}
uint32_t PostProc::NeedScanlineFilter(const Rect &cropRect, const Size &srcSize, const bool &hasPixelConvert)
{
CropValue value = GetCropValue(cropRect, srcSize);
if (value == CropValue::NOCROP && !hasPixelConvert) {
IMAGE_LOGD("[PostProc]no need crop and pixel convert.");
return SUCCESS;
} else if (value == CropValue::INVALID) {
IMAGE_LOGE("[PostProc]invalid corp region, top:%{public}d, left:%{public}d, "
"width:%{public}d, height:%{public}d", cropRect.top, cropRect.left, cropRect.width, cropRect.height);
return ERR_IMAGE_CROP;
}
return NEED_NEXT;
}
void PostProc::ConvertPixelMapToPixmapInfo(PixelMap &pixelMap, PixmapInfo &pixmapInfo)
{
pixmapInfo.imageInfo.size.width = pixelMap.GetWidth();
pixmapInfo.imageInfo.size.height = pixelMap.GetHeight();
pixmapInfo.imageInfo.pixelFormat = pixelMap.GetPixelFormat();
pixmapInfo.imageInfo.colorSpace = pixelMap.GetColorSpace();
pixmapInfo.imageInfo.alphaType = pixelMap.GetAlphaType();
pixmapInfo.imageInfo.baseDensity = pixelMap.GetBaseDensity();
pixmapInfo.data = const_cast<uint8_t *>(pixelMap.GetPixels());
pixmapInfo.bufferSize = pixelMap.GetByteCount();
}
bool PostProc::RotatePixelMap(float rotateDegrees, PixelMap &pixelMap)
{
BasicTransformer trans;
PixmapInfo input(false);
ConvertPixelMapToPixmapInfo(pixelMap, input);
trans.SetRotateParam(rotateDegrees, static_cast<float>(input.imageInfo.size.width) * FHALF,
static_cast<float>(input.imageInfo.size.height) * FHALF);
return Transform(trans, input, pixelMap);
}
bool PostProc::ScalePixelMap(const Size &size, PixelMap &pixelMap)
{
int32_t srcWidth = pixelMap.GetWidth();
int32_t srcHeight = pixelMap.GetHeight();
bool cond = srcWidth <= 0 || srcHeight <= 0;
CHECK_ERROR_RETURN_RET_LOG(cond, false,
"[PostProc]src width:%{public}d, height:%{public}d is invalid.", srcWidth, srcHeight);
uint64_t dstBufferSizeOverflow =
static_cast<uint64_t>(size.width) * static_cast<uint64_t>(size.height) *
static_cast<uint64_t>(ImageUtils::GetPixelBytes(pixelMap.GetPixelFormat()));
CHECK_ERROR_RETURN_RET_LOG(dstBufferSizeOverflow > UINT_MAX, false, "[PostProc]target size too large");
float scaleX = static_cast<float>(size.width) / static_cast<float>(srcWidth);
float scaleY = static_cast<float>(size.height) / static_cast<float>(srcHeight);
return ScalePixelMap(scaleX, scaleY, pixelMap);
}
bool PostProc::ScalePixelMap(float scaleX, float scaleY, PixelMap &pixelMap)
{
bool cond = (fabs(scaleX - 1.0f) < EPSILON) && (fabs(scaleY - 1.0f) < EPSILON);
CHECK_ERROR_RETURN_RET(cond, true);
return pixelMap.resize(scaleX, scaleY);
}
bool PostProc::TranslatePixelMap(float tX, float tY, PixelMap &pixelMap)
{
BasicTransformer trans;
PixmapInfo input(false);
ConvertPixelMapToPixmapInfo(pixelMap, input);
trans.SetTranslateParam(tX, tY);
return Transform(trans, input, pixelMap);
}
static void ReleasePixmapBuffer(PixmapInfo &pixmap, AllocatorType allocatorType)
{
#if !defined(CROSS_PLATFORM)
if (allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
int *fd = static_cast<int *>(pixmap.context);
if (pixmap.data != nullptr) {
::munmap(pixmap.data, pixmap.bufferSize);
pixmap.data = nullptr;
}
if (fd != nullptr) {
::close(*fd);
delete fd;
pixmap.context = nullptr;
}
return;
}
#endif
pixmap.Destroy();
}
bool PostProc::Transform(BasicTransformer &trans, const PixmapInfo &input, PixelMap &pixelMap)
{
bool cond = pixelMap.IsTransformered();
CHECK_ERROR_RETURN_RET_LOG(cond, false, "[PostProc]Transform pixelmap is transforming");
pixelMap.SetTransformered(true);
PixmapInfo output(false);
output.uniqueId = pixelMap.GetUniqueId();
uint32_t ret;
if (decodeOpts_.allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
typedef uint8_t *(*AllocMemory)(const Size &size, const uint64_t bufferSize, int &fd, uint32_t uniqueId);
AllocMemory allcFunc = AllocSharedMemory;
ret = trans.TransformPixmap(input, output, allcFunc);
} else {
ret = trans.TransformPixmap(input, output);
}
if (ret != IMAGE_SUCCESS) {
ReleasePixmapBuffer(output, decodeOpts_.allocatorType);
pixelMap.SetTransformered(false);
return false;
}
if (pixelMap.SetImageInfo(output.imageInfo) != SUCCESS) {
ReleasePixmapBuffer(output, decodeOpts_.allocatorType);
pixelMap.SetTransformered(false);
return false;
}
pixelMap.SetPixelsAddr(output.data, output.context, output.bufferSize, decodeOpts_.allocatorType, nullptr);
pixelMap.SetTransformered(false);
return true;
}
CropValue PostProc::GetCropValue(const Rect &rect, const Size &size)
{
bool isSameSize = (rect.top == 0 && rect.left == 0 && rect.height == size.height && rect.width == size.width);
bool cond = !IsHasCrop(rect) || isSameSize;
CHECK_ERROR_RETURN_RET(cond, CropValue::NOCROP);
bool isValid = rect.top >= 0 && rect.width > 0 && rect.left >= 0 && rect.height > 0;
CHECK_ERROR_RETURN_RET(!isValid, CropValue::INVALID);
int32_t sum = 0;
CHECK_ERROR_RETURN_RET(__builtin_add_overflow(rect.top, rect.height, &sum), CropValue::INVALID);
CHECK_ERROR_RETURN_RET(sum > size.height, CropValue::INVALID);
CHECK_ERROR_RETURN_RET(__builtin_add_overflow(rect.left, rect.width, &sum), CropValue::INVALID);
CHECK_ERROR_RETURN_RET(sum > size.width, CropValue::INVALID);
return CropValue::VALID;
}
CropValue PostProc::ValidCropValue(Rect &rect, const Size &size)
{
CropValue res = GetCropValue(rect, size);
if (res == CropValue::INVALID) {
int sum = 0;
if (__builtin_add_overflow(rect.top, rect.height, &sum) || sum > size.height) {
rect.height = (rect.top < size.height) ? size.height - rect.top : 0;
}
if (__builtin_add_overflow(rect.left, rect.width, &sum) || sum > size.width) {
rect.width = (rect.left < size.width) ? size.width - rect.left : 0;
}
res = GetCropValue(rect, size);
}
return res;
}
bool PostProc::IsHasCrop(const Rect &rect)
{
return (rect.top != 0 || rect.left != 0 || rect.width != 0 || rect.height != 0);
}
bool PostProc::HasPixelConvert(const ImageInfo &srcImageInfo, ImageInfo &dstImageInfo)
{
dstImageInfo.alphaType = ImageUtils::GetValidAlphaTypeByFormat(dstImageInfo.alphaType, dstImageInfo.pixelFormat);
return (dstImageInfo.pixelFormat != srcImageInfo.pixelFormat || dstImageInfo.alphaType != srcImageInfo.alphaType);
}
void PostProc::SetScanlineCropAndConvert(const Rect &cropRect, ImageInfo &dstImageInfo, ImageInfo &srcImageInfo,
ScanlineFilter &scanlineFilter, bool hasPixelConvert)
{
if (hasPixelConvert) {
scanlineFilter.SetPixelConvert(srcImageInfo, dstImageInfo);
}
Rect srcRect = cropRect;
if (IsHasCrop(cropRect)) {
dstImageInfo.size.width = cropRect.width;
dstImageInfo.size.height = cropRect.height;
} else {
srcRect = { 0, 0, srcImageInfo.size.width, srcImageInfo.size.height };
dstImageInfo.size = srcImageInfo.size;
}
scanlineFilter.SetSrcRegion(srcRect);
}
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
bool GetScaleFormat(const PixelFormat &format, AVPixelFormat &pixelFormat)
{
if (format != PixelFormat::UNKNOWN) {
auto formatPair = PIXEL_FORMAT_MAP.find(format);
if (formatPair != PIXEL_FORMAT_MAP.end() && formatPair->second != 0) {
pixelFormat = formatPair->second;
return true;
}
}
return false;
}
int GetInterpolation(const AntiAliasingOption &option)
{
switch (option) {
case AntiAliasingOption::NONE:
return SWS_POINT;
case AntiAliasingOption::LOW:
return SWS_BILINEAR;
case AntiAliasingOption::MEDIUM:
return SWS_BICUBIC;
case AntiAliasingOption::HIGH:
return SWS_AREA;
case AntiAliasingOption::FAST_BILINEAER:
return SWS_FAST_BILINEAR;
case AntiAliasingOption::BICUBLIN:
return SWS_BICUBLIN;
case AntiAliasingOption::GAUSS:
return SWS_GAUSS;
case AntiAliasingOption::SINC:
return SWS_SINC;
case AntiAliasingOption::LANCZOS:
return SWS_LANCZOS;
case AntiAliasingOption::SPLINE:
return SWS_SPLINE;
default:
return SWS_POINT;
}
}
static SkSLRCacheMgr GetNewSkSLRCacheMgr()
{
static SkMutex slrMutex;
static SLRLRUCache slrCache(SLR_CACHE_CAPACITY);
return SkSLRCacheMgr(slrCache, slrMutex);
}
std::shared_ptr<SLRWeightTuple> initSLRFactor(Size srcSize, Size dstSize)
{
bool cond = srcSize.width == 0 || srcSize.height == 0 || dstSize.width == 0 || dstSize.height == 0;
CHECK_ERROR_RETURN_RET_LOG(cond, nullptr,
"initSLRFactor invalid size, %{public}d, %{public}d, %{public}d, %{public}d",
srcSize.width, srcSize.height, dstSize.width, dstSize.height);
SkSLRCacheMgr cacheMgr = GetNewSkSLRCacheMgr();
SLRWeightKey key(srcSize, dstSize);
std::shared_ptr<SLRWeightTuple> weightTuplePtr = cacheMgr.find(key.fKey);
if (weightTuplePtr != nullptr) {
const SLRWeightKey& cachedKey = std::get<2>(*weightTuplePtr);
if (cachedKey.Match(srcSize, dstSize)) {
return weightTuplePtr;
}
IMAGE_LOGW("initSLRFactor hash collision, cached:%{public}d x %{public}d -> %{public}d x %{public}d, "
"requested:%{public}d x %{public}d -> %{public}d x %{public}d, key:%{public}u",
cachedKey.src_.width, cachedKey.src_.height, cachedKey.dst_.width, cachedKey.dst_.height,
srcSize.width, srcSize.height, dstSize.width, dstSize.height, key.fKey);
}
SLRWeightMat slrWeightX = SLRProc::GetWeights(static_cast<float>(dstSize.width) / srcSize.width,
static_cast<int>(dstSize.width));
SLRWeightMat slrWeightY = SLRProc::GetWeights(static_cast<float>(dstSize.height) / srcSize.height,
static_cast<int>(dstSize.height));
SLRWeightTuple value{slrWeightX, slrWeightY, key};
std::shared_ptr<SLRWeightTuple> weightPtr = std::make_shared<SLRWeightTuple>(value);
cacheMgr.insert(key.fKey, weightPtr);
IMAGE_LOGI("initSLRFactor insert:%{public}d", key.fKey);
return weightPtr;
}
bool CheckPixelMapSLR(const Size &desiredSize, PixelMap &pixelMap)
{
ImageInfo imgInfo;
pixelMap.GetImageInfo(imgInfo);
bool cond = imgInfo.pixelFormat != PixelFormat::RGBA_8888 && imgInfo.pixelFormat != PixelFormat::BGRA_8888;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "CheckPixelMapSLR only support RGBA_8888 format");
int32_t srcWidth = pixelMap.GetWidth();
int32_t srcHeight = pixelMap.GetHeight();
cond = srcWidth <= 0 || srcHeight <= 0 || !pixelMap.GetWritablePixels();
CHECK_ERROR_RETURN_RET_LOG(cond, false,
"CheckPixelMapSLR invalid src size, %{public}d, %{public}d", srcWidth, srcHeight);
cond = desiredSize.width <= 0 || desiredSize.height <= 0;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "CheckPixelMapSLR invalid desired size, %{public}d, %{public}d",
desiredSize.width, desiredSize.height);
cond = desiredSize.width == srcWidth && desiredSize.height == srcHeight;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "CheckPixelMapSLR same source and desired size, %{public}d, %{public}d",
desiredSize.width, desiredSize.height);
cond = static_cast<float>(desiredSize.width) / srcWidth < EPSILON ||
static_cast<float>(desiredSize.height) / srcHeight < EPSILON;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "CheckPixelMapSLR scaling factor overflow");
int32_t pixelBytes = pixelMap.GetPixelBytes();
CHECK_ERROR_RETURN_RET_LOG(pixelBytes <= 0, false, "CheckPixelMapSLR invalid pixel bytes, %{public}d", pixelBytes);
uint64_t dstSizeOverflow =
static_cast<uint64_t>(desiredSize.width) * static_cast<uint64_t>(desiredSize.height) *
static_cast<uint64_t>(pixelBytes);
CHECK_ERROR_RETURN_RET_LOG(dstSizeOverflow > UINT_MAX, false, "ScalePixelMapWithSLR desired size overflow");
return true;
}
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
static int g_minSize = 512;
static constexpr int g_maxTextureSize = 8192;
static bool CheckPixelMapSLR(PixelMap &pixelMap, const Size &desiredSize, GPUTransformData &trans)
{
ImageInfo imgInfo;
pixelMap.GetImageInfo(imgInfo);
bool cond = imgInfo.pixelFormat != PixelFormat::RGBA_8888;
CHECK_ERROR_RETURN_RET_LOG(cond, false,
"slr_gpu CheckPixelMapSLR only support RGBA_8888 format %{public}d", imgInfo.pixelFormat);
int32_t srcWidth = pixelMap.GetWidth();
int32_t srcHeight = pixelMap.GetHeight();
cond = srcWidth <= 0 || srcHeight <= 0 || !pixelMap.GetWritablePixels();
CHECK_ERROR_RETURN_RET_LOG(cond, false,
"slr_gpu CheckPixelMapSLR invalid src size, %{public}d, %{public}d", srcWidth, srcHeight);
cond = desiredSize.width <= 0 || desiredSize.height <= 0;
CHECK_ERROR_RETURN_RET_LOG(cond, false,
"slr_gpu CheckPixelMapSLR invalid desired size, %{public}d, %{public}d",
desiredSize.width, desiredSize.height);
int32_t pixelBytes = pixelMap.GetPixelBytes();
cond = pixelBytes <= 0;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "slr_gpu CheckPixelMapSLR invalid pixel bytes, %{public}d", pixelBytes);
cond = srcWidth > g_maxTextureSize || srcHeight > g_maxTextureSize;
CHECK_INFO_RETURN_RET_LOG(cond, false,
"slr_gpu CheckPixelMapSLR The maximum width and height cannot exceed:%{public}d.", g_maxTextureSize);
uint64_t dstSizeOverflow = static_cast<uint64_t>(desiredSize.width) * static_cast<uint64_t>(desiredSize.height) *
static_cast<uint64_t>(pixelBytes);
cond = dstSizeOverflow > UINT_MAX;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "slr_gpu ScalePixelMapWithSLR desired size overflow");
cond = trans.transformationType == TransformationType::SCALE &&
(srcWidth <= desiredSize.width || srcHeight <= desiredSize.height);
CHECK_INFO_RETURN_RET_LOG(cond, false,
"slr_gpu CheckPixelMapSLR failed. Only zoom-out is supported.");
cond = trans.transformationType == TransformationType::SCALE &&
(srcWidth * srcHeight < g_minSize * g_minSize);
CHECK_INFO_RETURN_RET_LOG(cond, false,
"slr_gpu CheckPixelMapSLR failed. srcWidth * srcHeight < minSize * minSize.");
cond = trans.transformationType == TransformationType::ROTATE &&
!(std::fabs(std::fmod(trans.rotateDegreeZ, 90.f)) < 1e-6);
CHECK_INFO_RETURN_RET_LOG(cond, false, "slr_gpu CheckPixelMapSLR failed. Only 90* is supported.");
return true;
}
static void GetPixelMapInfo(PixelMap &source, Size &size, GLenum &glFormat, int &perPixelSize)
{
size = {
.width = source.GetWidth(),
.height = source.GetHeight(),
};
glFormat = GL_RGBA;
perPixelSize = ImageUtils::GetPixelBytes(PixelFormat::RGBA_8888);
PixelFormat originFormat = source.GetPixelFormat();
switch (originFormat) {
case PixelFormat::RGBA_8888:
glFormat = GL_RGBA;
break;
case PixelFormat::RGB_565:
glFormat = GL_RGB565;
perPixelSize = ImageUtils::GetPixelBytes(PixelFormat::RGB_565);
break;
case PixelFormat::RGB_888:
glFormat = GL_RGB;
perPixelSize = ImageUtils::GetPixelBytes(PixelFormat::RGB_888);
break;
case PixelFormat::BGRA_8888:
glFormat = GL_BGRA_EXT;
break;
case PixelFormat::ALPHA_8:
glFormat = GL_ALPHA8_EXT;
perPixelSize = ImageUtils::GetPixelBytes(PixelFormat::ALPHA_8);
break;
default:
IMAGE_LOGE("slr_gpu %{public}s format %{public}d is not support! ", __func__, originFormat);
break;
}
}
static bool PixelMapPostProcWithGL(PixelMap &sourcePixelMap, GPUTransformData &trans, bool needHighQuality)
{
Size &desiredSize = trans.targetInfo_.size;
bool cond = !CheckPixelMapSLR(sourcePixelMap, trans.targetInfo_.size, trans);
CHECK_ERROR_RETURN_RET(cond, false);
Size sourceSize;
GLenum glFormat = GL_RGBA;
int perPixelSize = ImageUtils::GetPixelBytes(sourcePixelMap.GetPixelFormat());
GetPixelMapInfo(sourcePixelMap, sourceSize, glFormat, perPixelSize);
ImageTrace imageTrace("PixelMapPostProcWithGL (%d, %d)=>(%d, %d) stride %d type %d transtype:%d",
sourceSize.width, sourceSize.height, desiredSize.width, desiredSize.height,
sourcePixelMap.GetRowStride(), static_cast<int>(sourcePixelMap.GetAllocatorType()),
static_cast<int>(trans.transformationType));
IMAGE_LOGI("slr_gpu PixelMapPostProcWithGL uniqueId:%{public}d AllocatorType:%{public}d "
"size (%{public}d, %{public}d)=>(%{public}d, %{public}d) stride %{public}d transtype:%{public}d",
sourcePixelMap.GetUniqueId(), static_cast<int>(sourcePixelMap.GetAllocatorType()), sourceSize.width,
sourceSize.height, desiredSize.width, desiredSize.height, sourcePixelMap.GetRowStride(),
static_cast<int>(trans.transformationType));
AllocatorType allocType = sourcePixelMap.GetAllocatorType();
const uint64_t noPaddingUsage = sourcePixelMap.GetNoPaddingUsage();
const auto dmaMode = PixelMapGlUtils::ResolveDmaTransferMode(allocType, noPaddingUsage);
if (dmaMode.isSourceDma && !dmaMode.isTargetDma) {
IMAGE_LOGI("slr_gpu PixelMapPostProcWithGL no-padding DMA does not support GPU writeback, fallback output");
}
size_t buffersize = static_cast<uint64_t>(desiredSize.width) * static_cast<uint64_t>(desiredSize.height) * 4;
MemoryData memoryData = {nullptr, buffersize, "PixelMapPostProcWithGL", desiredSize};
memoryData.usage = noPaddingUsage;
std::unique_ptr<AbsMemory> dstMemory = MemoryManager::CreateMemory(dmaMode.outputAllocType, memoryData);
cond = dstMemory == nullptr || dstMemory->data.data == nullptr;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "slr_gpu PixelMapPostProcWithGL dstMemory is null");
int outputStride = 4 * desiredSize.width;
if (dmaMode.isTargetDma) {
SurfaceBuffer* sbBuffer = reinterpret_cast<SurfaceBuffer*>(dstMemory->extend.data);
outputStride = sbBuffer->GetStride();
buffersize = static_cast<uint32_t>(static_cast<uint64_t>(sbBuffer->GetStride()) *
static_cast<uint64_t>(desiredSize.height));
}
PixelMapProgramManager::BuildShader();
bool ret = true;
auto program = PixelMapProgramManager::GetInstance().GetProgram();
if (program == nullptr) {
IMAGE_LOGE("slr_gpu PixelMapPostProcWithGL %{public}s create gl context failed", __func__);
ret = false;
} else {
trans.targetInfo_.stride = outputStride;
trans.targetInfo_.pixelBytes = perPixelSize;
trans.targetInfo_.outdata = dstMemory->data.data;
trans.targetInfo_.context = dstMemory->extend.data;
trans.glFormat = glFormat;
trans.isSourceDma = dmaMode.isSourceDma;
trans.isTargetDma = dmaMode.isTargetDma;
trans.isDma = dmaMode.isDma;
program->SetGPUTransformData(trans);
ret = PixelMapProgramManager::GetInstance().ExecutProgram(program);
}
if (!ret) {
dstMemory->Release();
IMAGE_LOGE("slr_gpu PixelMapPostProcWithGL Resize failed");
return false;
}
sourcePixelMap.SetPixelsAddr(dstMemory->data.data, dstMemory->extend.data,
static_cast<uint64_t>(desiredSize.height) * static_cast<uint64_t>(outputStride),
dmaMode.outputAllocType, nullptr);
ImageInfo info;
info.size = desiredSize;
info.pixelFormat = PixelFormat::RGBA_8888;
info.alphaType = AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL;
sourcePixelMap.SetImageInfo(info, true);
return true;
}
#endif
bool PostProc::RotateInRectangularSteps(PixelMap &pixelMap, float degrees, bool useGpu)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
float oldDegrees = degrees;
if (useGpu && ImageSystemProperties::GetGenThumbWithGpu() &&
ImageSystemProperties::UseGPUScalingCapabilities() &&
std::fabs(std::fmod(degrees, 90.f)) < 1e-6) {
ImageTrace imageTrace("RotateInRectangularSteps:%f", degrees);
IMAGE_LOGI("slr_gpu RotateInRectangularSteps in :%{public}f", degrees);
GPUTransformData gpuTransform;
ImageInfo imageInfo;
pixelMap.GetImageInfo(imageInfo);
GlCommon::Mat4 tmpMat4;
std::array<float, 3> axis = { 0.0f, 0.0f, 1.0f };
float angle = degrees * M_PI / 180.f;
gpuTransform.targetInfo_.size = {
std::abs(imageInfo.size.width * std::cos(angle)) + std::abs(imageInfo.size.height * std::sin(angle)),
std::abs(imageInfo.size.height * std::cos(angle)) + std::abs(imageInfo.size.width * std::sin(angle))
};
degrees = std::fmod(degrees, 360.f);
degrees = std::fmod(360.f - degrees, 360.f);
gpuTransform.rotateTrans = GlCommon::Mat4(tmpMat4, degrees, axis);
gpuTransform.rotateDegreeZ = degrees;
gpuTransform.sourceInfo_ = {
.size = imageInfo.size,
.stride = pixelMap.GetRowStride(),
.pixelBytes = ImageUtils::GetPixelBytes(pixelMap.GetPixelFormat()),
.addr = pixelMap.GetPixels(),
.context = pixelMap.GetFd(),
};
gpuTransform.transformationType = TransformationType::ROTATE;
if (PixelMapPostProcWithGL(pixelMap, gpuTransform, true)) {
IMAGE_LOGI("slr_gpu RotateInRectangularSteps success");
return true;
}
IMAGE_LOGI("slr_gpu RotateInRectangularSteps rotate with cpu");
}
#endif
pixelMap.rotate(oldDegrees);
return true;
}
bool PostProc::ScalePixelMapWithGPU(PixelMap &pixelMap, const Size &desiredSize,
const AntiAliasingOption &option, bool useGpu)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
if (useGpu && ImageSystemProperties::GetGenThumbWithGpu() &&
ImageSystemProperties::UseGPUScalingCapabilities() &&
option == AntiAliasingOption::HIGH) {
ImageTrace imageTrace("ScalePixelMapWithGPU:wh(%d,%d)->(%d,%d)",
pixelMap.GetWidth(), pixelMap.GetHeight(), desiredSize.width, desiredSize.height);
IMAGE_LOGI("slr_gpu ScalePixelMapWithGPU:wh(%{public}d,%{public}d)->(%{public}d,%{public}d)",
pixelMap.GetWidth(), pixelMap.GetHeight(), desiredSize.width, desiredSize.height);
GPUTransformData gpuTransform;
gpuTransform.targetInfo_.size = desiredSize;
ImageInfo imageInfo;
pixelMap.GetImageInfo(imageInfo);
gpuTransform.sourceInfo_ = {
.size = imageInfo.size,
.stride = pixelMap.GetRowStride(),
.pixelBytes = ImageUtils::GetPixelBytes(pixelMap.GetPixelFormat()),
.addr = pixelMap.GetPixels(),
.context = pixelMap.GetFd(),
};
gpuTransform.transformationType = TransformationType::SCALE;
if (PixelMapPostProcWithGL(pixelMap, gpuTransform, true)) {
IMAGE_LOGI("slr_gpu ScalePixelMapWithGPU success");
return true;
}
IMAGE_LOGI("slr_gpu ScalePixelMapWithGPU failed scale with cpu");
}
#endif
PostProc postProc;
return postProc.ScalePixelMapEx(desiredSize, pixelMap, option);
}
static std::unique_ptr<AbsMemory> CreateSLRMemory(PixelMap &pixelMap, uint32_t dstBufferSize, const Size &desiredSize,
std::unique_ptr<AbsMemory> &dstMemory, bool useLap)
{
AllocatorType allocatorType = pixelMap.GetAllocatorType();
if (useLap && allocatorType == AllocatorType::DMA_ALLOC) {
allocatorType = AllocatorType::SHARE_MEM_ALLOC;
}
MemoryData memoryData = {nullptr, dstBufferSize, "ScalePixelMapWithSLR ImageData", desiredSize,
pixelMap.GetPixelFormat()};
memoryData.usage = pixelMap.GetNoPaddingUsage();
dstMemory = MemoryManager::CreateMemory(allocatorType, memoryData);
CHECK_ERROR_RETURN_RET_LOG(dstMemory == nullptr, nullptr, "ScalePixelMapWithSLR create dstMemory failed");
std::unique_ptr<AbsMemory> lapMemory = nullptr;
if (useLap) {
MemoryData lapMemoryData = {nullptr, dstBufferSize, "ScalePixelMapWithSLR ImageData Lap", desiredSize,
pixelMap.GetPixelFormat()};
lapMemoryData.usage = pixelMap.GetNoPaddingUsage();
lapMemory = MemoryManager::CreateMemory(pixelMap.GetAllocatorType(), lapMemoryData);
if (lapMemory == nullptr) {
IMAGE_LOGE("ScalePixelMapWithSLR create lapMemory failed");
dstMemory->Release();
return nullptr;
}
}
return lapMemory;
}
float getLapFactor(const ImageInfo& imgInfo, const Size &desiredSize)
{
float coeff = ((float)desiredSize.width) / imgInfo.size.width;
if (coeff > 0.8f) {
return .0f;
}
if (coeff > 0.6f) {
return 0.06f;
}
if (coeff > 0.5f) {
return 0.1f;
}
return 0.15f;
}
struct SLRContext {
void *data;
bool useLap;
};
bool ExecuteSLR(PixelMap& pixelMap, const Size& desiredSize, SLRMat &src, SLRMat &dst,
SLRContext scalingContext)
{
ImageInfo imgInfo;
pixelMap.GetImageInfo(imgInfo);
std::shared_ptr<SLRWeightTuple> weightTuplePtr = initSLRFactor(imgInfo.size, desiredSize);
CHECK_ERROR_RETURN_RET_LOG(weightTuplePtr == nullptr, false, "PostProcExecuteSLR init failed");
SLRWeightMat slrWeightX = std::get<0>(*weightTuplePtr);
SLRWeightMat slrWeightY = std::get<1>(*weightTuplePtr);
if (ImageSystemProperties::GetSLRParallelEnabled()) {
SLRProc::Parallel(src, dst, slrWeightX, slrWeightY);
} else {
SLRProc::Serial(src, dst, slrWeightX, slrWeightY);
}
if (scalingContext.useLap) {
float factor = getLapFactor(imgInfo, desiredSize);
SLRProc::Laplacian(dst, scalingContext.data, factor);
}
return true;
}
bool PostProc::ScalePixelMapWithSLR(const Size &desiredSize, PixelMap &pixelMap, bool useLap)
{
ImageInfo imgInfo;
pixelMap.GetImageInfo(imgInfo);
bool cond = !CheckPixelMapSLR(desiredSize, pixelMap);
CHECK_ERROR_RETURN_RET(cond, false);
useLap = useLap && ImageSystemProperties::GetSLRLaplacianEnabled();
ImageTrace imageTrace("ScalePixelMapWithSLR");
int32_t pixelBytes = pixelMap.GetPixelBytes();
SLRMat src(imgInfo.size, imgInfo.pixelFormat, pixelMap.GetWritablePixels(), pixelMap.GetRowStride() / pixelBytes);
uint32_t dstBufferSize = desiredSize.height * desiredSize.width * pixelBytes;
std::unique_ptr<AbsMemory> m = nullptr;
auto lapMemory = CreateSLRMemory(pixelMap, dstBufferSize, desiredSize, m, useLap);
cond = m == nullptr || (useLap && (lapMemory == nullptr));
CHECK_ERROR_RETURN_RET_LOG(cond, false, "pixelMap scale slr memory nullptr");
size_t rowStride;
if (m->GetType() == AllocatorType::DMA_ALLOC) {
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
rowStride = reinterpret_cast<SurfaceBuffer*>(m->extend.data)->GetStride();
#endif
} else {
rowStride = desiredSize.width * pixelBytes;
}
void *data = useLap ? lapMemory->data.data : m->data.data;
SLRMat dst({desiredSize.width, desiredSize.height}, imgInfo.pixelFormat, data, rowStride / pixelBytes);
if (!ExecuteSLR(pixelMap, desiredSize, src, dst, {m->data.data, useLap})) {
m->Release();
if (useLap && lapMemory) {
lapMemory->Release();
}
return false;
}
pixelMap.SetPixelsAddr(m->data.data, m->extend.data, dstBufferSize, m->GetType(), nullptr);
imgInfo.size = desiredSize;
pixelMap.SetImageInfo(imgInfo, true);
if (m->GetType() == AllocatorType::DMA_ALLOC) {
ImageUtils::FlushSurfaceBuffer(&pixelMap);
}
if (lapMemory) {
lapMemory->Release();
}
return true;
}
bool PostProc::ScalePixelMapEx(const Size &desiredSize, PixelMap &pixelMap, const AntiAliasingOption &option)
{
ImageTrace imageTrace("PixelMap ScalePixelMapEx, srcSize[%d, %d], dstSize[%d, %d] ",
pixelMap.GetWidth(), pixelMap.GetHeight(), desiredSize.width, desiredSize.height);
IMAGE_LOGI("slr_gpu ScalePixelMapEx pixelMap: width = %{public}d, height = %{public}d, pixelFormat = %{public}d, "
"allocatorType = %{public}d; desiredSize: width = %{public}d, height = %{public}d",
pixelMap.GetWidth(), pixelMap.GetHeight(), pixelMap.GetPixelFormat(),
pixelMap.GetAllocatorType(), desiredSize.width, desiredSize.height);
ImageInfo imgInfo;
pixelMap.GetImageInfo(imgInfo);
int32_t srcWidth = pixelMap.GetWidth();
int32_t srcHeight = pixelMap.GetHeight();
bool cond = srcWidth <= 0 || srcHeight <= 0 || !pixelMap.GetWritablePixels() ||
desiredSize.width <= 0 || desiredSize.height <= 0;
CHECK_ERROR_RETURN_RET_LOG(cond, false,
"pixelMap param is invalid, src[%{public}d,%{public}d], desired[%{public}d,%{public}d]",
srcWidth, srcHeight, desiredSize.width, desiredSize.height);
if (srcWidth == desiredSize.width && srcHeight == desiredSize.height) {
IMAGE_LOGI("No need to scale, dstSize is equal to srcSize.");
return true;
}
AVPixelFormat pixelFormat;
cond = !GetScaleFormat(imgInfo.pixelFormat, pixelFormat);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "pixelMap format is invalid, format: %{public}d", imgInfo.pixelFormat);
uint64_t dstBufferSizeOverflow =
static_cast<uint64_t>(desiredSize.width) * static_cast<uint64_t>(desiredSize.height) *
static_cast<uint64_t>(ImageUtils::GetPixelBytes(imgInfo.pixelFormat));
CHECK_ERROR_RETURN_RET_LOG(dstBufferSizeOverflow > UINT_MAX, false, "ScalePixelMapEx target size too large");
if (ImageUtils::IsYuvFormat(imgInfo.pixelFormat)) {
return ScalePixelMapYuv(desiredSize, pixelMap, imgInfo, option);
}
uint32_t dstBufferSize = static_cast<uint32_t>(dstBufferSizeOverflow);
MemoryData memoryData = {nullptr, dstBufferSize, "ScalePixelMapEx ImageData", desiredSize};
memoryData.usage = pixelMap.GetNoPaddingUsage();
auto mem = MemoryManager::CreateMemory(pixelMap.GetAllocatorType() == AllocatorType::CUSTOM_ALLOC ?
AllocatorType::DEFAULT : pixelMap.GetAllocatorType(), memoryData);
CHECK_ERROR_RETURN_RET_LOG(mem == nullptr, false, "ScalePixelMapEx CreateMemory failed");
const uint8_t *srcPixels[FFMPEG_NUM] = {};
uint8_t *dstPixels[FFMPEG_NUM] = {};
srcPixels[0] = pixelMap.GetPixels();
dstPixels[0] = reinterpret_cast<uint8_t *>(mem->data.data);
int srcRowStride[FFMPEG_NUM] = {};
int dstRowStride[FFMPEG_NUM] = {};
srcRowStride[0] = pixelMap.GetRowStride();
dstRowStride[0] = (mem->GetType() == AllocatorType::DMA_ALLOC) ?
reinterpret_cast<SurfaceBuffer*>(mem->extend.data)->GetStride() :
desiredSize.width * ImageUtils::GetPixelBytes(imgInfo.pixelFormat);
void *inBuf = nullptr;
if (srcWidth % HALF != 0 &&
(pixelMap.GetAllocatorType() == AllocatorType::SHARE_MEM_ALLOC ||
pixelMap.GetAllocatorType() == AllocatorType::HEAP_ALLOC || pixelMap.GetNoPaddingUsage())) {
uint64_t byteCount = static_cast<uint64_t>(srcRowStride[0]) * static_cast<uint64_t>(srcHeight);
uint64_t allocSize = static_cast<uint64_t>(srcWidth + 1) * static_cast<uint64_t>(srcHeight) *
static_cast<uint64_t>(ImageUtils::GetPixelBytes(imgInfo.pixelFormat));
if (srcRowStride[0] <= 0 || byteCount > UINT_MAX || allocSize < byteCount || allocSize > UINT_MAX) {
mem->Release();
IMAGE_LOGE("ScalePixelMapEx invalid srcRowStride or pixelMap size too large");
return false;
}
inBuf = malloc(allocSize);
srcPixels[0] = reinterpret_cast<uint8_t*>(inBuf);
errno_t errRet = memcpy_s(inBuf, allocSize, pixelMap.GetWritablePixels(), byteCount);
if (errRet != EOK) {
if (inBuf != nullptr) {
free(inBuf);
}
mem->Release();
IMAGE_LOGE("ScalePixelMapEx memcpy_s failed with error code: %{public}d", errRet);
return false;
}
}
SwsContext *swsContext = sws_getContext(srcWidth, srcHeight, pixelFormat, desiredSize.width, desiredSize.height,
pixelFormat, GetInterpolation(option), nullptr, nullptr, nullptr);
if (swsContext == nullptr) {
if (inBuf != nullptr) {
free(inBuf);
}
mem->Release();
IMAGE_LOGE("sws_getContext failed");
return false;
}
auto res = sws_scale(swsContext, srcPixels, srcRowStride, 0, srcHeight, dstPixels, dstRowStride);
sws_freeContext(swsContext);
if (inBuf != nullptr) {
free(inBuf);
}
if (!res) {
mem->Release();
IMAGE_LOGE("sws_scale failed");
return false;
}
pixelMap.SetPixelsAddr(mem->data.data, mem->extend.data, dstBufferSize, mem->GetType(), nullptr);
imgInfo.size = desiredSize;
pixelMap.SetImageInfo(imgInfo, true);
ImageUtils::FlushSurfaceBuffer(&pixelMap);
return true;
}
bool PostProc::ScalePixelMapYuv(const Size &desiredSize, PixelMap &pixelMap, ImageInfo &imgInfo,
const AntiAliasingOption &option)
{
bool cond = !ImageUtils::IsYuvFormat(imgInfo.pixelFormat);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "ScalePixelMapYuv unsupport pixelformat");
int32_t srcWidth = imgInfo.size.width;
int32_t srcHeight = imgInfo.size.height;
cond = (srcWidth == 0 || srcHeight == 0 || desiredSize.width <= 0 || desiredSize.height <= 0);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "ScalePixelMapYuv invalid image size or desiredSize");
YUVStrideInfo dstStrides;
void *srcSurfaceBuffer = nullptr;
#if !defined(CROSS_PLATFORM)
if (pixelMap.GetAllocatorType() == AllocatorType::DMA_ALLOC) {
srcSurfaceBuffer = reinterpret_cast<void *>(pixelMap.GetFd());
}
#endif
auto dstMemory = PixelYuvUtils::CreateYuvMemory(imgInfo.pixelFormat, "ScalePixelMapEx YUV ImageData",
desiredSize.width, desiredSize.height, pixelMap.GetAllocatorType(), pixelMap.GetNoPaddingUsage(),
srcSurfaceBuffer, dstStrides);
cond = (dstMemory == nullptr) || (dstMemory->data.data == nullptr);
CHECK_ERROR_RETURN_RET_LOG(cond, false, "ScalePixelMapYuv CreateMemory failed");
uint8_t *dstYuvData = reinterpret_cast<uint8_t *>(dstMemory->data.data);
YUVDataInfo srcYuvDataInfo;
ImageUtils::UpdateYUVDataInfo(pixelMap);
pixelMap.GetImageYUVInfo(srcYuvDataInfo);
YuvImageInfo srcInfo = {PixelYuvUtils::ConvertFormat(imgInfo.pixelFormat),
srcWidth, srcHeight, imgInfo.pixelFormat, srcYuvDataInfo};
YUVDataInfo dstYuvInfo;
if (pixelMap.GetAllocatorType() == AllocatorType::DMA_ALLOC && dstMemory->extend.data != nullptr) {
auto surfaceBuffer = reinterpret_cast<SurfaceBuffer*>(dstMemory->extend.data);
ImageUtils::GetYuvInfoFromDmaBuffer(surfaceBuffer, dstYuvInfo);
} else {
ImageUtils::GetYuvInfoFromNonDmaBuffer(desiredSize.width, desiredSize.height, imgInfo.pixelFormat, dstYuvInfo);
}
YuvImageInfo dstInfo = {PixelYuvUtils::ConvertFormat(imgInfo.pixelFormat),
desiredSize.width, desiredSize.height, imgInfo.pixelFormat, dstYuvInfo};
int32_t scaleRet = PixelYuvUtils::YuvScale(const_cast<uint8_t *>(pixelMap.GetPixels()),
srcInfo, dstYuvData, dstInfo, PixelYuvUtils::YuvConvertOption(option));
if (scaleRet != SUCCESS) {
IMAGE_LOGE("ScalePixelMapYuv YuvScale failed, ret: %{public}d", scaleRet);
dstMemory->Release();
return false;
}
pixelMap.SetPixelsAddr(dstMemory->data.data, dstMemory->extend.data, dstMemory->data.size,
dstMemory->GetType(), nullptr);
imgInfo.size = desiredSize;
cond = pixelMap.SetImageInfo(imgInfo, true) != SUCCESS;
CHECK_ERROR_RETURN_RET_LOG(cond, false, "ScalePixelMapYuv SetImageInfo failed");
ImageUtils::UpdateYUVDataInfo(pixelMap);
ImageUtils::FlushSurfaceBuffer(&pixelMap);
return true;
}
#endif
}
}