From 3de446e00014331b1a7d4b62762a31a9046f8063 Mon Sep 17 00:00:00 2001 From: yaozhupeng Date: Wed, 3 Apr 2024 12:53:42 +0800 Subject: [PATCH] add pixelmap format convert ability Signed-off-by: yaozhupeng --- .../innerkitsimpl/common/src/pixel_map.cpp | 200 ++++++++++++--- .../converter/include/pixel_convert.h | 3 + .../converter/src/pixel_convert.cpp | 242 ++++++++++++++++++ .../js/common/image_pixel_map_napi_kits.cpp | 3 +- frameworks/kits/js/common/pixel_map_napi.cpp | 6 + .../pixelmap_ndk/image_pixel_map_ndk.cpp | 1 + interfaces/innerkits/BUILD.gn | 6 +- interfaces/innerkits/include/pixel_map.h | 7 +- .../kits/native/include/image_pixel_map_mdk.h | 2 + 9 files changed, 428 insertions(+), 42 deletions(-) diff --git a/frameworks/innerkitsimpl/common/src/pixel_map.cpp b/frameworks/innerkitsimpl/common/src/pixel_map.cpp index 40d866f41..5e1ebf2e3 100644 --- a/frameworks/innerkitsimpl/common/src/pixel_map.cpp +++ b/frameworks/innerkitsimpl/common/src/pixel_map.cpp @@ -56,6 +56,17 @@ #include "surface_buffer.h" #endif +#ifdef __cplusplus +extern "C" { +#endif +#include "libswscale/swscale.h" +#include "libavutil/opt.h" +#include "libavutil/imgutils.h" +#include "libavcodec/avcodec.h" +#ifdef __cplusplus +} +#endif + #undef LOG_DOMAIN #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE @@ -66,7 +77,6 @@ namespace OHOS { namespace Media { using namespace std; constexpr int32_t MAX_DIMENSION = INT32_MAX >> 2; -constexpr uint8_t FOUR_BYTE_SHIFT = 2; constexpr int8_t INVALID_ALPHA_INDEX = -1; constexpr uint8_t ARGB_ALPHA_INDEX = 0; constexpr uint8_t BGRA_ALPHA_INDEX = 3; @@ -74,6 +84,7 @@ constexpr uint8_t ALPHA_BYTES = 1; constexpr uint8_t BGRA_BYTES = 4; constexpr uint8_t RGBA_F16_BYTES = 8; constexpr uint8_t PER_PIXEL_LEN = 1; +constexpr uint32_t MAX_READ_COUNT = 2048; constexpr uint8_t FILL_NUMBER = 3; constexpr uint8_t ALIGN_NUMBER = 4; @@ -213,20 +224,20 @@ unique_ptr PixelMap::Create(const uint32_t *colors, uint32_t colorLeng return Create(colors, colorLength, 0, opts.size.width, opts); } -unique_ptr PixelMap::Create(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t stride, +unique_ptr PixelMap::Create(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t width, const InitializationOptions &opts) { IMAGE_LOGD("PixelMap::Create2 enter"); - return Create(colors, colorLength, 0, opts.size.width, opts, false); + return Create(colors, colorLength, 0, opts.size.width, opts, true); } -unique_ptr PixelMap::Create(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t stride, +unique_ptr PixelMap::Create(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t width, const InitializationOptions &opts, bool useCustomFormat) { int errorCode; BUILD_PARAM info; info.offset_ = offset; - info.stride_ = stride; + info.width_ = width; info.flag_ = useCustomFormat; return Create(colors, colorLength, info, opts, errorCode); } @@ -243,53 +254,129 @@ static void MakePixelMap(void *dstPixels, int fd, std::unique_ptr &dst #endif } +static const map FFMPEG_PIXEL_FORMAT_MAP = { + { PixelFormat::UNKNOWN, AVPixelFormat::AV_PIX_FMT_NONE }, + { PixelFormat::ARGB_8888, AVPixelFormat::AV_PIX_FMT_ARGB }, + { PixelFormat::RGB_565, AVPixelFormat::AV_PIX_FMT_RGB565 }, + { PixelFormat::RGBA_8888, AVPixelFormat::AV_PIX_FMT_RGBA }, + { PixelFormat::BGRA_8888, AVPixelFormat::AV_PIX_FMT_BGRA }, + { PixelFormat::RGB_888, AVPixelFormat::AV_PIX_FMT_RGB24 }, + { PixelFormat::NV21, AVPixelFormat::AV_PIX_FMT_NV21 }, + { PixelFormat::NV12, AVPixelFormat::AV_PIX_FMT_NV12 }, + { PixelFormat::CMYK, AVPixelFormat::AV_PIX_FMT_GBRP }, +}; + +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 PixelMap::GetRGBxRowDataSize(const ImageInfo& info) +{ + if (info.pixelFormat <= PixelFormat::UNKNOWN || info.pixelFormat >= PixelFormat::NV21) { + IMAGE_LOGE("[ImageUtil]unsupport pixel format"); + return -1; + } + int32_t pixelBytes = ImageUtils::GetPixelBytes(info.pixelFormat); + if (pixelBytes < 0) { + IMAGE_LOGE("[ImageUtil]get rgbx pixel bytes failed"); + return -1; + } + return pixelBytes * info.size.width; +} + +int32_t PixelMap::GetRGBxByteCount(const ImageInfo& info) +{ + if (info.pixelFormat == PixelFormat::NV21 || info.pixelFormat == PixelFormat::NV12) { + IMAGE_LOGE("[ImageUtil]unsupport pixel format"); + return -1; + } + int32_t rowDataSize = GetRGBxRowDataSize(info); + if (rowDataSize < 0) { + IMAGE_LOGE("[ImageUtil]get rgbx row data size failed"); + return -1; + } + return rowDataSize * info.size.height; +} + +int32_t PixelMap::GetYUVByteCount(const ImageInfo& info) +{ + if (info.pixelFormat != PixelFormat::NV21 && info.pixelFormat != PixelFormat::NV12) { + IMAGE_LOGE("[ImageUtil]unsupport 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 PixelMap::GetAllocatedByteCount(const ImageInfo& info) +{ + if (info.pixelFormat == PixelFormat::NV21 || info.pixelFormat == PixelFormat::NV12) { + return GetYUVByteCount(info); + } else { + return GetRGBxByteCount(info); + } +} + unique_ptr PixelMap::Create(const uint32_t *colors, uint32_t colorLength, BUILD_PARAM &info, const InitializationOptions &opts, int &errorCode) { + IMAGE_LOGE("[PixelMap]Create: make pixelmap failed!"); int offset = info.offset_; - int32_t stride = info.stride_; - bool useCustomFormat = info.flag_; - if (!CheckParams(colors, colorLength, offset, stride, opts)) { + if (!CheckParams(colors, colorLength, offset, info.width_, opts)) { return nullptr; } unique_ptr dstPixelMap = make_unique(); if (dstPixelMap == nullptr) { + IMAGE_LOGE("[image]Create: make pixelmap failed!"); errorCode = IMAGE_RESULT_PLUGIN_REGISTER_FAILED; return nullptr; } PixelFormat format = PixelFormat::BGRA_8888; - if (useCustomFormat) { + if (info.flag_) { format = ((opts.srcPixelFormat == PixelFormat::UNKNOWN) ? PixelFormat::BGRA_8888 : opts.srcPixelFormat); } ImageInfo srcImageInfo = - MakeImageInfo(stride, opts.size.height, format, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); + MakeImageInfo(info.width_, opts.size.height, format, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL); PixelFormat dstPixelFormat = (opts.pixelFormat == PixelFormat::UNKNOWN ? PixelFormat::RGBA_8888 : opts.pixelFormat); AlphaType dstAlphaType = (opts.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) ? AlphaType::IMAGE_ALPHA_TYPE_PREMUL : opts.alphaType; dstAlphaType = ImageUtils::GetValidAlphaTypeByFormat(dstAlphaType, dstPixelFormat); ImageInfo dstImageInfo = MakeImageInfo(opts.size.width, opts.size.height, dstPixelFormat, dstAlphaType); if (!CheckPixelmap(dstPixelMap, dstImageInfo)) { + IMAGE_LOGE("[PixelMap]Create: check pixelmap failed!"); errorCode = IMAGE_RESULT_DATA_ABNORMAL; return nullptr; } int fd = 0; uint32_t bufferSize = dstPixelMap->GetByteCount(); + void *dstPixels = AllocSharedMemory(bufferSize, fd, dstPixelMap->GetUniqueId()); if (dstPixels == nullptr) { - IMAGE_LOGE("allocate memory size %{public}u fail", bufferSize); + IMAGE_LOGE("[PixelMap]Create: allocate memory size %{public}u fail", bufferSize); errorCode = IMAGE_RESULT_ERR_SHAMEM_NOT_EXIST; return nullptr; } - Position dstPosition; - if (!PixelConvertAdapter::WritePixelsConvert(reinterpret_cast(colors + offset), - static_cast(stride) << FOUR_BYTE_SHIFT, srcImageInfo, - dstPixels, dstPosition, dstPixelMap->GetRowBytes(), dstImageInfo)) { - IMAGE_LOGE("pixel convert in adapter failed."); + + int32_t dstLength = PixelConvert::PixelsConvert(reinterpret_cast(colors + offset), + colorLength, srcImageInfo, dstPixels, dstImageInfo); + if (dstLength < 0) { + IMAGE_LOGE("[PixelMap]Create: pixel convert failed."); ReleaseBuffer(AllocatorType::SHARE_MEM_ALLOC, fd, bufferSize, &dstPixels); dstPixels = nullptr; errorCode = IMAGE_RESULT_THIRDPART_SKIA_ERROR; return nullptr; } + dstPixelMap->SetEditable(opts.editable); MakePixelMap(dstPixels, fd, dstPixelMap); ImageUtils::DumpPixelMapIfDumpEnabled(dstPixelMap); @@ -345,7 +432,7 @@ void *PixelMap::AllocSharedMemory(const uint64_t bufferSize, int &fd, uint32_t u #endif } -bool PixelMap::CheckParams(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t stride, +bool PixelMap::CheckParams(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t width, const InitializationOptions &opts) { if (colors == nullptr || colorLength <= 0) { @@ -358,18 +445,18 @@ bool PixelMap::CheckParams(const uint32_t *colors, uint32_t colorLength, int32_t IMAGE_LOGE("initial options size invalid"); return false; } - if (stride < dstWidth) { - IMAGE_LOGE("stride: %{public}d must >= width: %{public}d", stride, dstWidth); + if (width < dstWidth) { + IMAGE_LOGE("width: %{public}d must >= width: %{public}d", width, dstWidth); return false; } - if (stride > MAX_DIMENSION) { - IMAGE_LOGE("stride %{public}d is out of range", stride); + if (width > MAX_DIMENSION) { + IMAGE_LOGE("stride %{public}d is out of range", width); return false; } - int64_t lastLine = static_cast(dstHeight - 1) * stride + offset; + int64_t lastLine = static_cast(dstHeight - 1) * width + offset; if (offset < 0 || static_cast(offset) + dstWidth > colorLength || lastLine + dstWidth > colorLength) { - IMAGE_LOGE("colors length: %{public}u, offset: %{public}d, stride: %{public}d is invalid", - colorLength, offset, stride); + IMAGE_LOGE("colors length: %{public}u, offset: %{public}d, width: %{public}d is invalid", + colorLength, offset, width); return false; } return true; @@ -1086,7 +1173,11 @@ int32_t PixelMap::GetRowBytes() int32_t PixelMap::GetByteCount() { IMAGE_LOGD("GetByteCount"); - return rowDataSize_ * imageInfo_.size.height; + if (imageInfo_.pixelFormat == PixelFormat::NV12 || imageInfo_.pixelFormat == PixelFormat::NV21) { + return GetYUVByteCount(imageInfo_); + } else { + return rowDataSize_ * imageInfo_.size.height; + } } int32_t PixelMap::GetWidth() @@ -1195,15 +1286,30 @@ uint32_t PixelMap::ReadPixels(const uint64_t &bufferSize, uint8_t *dst) static_cast(bufferSize), pixelsSize_); return ERR_IMAGE_INVALID_PARAMETER; } - - // Copy the actual pixel data without padding bytes - for (int i = 0; i < imageInfo_.size.height; ++i) { - errno_t ret = memcpy_s(dst, rowDataSize_, data_ + i * rowStride_, rowDataSize_); - if (ret != 0) { - IMAGE_LOGE("read pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret); - return ERR_IMAGE_READ_PIXELMAP_FAILED; + if (imageInfo_.pixelFormat == PixelFormat::NV12 || imageInfo_.pixelFormat == PixelFormat::NV21) { + uint64_t tmpSize = 0; + int readSize = MAX_READ_COUNT; + while (tmpSize < bufferSize) { + if (tmpSize + MAX_READ_COUNT > bufferSize) { + readSize = (int)(bufferSize - tmpSize); + } + errno_t ret = memcpy_s(dst + tmpSize, readSize, data_ + tmpSize, readSize); + if (ret != 0) { + IMAGE_LOGE("read pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret); + return ERR_IMAGE_READ_PIXELMAP_FAILED; + } + tmpSize += readSize; + } + } else { + // Copy the actual pixel data without padding bytes + for (int i = 0; i < imageInfo_.size.height; ++i) { + errno_t ret = memcpy_s(dst, rowDataSize_, data_ + i * rowStride_, rowDataSize_); + if (ret != 0) { + IMAGE_LOGE("read pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret); + return ERR_IMAGE_READ_PIXELMAP_FAILED; + } + dst += rowDataSize_; // Move the destination buffer pointer to the next row } - dst += rowDataSize_; // Move the destination buffer pointer to the next row } return SUCCESS; } @@ -1444,12 +1550,28 @@ uint32_t PixelMap::WritePixels(const uint8_t *source, const uint64_t &bufferSize return ERR_IMAGE_WRITE_PIXELMAP_FAILED; } - for (int i = 0; i < imageInfo_.size.height; ++i) { - const uint8_t* sourceRow = source + i * rowDataSize_; - errno_t ret = memcpy_s(data_ + i * rowStride_, rowDataSize_, sourceRow, rowDataSize_); - if (ret != 0) { - IMAGE_LOGE("write pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret); - return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + if (imageInfo_.pixelFormat == PixelFormat::NV12 || imageInfo_.pixelFormat == PixelFormat::NV21) { + uint64_t tmpSize = 0; + int readSize = MAX_READ_COUNT; + while (tmpSize < bufferSize) { + if (tmpSize + MAX_READ_COUNT > bufferSize) { + readSize = (int)(bufferSize - tmpSize); + } + errno_t ret = memcpy_s(data_ + tmpSize, readSize, source + tmpSize, readSize); + if (ret != 0) { + IMAGE_LOGE("write pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret); + return ERR_IMAGE_READ_PIXELMAP_FAILED; + } + tmpSize += readSize; + } + } else { + for (int i = 0; i < imageInfo_.size.height; ++i) { + const uint8_t* sourceRow = source + i * rowDataSize_; + errno_t ret = memcpy_s(data_ + i * rowStride_, rowDataSize_, sourceRow, rowDataSize_); + if (ret != 0) { + IMAGE_LOGE("write pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret); + return ERR_IMAGE_WRITE_PIXELMAP_FAILED; + } } } return SUCCESS; diff --git a/frameworks/innerkitsimpl/converter/include/pixel_convert.h b/frameworks/innerkitsimpl/converter/include/pixel_convert.h index ce7d01b2a..b1bbbd61e 100644 --- a/frameworks/innerkitsimpl/converter/include/pixel_convert.h +++ b/frameworks/innerkitsimpl/converter/include/pixel_convert.h @@ -181,6 +181,9 @@ public: static std::unique_ptr Create(const ImageInfo &srcInfo, const ImageInfo &dstInfo); void Convert(void *destinationPixels, const uint8_t *sourcePixels, uint32_t sourcePixelsNum); + static int32_t PixelsConvert(const void *srcPixels, const int32_t srcLength, const ImageInfo &srcInfo, + void *dstPixels, const ImageInfo &dstInfo); + private: PixelConvert(ProcFuncType funcPtr, ProcFuncExtension extension, bool isNeedConvert); static AlphaConvertType GetAlphaConvertType(const AlphaType &srcType, const AlphaType &dstType); diff --git a/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp b/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp index a1f6acf4e..f18c9a083 100644 --- a/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp +++ b/frameworks/innerkitsimpl/converter/src/pixel_convert.cpp @@ -17,9 +17,28 @@ #include #include +#ifndef _WIN32 +#include "securec.h" +#else +#include "memory.h" +#endif +#include "pixel_convert_adapter.h" +#include "image_utils.h" +#include "pixel_map.h" #include "image_log.h" +#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 @@ -1056,6 +1075,229 @@ static ProcFuncType GetProcFuncType(uint32_t srcPixelFormat, uint32_t dstPixelFo return nullptr; } +static const map FFMPEG_PIXEL_FORMAT_MAP = { + { PixelFormat::UNKNOWN, AVPixelFormat::AV_PIX_FMT_NONE }, + { PixelFormat::ARGB_8888, AVPixelFormat::AV_PIX_FMT_ARGB }, + { PixelFormat::RGB_565, AVPixelFormat::AV_PIX_FMT_RGB565 }, + { PixelFormat::RGBA_8888, AVPixelFormat::AV_PIX_FMT_RGBA }, + { PixelFormat::BGRA_8888, AVPixelFormat::AV_PIX_FMT_BGRA }, + { PixelFormat::RGB_888, AVPixelFormat::AV_PIX_FMT_RGB24 }, + { PixelFormat::NV21, AVPixelFormat::AV_PIX_FMT_NV21 }, + { PixelFormat::NV12, AVPixelFormat::AV_PIX_FMT_NV12 }, + { PixelFormat::CMYK, AVPixelFormat::AV_PIX_FMT_GBRP }, +}; + +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; +} + +typedef struct FFMpegConvertInfo { + AVPixelFormat format = AVPixelFormat::AV_PIX_FMT_NONE; + int32_t width = 0; + int32_t height = 0; + int32_t alignSize = 1; +} FFMPEG_CONVERT_INFO; + +static bool FFMpegConvert(const void *srcPixels, const FFMPEG_CONVERT_INFO& srcInfo, + void *dstPixels, const FFMPEG_CONVERT_INFO& dstInfo) +{ + bool ret = true; + AVFrame *inputFrame = nullptr; + AVFrame *outputFrame = nullptr; + + if (srcInfo.format == AVPixelFormat::AV_PIX_FMT_NONE || + dstInfo.format == AVPixelFormat::AV_PIX_FMT_NONE) { + IMAGE_LOGE("unsupport src/dst pixel format!"); + return false; + } + if (srcInfo.width <= 0 || srcInfo.height <= 0 || dstInfo.width <= 0 || dstInfo.height <= 0) { + IMAGE_LOGE("src/dst width/height error!"); + return false; + } + + inputFrame = av_frame_alloc(); + outputFrame = av_frame_alloc(); + if (inputFrame != nullptr && outputFrame != nullptr) { + struct SwsContext *ctx = sws_getContext(srcInfo.width, srcInfo.height, srcInfo.format, + dstInfo.width, dstInfo.height, dstInfo.format, SWS_POINT, nullptr, nullptr, nullptr); + if (ctx != nullptr) { + av_image_fill_arrays(inputFrame->data, inputFrame->linesize, (uint8_t *)srcPixels, + srcInfo.format, srcInfo.width, srcInfo.height, srcInfo.alignSize); + av_image_fill_arrays(outputFrame->data, outputFrame->linesize, (uint8_t *)dstPixels, + dstInfo.format, dstInfo.width, dstInfo.height, dstInfo.alignSize); + + sws_scale(ctx, (uint8_t const **)inputFrame->data, inputFrame->linesize, 0, srcInfo.height, + outputFrame->data, outputFrame->linesize); + sws_freeContext(ctx); + } else { + IMAGE_LOGE("FFMpeg: sws_getContext failed!"); + ret = false; + } + } else { + IMAGE_LOGE("FFMpeg: av_frame_alloc failed!"); + ret = false; + } + av_frame_free(&inputFrame); + av_frame_free(&outputFrame); + return ret; +} + +static int32_t ConvertFromYUV(const void *srcPixels, const int32_t srcLength, const ImageInfo &srcInfo, + void *dstPixels, const ImageInfo &dstInfo) +{ + if (srcPixels == nullptr || dstPixels == nullptr || srcLength <= 0) { + IMAGE_LOGE("[PixelMap]Convert: src pixels or dst pixels or src pixels length invalid."); + return -1; + } + if ((srcInfo.pixelFormat != PixelFormat::NV21 && srcInfo.pixelFormat != PixelFormat::NV12) || + (dstInfo.pixelFormat == PixelFormat::NV21 || dstInfo.pixelFormat == PixelFormat::NV12)) { + IMAGE_LOGE("[PixelMap]Convert: src or dst pixel format invalid."); + return -1; + } + + FFMPEG_CONVERT_INFO srcFFmpegInfo = {PixelFormatToAVPixelFormat(srcInfo.pixelFormat), + srcInfo.size.width, srcInfo.size.height, 1}; + FFMPEG_CONVERT_INFO tmpFFmpegInfo = {PixelFormatToAVPixelFormat(PixelFormat::RGB_888), + srcInfo.size.width, srcInfo.size.height, 1}; + int tmpPixelsLen = av_image_get_buffer_size(tmpFFmpegInfo.format, tmpFFmpegInfo.width, tmpFFmpegInfo.height, + tmpFFmpegInfo.alignSize); + if (tmpPixelsLen <= 0) { + IMAGE_LOGE("[PixelMap]Convert: Get tmp pixels length failed!"); + return -1; + } + uint8_t* tmpPixels = new uint8_t[tmpPixelsLen]; + if (tmpPixels == nullptr) { + IMAGE_LOGE("[PixelMap]Convert: alloc memory failed!"); + return -1; + } + memset_s(tmpPixels, tmpPixelsLen, 0, tmpPixelsLen); + if (!FFMpegConvert(srcPixels, srcFFmpegInfo, (void *)tmpPixels, tmpFFmpegInfo)) { + IMAGE_LOGE("[PixelMap]Convert: ffmpeg convert failed!"); + delete[] tmpPixels; + tmpPixels = nullptr; + return -1; + } + + ImageInfo tmpInfo = srcInfo; + tmpInfo.pixelFormat = PixelFormat::RGB_888; + Position pos; + if (!PixelConvertAdapter::WritePixelsConvert(tmpPixels, PixelMap::GetRGBxRowDataSize(tmpInfo), tmpInfo, + dstPixels, pos, PixelMap::GetRGBxRowDataSize(dstInfo), dstInfo)) { + IMAGE_LOGE("[PixelMap]Convert: ConvertFromYUV: pixel convert in adapter failed."); + delete[] tmpPixels; + tmpPixels = nullptr; + return -1; + } + + delete[] tmpPixels; + tmpPixels = nullptr; + + return PixelMap::GetRGBxByteCount(dstInfo); +} + +static int32_t ConvertToYUV(const void *srcPixels, const int32_t srcLength, const ImageInfo &srcInfo, + void *dstPixels, const ImageInfo &dstInfo) +{ + if (srcPixels == nullptr || dstPixels == nullptr || srcLength <= 0) { + IMAGE_LOGE("[PixelMap]Convert: src pixels or dst pixels or src pixel length invalid"); + return -1; + } + if ((srcInfo.pixelFormat == PixelFormat::NV21 || srcInfo.pixelFormat == PixelFormat::NV12) || + (dstInfo.pixelFormat != PixelFormat::NV21 && dstInfo.pixelFormat != PixelFormat::NV12)) { + IMAGE_LOGE("[PixelMap]Convert: src or dst pixel format invalid."); + return -1; + } + + ImageInfo tmpInfo = srcInfo; + tmpInfo.pixelFormat = PixelFormat::RGB_888; + int tmpPixelsLen = PixelMap::GetRGBxByteCount(tmpInfo); + if (tmpPixelsLen <= 0) { + IMAGE_LOGE("[PixelMap]Convert: Get tmp pixels length failed!"); + return -1; + } + uint8_t* tmpPixels = new uint8_t[tmpPixelsLen]; + if (tmpPixels == nullptr) { + IMAGE_LOGE("[PixelMap]Convert: alloc memory failed!"); + return -1; + } + memset_s(tmpPixels, tmpPixelsLen, 0, tmpPixelsLen); + + Position pos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, PixelMap::GetRGBxRowDataSize(srcInfo), srcInfo, + tmpPixels, pos, PixelMap::GetRGBxRowDataSize(tmpInfo), tmpInfo)) { + IMAGE_LOGE("[PixelMap]Convert: ConvertToYUV: pixel convert in adapter failed."); + delete[] tmpPixels; + tmpPixels = nullptr; + return -1; + } + + FFMPEG_CONVERT_INFO srcFFmpegInfo = {PixelFormatToAVPixelFormat(PixelFormat::RGB_888), + tmpInfo.size.width, tmpInfo.size.height, 1}; + FFMPEG_CONVERT_INFO dstFFmpegInfo = {PixelFormatToAVPixelFormat(dstInfo.pixelFormat), + dstInfo.size.width, dstInfo.size.height, 1}; + if (!FFMpegConvert(tmpPixels, srcFFmpegInfo, (void *)dstPixels, dstFFmpegInfo)) { + IMAGE_LOGE("[PixelMap]Convert: ffmpeg convert failed!"); + delete[] tmpPixels; + tmpPixels = nullptr; + return -1; + } + + delete[] tmpPixels; + tmpPixels = nullptr; + + return av_image_get_buffer_size(dstFFmpegInfo.format, dstFFmpegInfo.width, dstFFmpegInfo.height, + dstFFmpegInfo.alignSize); +} + +int32_t PixelConvert::PixelsConvert(const void *srcPixels, const int32_t srcLength, const ImageInfo &srcInfo, + void *dstPixels, const ImageInfo &dstInfo) +{ + if (srcPixels == nullptr || dstPixels == nullptr || srcLength <= 0) { + IMAGE_LOGE("[PixelMap]Convert: src pixels or dst pixels or src pixels length invalid."); + return -1; + } + + if (srcInfo.pixelFormat == dstInfo.pixelFormat && + srcInfo.size.width == dstInfo.size.width && srcInfo.size.height == dstInfo.size.height) { + IMAGE_LOGE("src pixel format is equal dst pixel format. no need to convert"); + if (memcpy_s(dstPixels, srcLength, srcPixels, srcLength) != 0) { + IMAGE_LOGE("[PixelMap]Convert: memcpy_s failed!"); + return -1; + } + return srcLength; + } + + if ((srcInfo.pixelFormat == PixelFormat::NV12 || srcInfo.pixelFormat == PixelFormat::NV21) && + (dstInfo.pixelFormat == PixelFormat::NV12 || dstInfo.pixelFormat == PixelFormat::NV21)) { + FFMPEG_CONVERT_INFO srcFFmpegInfo = {PixelFormatToAVPixelFormat(srcInfo.pixelFormat), + srcInfo.size.width, srcInfo.size.height, 1}; + FFMPEG_CONVERT_INFO dstFFmpegInfo = {PixelFormatToAVPixelFormat(dstInfo.pixelFormat), + dstInfo.size.width, dstInfo.size.height, 1}; + if (!FFMpegConvert(srcPixels, srcFFmpegInfo, (void *)dstPixels, dstFFmpegInfo)) { + IMAGE_LOGE("[PixelMap]Convert: ffmpeg convert failed!"); + return -1; + } + return av_image_get_buffer_size(dstFFmpegInfo.format, dstFFmpegInfo.width, dstFFmpegInfo.height, + dstFFmpegInfo.alignSize); + } + if (srcInfo.pixelFormat == PixelFormat::NV12 || srcInfo.pixelFormat == PixelFormat::NV21) { + return ConvertFromYUV(srcPixels, srcLength, srcInfo, dstPixels, dstInfo); + } else if (dstInfo.pixelFormat == PixelFormat::NV12 || dstInfo.pixelFormat == PixelFormat::NV21) { + return ConvertToYUV(srcPixels, srcLength, srcInfo, dstPixels, dstInfo); + } + + Position pos; + if (!PixelConvertAdapter::WritePixelsConvert(srcPixels, PixelMap::GetRGBxRowDataSize(srcInfo), srcInfo, + dstPixels, pos, PixelMap::GetRGBxRowDataSize(dstInfo), dstInfo)) { + IMAGE_LOGE("[PixelMap]Convert: PixelsConvert: pixel convert in adapter failed."); + return -1; + } + + return PixelMap::GetRGBxByteCount(dstInfo); +} + PixelConvert::PixelConvert(ProcFuncType funcPtr, ProcFuncExtension extension, bool isNeedConvert) : procFunc_(funcPtr), procFuncExtension_(extension), isNeedConvert_(isNeedConvert) {} diff --git a/frameworks/kits/js/common/image_pixel_map_napi_kits.cpp b/frameworks/kits/js/common/image_pixel_map_napi_kits.cpp index aa9fabf9e..318df3ba1 100644 --- a/frameworks/kits/js/common/image_pixel_map_napi_kits.cpp +++ b/frameworks/kits/js/common/image_pixel_map_napi_kits.cpp @@ -99,6 +99,7 @@ static int32_t PixelMapNapiCreate(napi_env env, PixelMapNapiArgs* args) InitializationOptions info; info.alphaType = ParseAlphaType(args->createOptions.alphaType); info.editable = args->createOptions.editable != NUM_0; + info.srcPixelFormat = ParsePixelForamt(args->createOptions.srcPixelFormat); info.pixelFormat = ParsePixelForamt(args->createOptions.pixelFormat); info.scaleMode = ParseScaleMode(args->createOptions.scaleMode); info.size.height = args->createOptions.height; @@ -106,7 +107,7 @@ static int32_t PixelMapNapiCreate(napi_env env, PixelMapNapiArgs* args) BUILD_PARAM pam; pam.offset_ = 0; - pam.stride_ = info.size.width; + pam.width_ = info.size.width; pam.flag_ = false; int32_t error = IMAGE_RESULT_SUCCESS; auto pixelmap = PixelMap::Create(static_cast(args->inBuffer), args->bufferLen, pam, info, error); diff --git a/frameworks/kits/js/common/pixel_map_napi.cpp b/frameworks/kits/js/common/pixel_map_napi.cpp index 943e351cf..3e136211a 100644 --- a/frameworks/kits/js/common/pixel_map_napi.cpp +++ b/frameworks/kits/js/common/pixel_map_napi.cpp @@ -170,6 +170,12 @@ static bool parseInitializationOptions(napi_env env, napi_value root, Initializa } opts->pixelFormat = ParsePixlForamt(tmpNumber); + tmpNumber = 0; + if (!GET_UINT32_BY_NAME(root, "srcPixelFormat", tmpNumber)) { + IMAGE_LOGI("no srcPixelFormat in initialization options"); + } + opts->srcPixelFormat = ParsePixlForamt(tmpNumber); + tmpNumber = 0; if (!GET_UINT32_BY_NAME(root, "scaleMode", tmpNumber)) { IMAGE_LOGI("no scaleMode in initialization options"); diff --git a/frameworks/kits/js/common/pixelmap_ndk/image_pixel_map_ndk.cpp b/frameworks/kits/js/common/pixelmap_ndk/image_pixel_map_ndk.cpp index c11509966..fcea5281e 100644 --- a/frameworks/kits/js/common/pixelmap_ndk/image_pixel_map_ndk.cpp +++ b/frameworks/kits/js/common/pixelmap_ndk/image_pixel_map_ndk.cpp @@ -46,6 +46,7 @@ int32_t OH_PixelMap_CreatePixelMap(napi_env env, OhosPixelMapCreateOps info, PixelMapNapiArgs args; args.createOptions.width = info.width; args.createOptions.height = info.height; + args.createOptions.srcPixelFormat = info.srcPixelFormat; args.createOptions.pixelFormat = info.pixelFormat; args.createOptions.editable = info.editable; args.createOptions.alphaType = info.alphaType; diff --git a/interfaces/innerkits/BUILD.gn b/interfaces/innerkits/BUILD.gn index 0b1750e0e..dd0877eb5 100644 --- a/interfaces/innerkits/BUILD.gn +++ b/interfaces/innerkits/BUILD.gn @@ -108,6 +108,7 @@ if (use_clang_android) { sources = image_native_android_sources include_dirs = image_native_android_include_dirs deps = image_native_android_deps + deps += [ "//third_party/ffmpeg:libohosffmpeg_static" ] subsystem_name = "multimedia" part_name = "image_framework" } @@ -120,6 +121,7 @@ if (use_clang_android) { include_dirs = image_native_ios_include_dirs sources = image_native_ios_sources deps = image_native_ios_deps + deps += [ "//third_party/ffmpeg:libohosffmpeg_static" ] external_deps = image_native_ios_external_deps subsystem_name = "multimedia" part_name = "image_framework" @@ -195,6 +197,7 @@ if (use_clang_android) { "//foundation/multimedia/image_framework/frameworks/innerkitsimpl/utils:image_utils_static", "//foundation/multimedia/image_framework/mock/native:log_mock_static", "//foundation/multimedia/image_framework/plugins/manager:pluginmanager_static", + "//third_party/ffmpeg:libohosffmpeg_static", ] external_deps = [ "graphic_surface:surface" ] } else if (use_clang_mac) { @@ -213,6 +216,7 @@ if (use_clang_android) { "//foundation/multimedia/image_framework/mock/native:log_mock_static", "//foundation/multimedia/image_framework/plugins/manager:pluginmanager_static", "//third_party/bounds_checking_function:libsec_statics", + "//third_party/ffmpeg:libohosffmpeg_static", ] external_deps = [ "graphic_surface:surface" ] } else { @@ -223,6 +227,7 @@ if (use_clang_android) { "//foundation/multimedia/image_framework/frameworks/innerkitsimpl/pixelconverter:pixelconvertadapter", "//foundation/multimedia/image_framework/frameworks/innerkitsimpl/utils:image_utils", "//foundation/multimedia/image_framework/plugins/manager:pluginmanager", + "//third_party/ffmpeg:libohosffmpeg", ] deps += skia_platform @@ -230,7 +235,6 @@ if (use_clang_android) { } else { deps += [ "//third_party/libpng:libpng" ] } - deps += [ "//third_party/ffmpeg:libohosffmpeg" ] external_deps = [ "c_utils:utils", "graphic_2d:color_manager", diff --git a/interfaces/innerkits/include/pixel_map.h b/interfaces/innerkits/include/pixel_map.h index a9dd77dfc..d8c7c65a4 100644 --- a/interfaces/innerkits/include/pixel_map.h +++ b/interfaces/innerkits/include/pixel_map.h @@ -76,7 +76,7 @@ typedef struct PixelMapError { typedef struct BuildParam { int32_t offset_ = 0; - int32_t stride_ = 0; + int32_t width_ = 0; bool flag_ = true; } BUILD_PARAM; @@ -291,6 +291,11 @@ public: NATIVEEXPORT uint32_t ModifyImageProperty(const std::string &key, const std::string &value, const int fd); + static int32_t GetRGBxRowDataSize(const ImageInfo& info); + static int32_t GetRGBxByteCount(const ImageInfo& info); + static int32_t GetYUVByteCount(const ImageInfo& info); + static int32_t GetAllocatedByteCount(const ImageInfo& info); + private: static constexpr uint8_t TLV_VARINT_BITS = 7; static constexpr uint8_t TLV_VARINT_MASK = 0x7F; diff --git a/interfaces/kits/native/include/image_pixel_map_mdk.h b/interfaces/kits/native/include/image_pixel_map_mdk.h index ee52695e4..076d3a446 100644 --- a/interfaces/kits/native/include/image_pixel_map_mdk.h +++ b/interfaces/kits/native/include/image_pixel_map_mdk.h @@ -128,6 +128,8 @@ struct OhosPixelMapCreateOps { uint32_t width; /** Image height, in pixels. */ uint32_t height; + /** Image source format. */ + int32_t srcPixelFormat; /** Image format. */ int32_t pixelFormat; /** Editing type of the image. */ -- Gitee