diff --git a/frameworks/innerkitsimpl/codec/src/image_source.cpp b/frameworks/innerkitsimpl/codec/src/image_source.cpp index 085ca9c9653bc5b63a2bd88848005a3c4b0b4aed..881cbdf88c31317a62e274b84b6422c91d25d5c8 100644 --- a/frameworks/innerkitsimpl/codec/src/image_source.cpp +++ b/frameworks/innerkitsimpl/codec/src/image_source.cpp @@ -905,14 +905,21 @@ uint64_t ImageSource::GetNowTimeMicroSeconds() return std::chrono::duration_cast(now.time_since_epoch()).count(); } -static void UpdatePlImageInfo(DecodeContext context, ImagePlugin::PlImageInfo &plInfo) +static inline bool IsHeifRegionDecode(int32_t heifRegionGridWidth, int32_t heifRegionGridHeight) +{ + return (heifRegionGridWidth > 0 && heifRegionGridHeight > 0); +} + +static void UpdatePlImageInfo(DecodeContext context, ImagePlugin::PlImageInfo &plInfo, + std::unique_ptr& decoder) { if (context.hdrType > Media::ImageHdrType::SDR) { plInfo.colorSpace = context.colorSpace; plInfo.pixelFormat = context.pixelFormat; } - - if (plInfo.size.width != context.outInfo.size.width || plInfo.size.height != context.outInfo.size.height) { + OHOS::Media::Size heifRegionGridSize = decoder->GetHeifRegionGridSize(); + if ((plInfo.size.width != context.outInfo.size.width || plInfo.size.height != context.outInfo.size.height) && + !IsHeifRegionDecode(heifRegionGridSize.width, heifRegionGridSize.height)) { plInfo.size = context.outInfo.size; } if ((plInfo.pixelFormat == PixelFormat::NV12 || plInfo.pixelFormat == PixelFormat::NV21 || @@ -1032,7 +1039,7 @@ unique_ptr ImageSource::CreatePixelMapExtended(uint32_t index, const D opts_.desiredSize.height = opts.desiredSize.height; } } - UpdatePlImageInfo(context, plInfo); + UpdatePlImageInfo(context, plInfo, mainDecoder_); auto pixelMap = CreatePixelMapByInfos(plInfo, context, errorCode); if (pixelMap == nullptr) { @@ -1214,6 +1221,11 @@ unique_ptr ImageSource::CreatePixelMapByInfos(ImagePlugin::PlImageInfo if (opts_.CropRect.width > INT_ZERO && opts_.CropRect.height > INT_ZERO) { if (!mainDecoder_->HasProperty(SUPPORT_CROP_KEY)) { Rect crop; + OHOS::Media::Size heifRegionGridSize = mainDecoder_->GetHeifRegionGridSize(); + if (IsHeifRegionDecode(heifRegionGridSize.width, heifRegionGridSize.height)) { + opts_.CropRect.left = opts_.CropRect.left % heifRegionGridSize.width; + opts_.CropRect.top = opts_.CropRect.top % heifRegionGridSize.height; + } GetValidCropRect(opts_.CropRect, {pixelMap->GetWidth(), pixelMap->GetHeight()}, crop); errorCode = pixelMap->crop(crop); if (errorCode != SUCCESS) { diff --git a/plugins/common/libs/image/libextplugin/include/ext_decoder.h b/plugins/common/libs/image/libextplugin/include/ext_decoder.h index 70c16cb0001ca43c6d96f2699d121c8d7c5af30d..6676b7680b105e088f7886939a115fdbcaafcd2b 100644 --- a/plugins/common/libs/image/libextplugin/include/ext_decoder.h +++ b/plugins/common/libs/image/libextplugin/include/ext_decoder.h @@ -82,7 +82,8 @@ public: OHOS::ColorManager::ColorSpace GetPixelMapColorSpace() override; bool IsSupportICCProfile() override; #endif - static void FillYuvInfo(DecodeContext &context, SkImageInfo &dstInfo); + void FillYuvInfo(DecodeContext &context, SkImageInfo &dstInfo); + OHOS::Media::Size GetHeifRegionGridSize() override; private: typedef struct FrameCacheInfo { int width; @@ -107,6 +108,7 @@ private: bool IsYuv420Format(OHOS::Media::PixelFormat format) const; bool IsHeifToYuvDecode(const DecodeContext &context) const; uint32_t DoHeifToYuvDecode(DecodeContext &context); + void UpdateDstInfoAndOutInfo(DecodeContext &context); uint32_t DoHeifSharedMemDecode(DecodeContext &context); bool IsHeifSharedMemDecode(DecodeContext &context); bool ConvertInfoToAlphaType(SkAlphaType &alphaType, OHOS::Media::AlphaType &outputType); @@ -128,7 +130,8 @@ private: uint32_t DmaMemAlloc(DecodeContext &context, uint64_t count, SkImageInfo &dstInfo); uint32_t JpegHwDmaMemAlloc(DecodeContext &context, uint64_t count, SkImageInfo &dstInfo); uint32_t DmaAlloc(DecodeContext &context, uint64_t count, const OHOS::BufferRequestConfig &requestConfig); - uint32_t UpdateHeifYuvDataInfo(DecodeContext &context, SkImageInfo &heifInfo); + uint32_t UpdateHeifYuvDataInfo(DecodeContext &context, SkImageInfo &heifInfo, + uint32_t gridTileWidth, uint32_t gridTileHeight); uint32_t HeifYUVMemAlloc(DecodeContext &context, SkImageInfo &heifInfo); uint32_t DoHeifDecode(DecodeContext &context); uint32_t DoHeifToRgbDecode(DecodeContext &context); @@ -141,12 +144,21 @@ private: uint32_t ConvertFormatToYUV(DecodeContext &context, SkImageInfo &skInfo, uint64_t byteCount, OHOS::Media::PixelFormat format); bool IsHeifToSingleHdrDecode(const DecodeContext &context) const; + uint32_t AllocHeifSingleHdrBuffer(DecodeContext &context); uint32_t DoHeifToSingleHdrDecode(OHOS::ImagePlugin::DecodeContext &context); uint32_t HandleGifCache(uint8_t* src, uint8_t* dst, uint64_t rowStride, int dstHeight); uint32_t GetFramePixels(SkImageInfo& info, uint8_t* buffer, uint64_t rowStride, SkCodec::Options options); FrameCacheInfo InitFrameCacheInfo(const uint64_t rowStride, SkImageInfo info); bool FrameCacheInfoIsEqual(FrameCacheInfo& src, FrameCacheInfo& dst); uint32_t UpdateHardWareDecodeInfo(DecodeContext &context); + uint32_t ExtractHeifRegion(const PixelDecodeOptions &opts); + bool IsHeifValidCrop(OHOS::Media::Rect &crop, SkImageInfo &info, int32_t gridInfoCols, int32_t gridInfoRows); + void SetHeifDecodeRegion(DecodeContext &context, int32_t gridTileWidth, int32_t gridTileHeight); + void UpdateHeifRegionDstInfo(DecodeContext &context); + void UpdateHeifSKInfo(DecodeContext &context, uint64_t &rowStride); + bool IsHeifRegionDecode(); + bool HeifGainMapRegionCrop(DecodeContext &gainmapRegionContext, int32_t rowStride, uint8_t* dstBuffer, + uint32_t gainmapWidth, uint32_t gainmapHeight); bool IsRegionDecodeSupported(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info); uint32_t DoRegionDecode(DecodeContext &context); SkCodec::Result DoSampleDecode(DecodeContext &context); @@ -171,6 +183,19 @@ private: FrameCacheInfo frameCacheInfo_ = {0, 0, 0, 0}; uint32_t heifParseErr_ = 0; std::shared_ptr reusePixelmap_ = nullptr; + OHOS::Media::Rect desiredRegion_ = {0, 0, 0, 0}; + typedef struct HeifGridRegionInfo { + int32_t colCount; + int32_t rowCount; + int32_t tileWidth; + int32_t tileHeight; + int32_t heightPadding; + int32_t widthPadding; + bool isGridType; + } HeifGridRegionInfo; + HeifGridRegionInfo heifGridRegionInfo_ = {0, 0, 0, 0, 0, 0, false}; + int32_t gridTileWidth_ = 0; + int32_t gridTileHeight_ = 0; #ifdef IMAGE_COLORSPACE_FLAG std::shared_ptr dstColorSpace_ = nullptr; std::shared_ptr srcColorSpace_ = nullptr; diff --git a/plugins/common/libs/image/libextplugin/include/heif_impl/HeifDecoderImpl.h b/plugins/common/libs/image/libextplugin/include/heif_impl/HeifDecoderImpl.h index 1890418d028ba42bcabb9c13b02dedb885de3799..5a0d2da59e9c0d6ab371beab2cc27231e52f56a6 100644 --- a/plugins/common/libs/image/libextplugin/include/heif_impl/HeifDecoderImpl.h +++ b/plugins/common/libs/image/libextplugin/include/heif_impl/HeifDecoderImpl.h @@ -76,10 +76,15 @@ public: void setAuxiliaryDstBuffer(uint8_t* dstBuffer, size_t dstSize, size_t rowStride, void *context); void getFragmentMetadata(Media::Rect& fragmentMetadata); bool SwDecode(bool isSharedMemory = false); + void SetDecodeRegion(int32_t colCount, int32_t rowCount, int32_t left, int32_t top, size_t rowStride); + bool IsHeifHasAlphaImage(); + void SetPadding(int32_t widthPadding, int32_t heightPadding); + bool IsHeifGainmapDivisibility(int32_t primaryDisplayWidth, int32_t primaryDisplayHeight); bool IsHeifGainmapYuv400(); bool IsHeifAlphaYuv400(); void SetSampleFormat(uint32_t sampleSize, ColorManager::ColorSpaceName colorSpaceName, bool isColorSpaceFromCicp); int32_t GetPrimaryLumaBitNum(); + bool IsGainmapDivisibleBySampleSize(uint32_t sampleSize); void setGainmapDstBuffer(uint8_t* dstBuffer, size_t rowStride, void *context); private: bool Reinit(HeifFrameInfo *frameInfo); @@ -108,8 +113,27 @@ private: bool HwDecodeImage(std::shared_ptr &image, GridInfo &gridInfo, sptr *outBuffer, bool isPrimary); - void PreparePackedInput(std::vector> tileImages, - std::vector> &packedInput, size_t gridCount); + void PrepareInput(std::vector> tileImages, + std::vector> &inputs, size_t gridCount); + + bool IsRegionDecode(); + + void DoRegionDecodeForUnpacked(std::vector> tileImages, uint32_t decodeIndex, + std::vector> &unPackedInput, std::shared_ptr &tileImage); + + void HwRegionDecodeForUnPacked(std::vector> tileImages, + std::vector> &unPackedInput, size_t gridCount); + + void HwPrepareUnPackedInput(std::vector> tileImages, + std::vector> &unPackedInput, size_t gridCount); + + void DoSwRegionDecode(std::vector> tileImages, + std::vector> &inputs, std::shared_ptr &tileImage, uint32_t decodeIndex); + + void SwRegionDecode(std::vector> tileImages, + std::vector> &inputs, size_t numGrid); + + bool IsGainmapGrid(); bool AllocateHwOutputBuffer(sptr &hwBuffer, bool isPrimary); @@ -168,6 +192,17 @@ private: uint8_t *dstMemory_; size_t dstRowStride_; SurfaceBuffer *dstHwBuffer_; + typedef struct GridRegionInfo { + uint32_t colCount; + uint32_t rowCount; + uint32_t left; + uint32_t top; + uint32_t heightPadding; + uint32_t widthPadding; + size_t rowStride; + bool isGainmapImage; + } GridRegionInfo; + GridRegionInfo regionInfo_ = {0, 0, 0, 0, 0, 0, 0, false}; std::shared_ptr gainmapImage_ = nullptr; HeifFrameInfo gainmapImageInfo_{}; @@ -182,8 +217,8 @@ private: size_t auxiliaryDstMemorySize_; bool isAuxiliaryDecode_ = false; bool isGainmapDecode_ = false; - SurfaceBuffer *auxiliaryDstHwBuffer_; - SurfaceBuffer *gainMapDstHwBuffer_; + SurfaceBuffer *auxiliaryDstHwbuffer_; + SurfaceBuffer *gainMapDstHwbuffer_; uint32_t sampleSize_ = 1; OHOS::ColorManager::ColorSpaceName colorSpaceName_ = ColorManager::ColorSpaceName::NONE; bool isColorSpaceFromCicp_ = false; diff --git a/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp b/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp index c31f5d7841f63d6d6b26425bcd64a221ebd6f0d8..dffc17e5aa06141b64c8ac8cf8d69163d1bed397 100644 --- a/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp +++ b/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp @@ -116,6 +116,7 @@ namespace { constexpr static int32_t SK_REPETITION_COUNT_INFINITE = -1; constexpr static int32_t SK_REPETITION_COUNT_ERROR_VALUE = -2; constexpr static int32_t BYTES_PER_YUV_SAMPLE = 2; + constexpr static int32_t RGBA8888_PIXEL_BYTE_SIZE = 4; constexpr static uint32_t HEIF_HARDWARE_TILE_MIN_DIM = 128; constexpr static uint32_t HEIF_HARDWARE_TILE_MAX_DIM = 4096; constexpr static uint32_t HEIF_HARDWARE_DISPLAY_MIN_DIM = 128; @@ -403,10 +404,11 @@ static uint32_t HeapMemAlloc(DecodeContext &context, uint64_t count) return SUCCESS; } -uint32_t ExtDecoder::UpdateHeifYuvDataInfo(DecodeContext &context, SkImageInfo &heifInfo) +uint32_t ExtDecoder::UpdateHeifYuvDataInfo(DecodeContext &context, SkImageInfo &heifInfo, + uint32_t gridTileWidth, uint32_t gridTileHeight) { #ifdef HEIF_HW_DECODE_ENABLE - SurfaceBuffer* sbBuffer = reinterpret_cast (context.pixelsBuffer.context); + SurfaceBuffer* sbBuffer = static_cast(context.pixelsBuffer.context); if (sbBuffer == nullptr) { return ERR_DMA_DATA_ABNORMAL; } @@ -417,7 +419,14 @@ uint32_t ExtDecoder::UpdateHeifYuvDataInfo(DecodeContext &context, SkImageInfo & } else { uint32_t uvPlaneIndex = (context.info.pixelFormat == PixelFormat::NV12 || context.info.pixelFormat == PixelFormat::YCBCR_P010) ? NUM_1 : NUM_2; - context.yuvInfo.imageSize = { heifInfo.width(), heifInfo.height() }; + if (IsHeifRegionDecode()) { + context.yuvInfo.imageSize = { heifGridRegionInfo_.colCount * static_cast(gridTileWidth) - + heifGridRegionInfo_.widthPadding, + heifGridRegionInfo_.rowCount * static_cast(gridTileHeight) - + heifGridRegionInfo_.heightPadding }; + } else { + context.yuvInfo.imageSize = { heifInfo.width(), heifInfo.height() }; + } context.yuvInfo.yWidth = static_cast(heifInfo.width()); context.yuvInfo.yHeight = static_cast(heifInfo.height()); context.yuvInfo.uvWidth = static_cast((heifInfo.width() + 1) / NUM_2); @@ -441,19 +450,35 @@ uint32_t ExtDecoder::HeifYUVMemAlloc(OHOS::ImagePlugin::DecodeContext &context, return ERR_IMAGE_INVALID_PARAMETER; } GridInfo gridInfo = heifContext->GetGridInfo(); - - uint64_t byteCount = static_cast(heifInfo.computeMinByteSize()); - bool cond = DmaMemAlloc(context, byteCount, heifInfo) != SUCCESS; - CHECK_INFO_RETURN_RET_LOG(cond, false, "DMA memalloc execution failed."); - uint8_t* dstBuffer = static_cast(context.pixelsBuffer.buffer); - SurfaceBuffer* sbBuffer = reinterpret_cast (context.pixelsBuffer.context); + if (IsHeifRegionDecode()) { + SetHeifDecodeRegion(context, static_cast(gridInfo.tileWidth), + static_cast(gridInfo.tileHeight)); + SkImageInfo dstInfo = SkImageInfo::Make(static_cast(heifGridRegionInfo_.colCount * gridInfo.tileWidth), + static_cast(heifGridRegionInfo_.rowCount * gridInfo.tileHeight), dstInfo_.colorType(), + dstInfo_.alphaType(), dstInfo_.refColorSpace()); + uint64_t byteCount = static_cast(dstInfo.computeMinByteSize()); + CHECK_ERROR_RETURN_RET_LOG(SkImageInfo::ByteSizeOverflowed(byteCount), ERR_IMAGE_TOO_LARGE, + "%{public}s too large byteCount: %{public}llu", __func__, static_cast(byteCount)); + bool cond = DmaMemAlloc(context, byteCount, dstInfo) != SUCCESS; + CHECK_INFO_RETURN_RET_LOG(cond, ERR_DMA_NOT_EXIST, "DmaMemAlloc execution failed."); + IMAGE_LOGI("Do Heif YUV Type Region Decode, xy [%{public}d , %{public}d], wh [%{public}d x %{public}d]", + desiredRegion_.left, desiredRegion_.top, desiredRegion_.width, desiredRegion_.height); + } else { + uint64_t byteCount = static_cast(heifInfo.computeMinByteSize()); + CHECK_ERROR_RETURN_RET_LOG(SkImageInfo::ByteSizeOverflowed(byteCount), ERR_IMAGE_TOO_LARGE, + "%{public}s too large byteCount: %{public}llu", __func__, static_cast(byteCount)); + bool cond = DmaMemAlloc(context, byteCount, heifInfo) != SUCCESS; + CHECK_INFO_RETURN_RET_LOG(cond, ERR_DMA_NOT_EXIST, "DmaMemAlloc execution failed."); + } + auto* dstBuffer = static_cast(context.pixelsBuffer.buffer); + auto* sbBuffer = reinterpret_cast(context.pixelsBuffer.context); int32_t rowStride = sbBuffer->GetStride(); if (rowStride <= 0) { - return false; + return ERR_DMA_DATA_ABNORMAL; } IMAGE_LOGI("ExtDecoder::HeifYUVMemAlloc sb stride is %{public}d, height is %{public}d, size is %{public}d", sbBuffer->GetStride(), sbBuffer->GetHeight(), sbBuffer->GetSize()); - return UpdateHeifYuvDataInfo(context, heifInfo); + return UpdateHeifYuvDataInfo(context, heifInfo, gridInfo.tileWidth, gridInfo.tileHeight); #else return ERR_IMAGE_DATA_UNSUPPORT; #endif @@ -702,6 +727,65 @@ static sk_sp getDesiredColorSpace(SkImageInfo &srcInfo, const Pixe return opts.plDesiredColorSpace->ToSkColorSpace(); } +bool ExtDecoder::IsHeifValidCrop(OHOS::Media::Rect &crop, SkImageInfo &info, + int32_t gridInfoCols, int32_t gridInfoRows) +{ + if (crop.height < ZERO || crop.width < ZERO || crop.left < ZERO || crop.top < ZERO) { + return false; + } + if (crop.height > info.height() - crop.top) { + heifGridRegionInfo_.heightPadding = gridInfoRows * heifGridRegionInfo_.tileHeight - info.height(); + crop.height = info.height() - crop.top; + } + if (crop.width > info.width() - crop.left) { + heifGridRegionInfo_.widthPadding = gridInfoCols * heifGridRegionInfo_.tileWidth - info.width(); + crop.width = info.width() - crop.left; + } + desiredRegion_.left = crop.left; + desiredRegion_.top = crop.top; + desiredRegion_.width = crop.width; + desiredRegion_.height = crop.height; + return true; +} + +uint32_t ExtDecoder::ExtractHeifRegion(const PixelDecodeOptions &opts) +{ +#ifdef HEIF_HW_DECODE_ENABLE + if (opts.CropRect.width <= ZERO || opts.CropRect.height <= ZERO) { + desiredRegion_ = {0, 0, 0, 0}; + heifGridRegionInfo_ = {0, 0, 0, 0, 0, 0, false}; + return SUCCESS; + } + bool cond = codec_ == nullptr; + CHECK_ERROR_RETURN_RET_LOG(cond, SUCCESS, "Decode failed, codec is null"); + SkEncodedImageFormat skEncodeFormat = codec_->getEncodedFormat(); + if (skEncodeFormat == SkEncodedImageFormat::kHEIF) { + auto heifContext = reinterpret_cast(codec_->getHeifContext()); + if (heifContext == nullptr) { + IMAGE_LOGE("Decode heifContext is nullptr"); + return ERR_IMAGE_DECODE_FAILED; + } + GridInfo gridInfo = heifContext->GetGridInfo(); + if (gridInfo.tileWidth != static_cast(info_.width()) || + gridInfo.tileHeight != static_cast(info_.height())) { + heifGridRegionInfo_.isGridType = true; + heifGridRegionInfo_.tileWidth = static_cast(gridInfo.tileWidth); + heifGridRegionInfo_.tileHeight = static_cast(gridInfo.tileHeight); + } + PixelDecodeOptions heifOpts = opts; + if (!IsHeifValidCrop(heifOpts.CropRect, info_, static_cast(gridInfo.cols), + static_cast(gridInfo.rows))) { + IMAGE_LOGE("Invalid heif crop rect xy [%{public}d x %{public}d], wh [%{public}d x %{public}d]", + opts.CropRect.left, opts.CropRect.top, opts.CropRect.width, opts.CropRect.height); + return ERR_IMAGE_INVALID_PARAMETER; + } + } + return SUCCESS; +#else + return SUCCESS; +#endif +} + static bool IsSampleDecodeFormat(SkEncodedImageFormat format) { return format == SkEncodedImageFormat::kJPEG || format == SkEncodedImageFormat::kHEIF || @@ -714,6 +798,10 @@ uint32_t ExtDecoder::CheckDecodeOptions(uint32_t index, const PixelDecodeOptions CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_INVALID_PARAMETER, "SetDecodeOptions failed, width:%{public}d, height:%{public}d is too large", dstInfo_.width(), dstInfo_.height()); + cond = ExtractHeifRegion(opts) != SUCCESS; + CHECK_ERROR_RETURN_RET(cond, ERR_IMAGE_INVALID_PARAMETER); + IMAGE_LOGD("%{public}s IN, dstSubset_: xy [%{public}d x %{public}d] right,bottom: [%{public}d x %{public}d]", + __func__, dstSubset_.left(), dstSubset_.top(), dstSubset_.right(), dstSubset_.bottom()); size_t tempSrcByteCount = info_.computeMinByteSize(); size_t tempDstByteCount = dstInfo_.computeMinByteSize(); bool srcOverflowed = SkImageInfo::ByteSizeOverflowed(tempSrcByteCount); @@ -1029,6 +1117,14 @@ bool ExtDecoder::IsHeifSharedMemDecode(DecodeContext &context) void ExtDecoder::FillYuvInfo(DecodeContext &context, SkImageInfo &dstInfo) { if (context.allocatorType == AllocatorType::SHARE_MEM_ALLOC) { + if (IsHeifRegionDecode()) { + context.yuvInfo.imageSize = { heifGridRegionInfo_.colCount * heifGridRegionInfo_.tileWidth - + heifGridRegionInfo_.widthPadding, + heifGridRegionInfo_.rowCount * heifGridRegionInfo_.tileHeight - + heifGridRegionInfo_.heightPadding }; + } else { + context.yuvInfo.imageSize = { dstInfo.width(), dstInfo.height() }; + } context.yuvInfo.imageSize = {dstInfo.width(), dstInfo.height()}; context.yuvInfo.yWidth = static_cast(dstInfo.width()); context.yuvInfo.yHeight = static_cast(dstInfo.height()); @@ -1060,23 +1156,52 @@ bool SetOutPutFormat(OHOS::Media::PixelFormat pixelFormat, HeifDecoderImpl* deco } #endif +void ExtDecoder::UpdateDstInfoAndOutInfo(DecodeContext &context) +{ + if (sampleSize_ != DEFAULT_SAMPLE_SIZE) { + sampleSize_ = DEFAULT_SAMPLE_SIZE; + dstInfo_ = SkImageInfo::Make(info_.width(), info_.height(), dstInfo_.colorType(), + dstInfo_.alphaType(), dstInfo_.refColorSpace()); + context.outInfo.size.width = info_.width(); + context.outInfo.size.height = info_.height(); + } +} + uint32_t ExtDecoder::DoHeifSharedMemDecode(DecodeContext &context) { #ifdef HEIF_HW_DECODE_ENABLE auto decoder = reinterpret_cast(codec_->getHeifContext()); CHECK_ERROR_RETURN_RET_LOG(decoder == nullptr, ERR_IMAGE_DATA_UNSUPPORT, "Decode HeifDecoder is nullptr"); - uint64_t rowStride = dstInfo_.minRowBytes64(); - uint64_t byteCount = dstInfo_.computeMinByteSize(); + uint64_t byteCount; + uint64_t rowStride; + if (IsHeifRegionDecode()) { + UpdateHeifRegionDstInfo(context); + } + UpdateDstInfoAndOutInfo(context); + rowStride = dstInfo_.minRowBytes64(); + byteCount = dstInfo_.computeMinByteSize(); + GridInfo gridInfo = decoder->GetGridInfo(); if (IsYuv420Format(context.info.pixelFormat)) { - rowStride = static_cast(dstInfo_.width()); - byteCount = JpegDecoderYuv::GetYuvOutSize(dstInfo_.width(), dstInfo_.height()); + if (IsHeifRegionDecode()) { + UpdateHeifRegionDstInfo(context); + rowStride = gridInfo.tileWidth * static_cast(heifGridRegionInfo_.colCount) - + static_cast(heifGridRegionInfo_.widthPadding); + byteCount = JpegDecoderYuv::GetYuvOutSize(dstInfo_.width(), dstInfo_.height()); + } else { + rowStride = static_cast(dstInfo_.width()); + byteCount = JpegDecoderYuv::GetYuvOutSize(dstInfo_.width(), dstInfo_.height()); + } } CHECK_ERROR_RETURN_RET_LOG(SkImageInfo::ByteSizeOverflowed(byteCount), ERR_IMAGE_TOO_LARGE, - "%{public}s not support sample decode, original image size: %{public}llu", __func__, - static_cast(byteCount)); + "%{public}s too large byteCount: %{public}llu", __func__, static_cast(byteCount)); CHECK_ERROR_RETURN_RET(!SetOutPutFormat(context.info.pixelFormat, decoder), ERR_IMAGE_DATA_UNSUPPORT); uint32_t res = ShareMemAlloc(context, byteCount); CHECK_ERROR_RETURN_RET(res != SUCCESS, res); + if (IsHeifRegionDecode()) { + decoder->SetDecodeRegion(heifGridRegionInfo_.colCount, heifGridRegionInfo_.rowCount, + desiredRegion_.left, desiredRegion_.top, rowStride); + decoder->SetPadding(heifGridRegionInfo_.widthPadding, heifGridRegionInfo_.heightPadding); + } decoder->setDstBuffer(reinterpret_cast(context.pixelsBuffer.buffer), rowStride, nullptr); bool decodeRet = decoder->SwDecode(context.isAppUseAllocator); if (!decodeRet) { @@ -1090,6 +1215,96 @@ uint32_t ExtDecoder::DoHeifSharedMemDecode(DecodeContext &context) #endif } +OHOS::Media::Size ExtDecoder::GetHeifRegionGridSize() +{ + OHOS::Media::Size heifGridSize = {gridTileWidth_, gridTileHeight_}; + return heifGridSize; +} + +void ExtDecoder::SetHeifDecodeRegion(DecodeContext &context, int32_t gridTileWidth, int32_t gridTileHeight) +{ + if (gridTileWidth == ZERO || gridTileHeight == ZERO) { + return; + } + double tempRegionColCount = ((desiredRegion_.left % gridTileWidth) + desiredRegion_.width) / + static_cast(gridTileWidth); + double tempRegionRowCount = ((desiredRegion_.top % gridTileHeight) + desiredRegion_.height) / + static_cast(gridTileHeight); + heifGridRegionInfo_.colCount = ceil(tempRegionColCount); + heifGridRegionInfo_.rowCount = ceil(tempRegionRowCount); + gridTileWidth_ = gridTileWidth; + gridTileHeight_ = gridTileHeight; + context.outInfo.size.height = heifGridRegionInfo_.rowCount * + gridTileHeight - heifGridRegionInfo_.heightPadding; + context.outInfo.size.width = heifGridRegionInfo_.colCount * + gridTileWidth - heifGridRegionInfo_.widthPadding; +} + +void ExtDecoder::UpdateHeifRegionDstInfo(DecodeContext &context) +{ +#ifdef HEIF_HW_DECODE_ENABLE + auto heifContext = reinterpret_cast(codec_->getHeifContext()); + if (heifContext == nullptr) { + IMAGE_LOGE("Decode heifContext is nullptr"); + return; + } + GridInfo gridInfo = heifContext->GetGridInfo(); + SetHeifDecodeRegion(context, static_cast(gridInfo.tileWidth), static_cast(gridInfo.tileHeight)); + if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) { + dstInfo_ = SkImageInfo::Make(heifGridRegionInfo_.colCount * gridInfo.tileWidth - + heifGridRegionInfo_.widthPadding, heifGridRegionInfo_.rowCount * + gridInfo.tileHeight - heifGridRegionInfo_.heightPadding, + dstInfo_.colorType(), dstInfo_.alphaType(), dstInfo_.refColorSpace()); + } else { + dstInfo_ = SkImageInfo::Make(heifGridRegionInfo_.colCount * gridInfo.tileWidth, + heifGridRegionInfo_.rowCount * gridInfo.tileHeight, + dstInfo_.colorType(), dstInfo_.alphaType(), dstInfo_.refColorSpace()); + } +#else + return; +#endif +} + +void ExtDecoder::UpdateHeifSKInfo(DecodeContext &context, uint64_t &rowStride) +{ +#ifdef HEIF_HW_DECODE_ENABLE + auto decoder = reinterpret_cast(codec_->getHeifContext()); + if (decoder == nullptr) { + IMAGE_LOGE("Decode HeifDecoder is nullptr"); + return; + } + auto dstBuffer = reinterpret_cast(context.pixelsBuffer.context); + decoder->SetDecodeRegion(heifGridRegionInfo_.colCount, heifGridRegionInfo_.rowCount, + desiredRegion_.left, desiredRegion_.top, dstBuffer->GetStride()); + dstInfo_ = SkImageInfo::Make(info_.width(), info_.height(), dstInfo_.colorType(), + dstInfo_.alphaType(), dstInfo_.refColorSpace()); + rowStride = dstInfo_.minRowBytes64(); +#else + return; +#endif +} + +bool ExtDecoder::IsHeifRegionDecode() +{ +#ifdef HEIF_HW_DECODE_ENABLE + if (desiredRegion_.width > ZERO && desiredRegion_.height > ZERO && heifGridRegionInfo_.isGridType && + cropAndScaleStrategy_ != OHOS::Media::CropAndScaleStrategy::SCALE_FIRST) { + auto decoder = reinterpret_cast(codec_->getHeifContext()); + bool cond = decoder == nullptr; + CHECK_ERROR_RETURN_RET_LOG(cond, false, "Decode Heifdecoder is nullptr"); + if (decoder->IsHeifHasAlphaImage() || !decoder->IsHeifGainmapDivisibility(info_.width(), info_.height()) || + decoder->IsHeifGainmapYuv400()) { + IMAGE_LOGI("Heif image contains alpha channels, or the size not be an integer multiple of GainMap"); + return false; + } + return true; + } + return false; +#else + return false; +#endif +} + uint32_t ExtDecoder::DoRegionDecode(DecodeContext &context) { #ifdef SK_ENABLE_OHOS_CODEC @@ -1241,8 +1456,27 @@ bool ExtDecoder::IsSupportHeifHardwareDecode(const PixelDecodeOptions &opts) bool ExtDecoder::IsDivisibleBySampleSize() { - return info_.width() % static_cast(sampleSize_) == 0 && - info_.height() % static_cast(sampleSize_) == 0; +#ifdef HEIF_HW_DECODE_ENABLE + auto decoder = reinterpret_cast(codec_->getHeifContext()); + bool cond = decoder == nullptr; + CHECK_ERROR_RETURN_RET_LOG(cond, false, "Decode Heifdecoder is nullptr"); + GridInfo gridInfo = decoder->GetGridInfo(); + if (gridInfo.tileWidth % sampleSize_ != 0 || gridInfo.tileHeight % sampleSize_ != 0) { + return false; + } + if (IsYuv420Format(heifPixelFormat_) && + (info_.height() / static_cast(sampleSize_)) % NUM_2 != 0) { + return false; + } + if (decoder->IsGainmapDivisibleBySampleSize(sampleSize_) && + info_.width() % static_cast(sampleSize_) == 0 && + info_.height() % static_cast(sampleSize_) == 0) { + return true; + } + return false; +#else + return false; +#endif } void ExtDecoder::SetHeifSampleSize(const PixelDecodeOptions &opts, int &dstWidth, int &dstHeight, @@ -1262,33 +1496,30 @@ void ExtDecoder::SetHeifSampleSize(const PixelDecodeOptions &opts, int &dstWidth #endif } -bool ExtDecoder::DoHeifSwDecode(DecodeContext &context) +bool ExtDecoder::DoHeifSwDecode(OHOS::ImagePlugin::DecodeContext &context) { #ifdef HEIF_HW_DECODE_ENABLE - sampleSize_ = 1; - context.outInfo.size.width = static_cast(info_.width()); - context.outInfo.size.height = static_cast(info_.height()); auto decoder = reinterpret_cast(codec_->getHeifContext()); - if (decoder == nullptr) { - IMAGE_LOGE("Decode HeifDecoder is nullptr"); - return false; - } + bool cond = decoder == nullptr; + CHECK_ERROR_RETURN_RET_LOG(cond, false, "Decode Heifdecoder is nullptr"); ReleaseOutputBuffer(context, context.allocatorType); uint64_t byteCount = info_.computeMinByteSize(); - CHECK_ERROR_RETURN_RET_LOG(SkImageInfo::ByteSizeOverflowed(byteCount), false, - "%{public}s not support sample decode, original image size: %{public}llu", __func__, - static_cast(byteCount)); - //If the HWdecode failed, software does not support samplesize, allocate memory based on original image. - bool cond = false; + //If the HWdecode failed, software does not support setting samplesize, allocate memory based on original image. + cond = false; + sampleSize_ = DEFAULT_SAMPLE_SIZE; + context.outInfo.size.width = info_.width(); + context.outInfo.size.height = info_.height(); if (IsHeifToYuvDecode(context)) { cond = HeifYUVMemAlloc(context, info_) != SUCCESS; } else { + CHECK_ERROR_RETURN_RET_LOG(SkImageInfo::ByteSizeOverflowed(byteCount), false, + "%{public}s too large byteCount: %{public}llu", __func__, static_cast(byteCount)); cond = DmaMemAlloc(context, byteCount, info_) != SUCCESS; } CHECK_ERROR_RETURN_RET(cond, false); auto dstBuffer = reinterpret_cast(context.pixelsBuffer.context); - decoder->SetSampleFormat(DEFAULT_SAMPLE_SIZE, heifColorSpaceName_, heifIsColorSpaceFromCicp_); - decoder->setDstBuffer(reinterpret_cast(context.pixelsBuffer.buffer), + decoder->SetSampleFormat(DEFAULT_SCALE_SIZE, heifColorSpaceName_, heifIsColorSpaceFromCicp_); + decoder->setDstBuffer(reinterpret_cast(context.pixelsBuffer.buffer), dstBuffer->GetStride(), context.pixelsBuffer.context); bool decodeRet = decoder->SwDecode(false); return decodeRet; @@ -1297,29 +1528,38 @@ bool ExtDecoder::DoHeifSwDecode(DecodeContext &context) #endif } -uint32_t ExtDecoder::DoHeifToRgbDecode(DecodeContext &context) +uint32_t ExtDecoder::DoHeifToRgbDecode(OHOS::ImagePlugin::DecodeContext &context) { #ifdef HEIF_HW_DECODE_ENABLE auto decoder = reinterpret_cast(codec_->getHeifContext()); - if (decoder == nullptr) { - IMAGE_LOGE("DoHeifToRgbDecode HeifDecoder is nullptr"); - return ERR_IMAGE_DATA_UNSUPPORT; + bool cond = decoder == nullptr; + CHECK_ERROR_RETURN_RET_LOG(cond, false, "Decode Heifdecoder is nullptr"); + + if (IsHeifRegionDecode()) { + UpdateHeifRegionDstInfo(context); } uint64_t byteCount = dstInfo_.computeMinByteSize(); if (ImageUtils::IsSdrPixelMapReuseSuccess(context, info_.width(), info_.height(), reusePixelmap_)) { IMAGE_LOGI("HEIF RGB Maindecode reusePixelmap success"); } else { + CHECK_ERROR_RETURN_RET_LOG(SkImageInfo::ByteSizeOverflowed(byteCount), ERR_IMAGE_TOO_LARGE, + "%{public}s too large byteCount: %{public}llu", __func__, static_cast(byteCount)); bool cond = DmaMemAlloc(context, byteCount, dstInfo_) != SUCCESS; CHECK_ERROR_RETURN_RET(cond, ERR_IMAGE_DATA_UNSUPPORT); } auto dstBuffer = reinterpret_cast(context.pixelsBuffer.context); + if (IsHeifRegionDecode()) { + decoder->SetDecodeRegion(heifGridRegionInfo_.colCount, heifGridRegionInfo_.rowCount, + desiredRegion_.left, desiredRegion_.top, dstBuffer->GetStride()); + IMAGE_LOGI("Do Heif RGB Type Region Decode, xy [%{public}d , %{public}d], wh [%{public}d x %{public}d]", + desiredRegion_.left, desiredRegion_.top, desiredRegion_.width, desiredRegion_.height); + } decoder->SetSampleFormat(sampleSize_, heifColorSpaceName_, heifIsColorSpaceFromCicp_); - decoder->setDstBuffer(reinterpret_cast(context.pixelsBuffer.buffer), + decoder->setDstBuffer(reinterpret_cast(context.pixelsBuffer.buffer), dstBuffer->GetStride(), context.pixelsBuffer.context); SetOutPutFormat(context.info.pixelFormat, decoder); bool decodeRet = decoder->decode(nullptr); if (!decodeRet && sampleSize_ != DEFAULT_SAMPLE_SIZE) { - IMAGE_LOGD("hwdecode failed, do heif sw decode"); decodeRet = DoHeifSwDecode(context); } if (!decodeRet) { @@ -1385,7 +1625,7 @@ uint32_t ExtDecoder::Decode(uint32_t index, DecodeContext &context) context.outInfo.size.width = dstInfo_.width(); context.outInfo.size.height = dstInfo_.height(); SkEncodedImageFormat skEncodeFormat = codec_->getEncodedFormat(); -#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM) +#if !defined(CROSS_PLATFORM) int timerFd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); if (timerFd >= 0) { close(timerFd); @@ -1408,7 +1648,7 @@ uint32_t ExtDecoder::Decode(uint32_t index, DecodeContext &context) if (result == JpegYuvDecodeError_Success) { return result; } - IMAGE_LOGI("Decode sample not support, apply rgb decode"); + IMAGE_LOGI("DecodeToYuv420 failed, decode rgba then convert"); context.pixelsBuffer.buffer = nullptr; context.info.pixelFormat = PixelFormat::RGBA_8888; #endif @@ -1421,6 +1661,7 @@ uint32_t ExtDecoder::Decode(uint32_t index, DecodeContext &context) if (tmpBuffer == nullptr) { IMAGE_LOGE("Make unique pointer failed, byteCount: %{public}llu", static_cast(byteCount)); + return ERR_IMAGE_DECODE_FAILED; } dstBuffer = tmpBuffer.get(); byteCount = byteCount / NUM_4 * NUM_3; @@ -2579,6 +2820,10 @@ uint32_t ExtDecoder::DoHeifToYuvDecode(OHOS::ImagePlugin::DecodeContext &context auto dstBuffer = reinterpret_cast(context.pixelsBuffer.context); decoder->setOutputColor(context.info.pixelFormat == PixelFormat::NV12 ? kHeifColorFormat_NV12 : kHeifColorFormat_NV21); + if (IsHeifRegionDecode()) { + decoder->SetDecodeRegion(heifGridRegionInfo_.colCount, heifGridRegionInfo_.rowCount, + desiredRegion_.left, desiredRegion_.top, dstBuffer->GetStride()); + } decoder->SetSampleFormat(sampleSize_, heifColorSpaceName_, heifIsColorSpaceFromCicp_); decoder->setDstBuffer(reinterpret_cast(context.pixelsBuffer.buffer), dstBuffer->GetStride(), context.pixelsBuffer.context); @@ -2603,35 +2848,51 @@ bool ExtDecoder::IsHeifToSingleHdrDecode(const DecodeContext& context) const context.info.pixelFormat == PixelFormat::YCRCB_P010); } -uint32_t ExtDecoder::DoHeifToSingleHdrDecode(DecodeContext &context) +uint32_t ExtDecoder::AllocHeifSingleHdrBuffer(DecodeContext &context) { #ifdef HEIF_HW_DECODE_ENABLE - auto decoder = reinterpret_cast(codec_->getHeifContext()); - bool cond = decoder == nullptr; - CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_DATA_UNSUPPORT, "SingleHdrDecode, HeifDecoder is nullptr"); - - uint64_t byteCount = static_cast(info_.computeMinByteSize()); - uint64_t dstByteCount = static_cast(dstInfo_.computeMinByteSize()); - CHECK_ERROR_RETURN_RET_LOG(SkImageInfo::ByteSizeOverflowed(dstByteCount), ERR_IMAGE_TOO_LARGE, - "%{public}s not support sample decode, original image size: %{public}llu", __func__, - static_cast(dstByteCount)); + uint64_t byteCount = static_cast(dstInfo_.computeMinByteSize()); if (context.info.pixelFormat == PixelFormat::YCBCR_P010 || context.info.pixelFormat == PixelFormat::YCRCB_P010) { uint32_t allocRet = HeifYUVMemAlloc(context, dstInfo_); - cond = allocRet != SUCCESS; + bool cond = allocRet != SUCCESS; CHECK_ERROR_RETURN_RET(cond, allocRet); } else { - if (DmaMemAlloc(context, byteCount, dstInfo_) != SUCCESS) { - return ERR_IMAGE_DATA_UNSUPPORT; + if (IsHeifRegionDecode()) { + UpdateHeifRegionDstInfo(context); + byteCount = dstInfo_.computeMinByteSize(); + IMAGE_LOGI("Do Heif Single Hdr Region Decode, xy [%{public}d , %{public}d], wh [%{public}d x %{public}d]", + desiredRegion_.left, desiredRegion_.top, desiredRegion_.width, desiredRegion_.height); } + CHECK_ERROR_RETURN_RET_LOG(SkImageInfo::ByteSizeOverflowed(byteCount), ERR_IMAGE_TOO_LARGE, + "%{public}s too large byteCount: %{public}llu", __func__, static_cast(byteCount)); + bool cond = DmaMemAlloc(context, byteCount, dstInfo_) != SUCCESS; + CHECK_ERROR_RETURN_RET(cond, ERR_IMAGE_DATA_UNSUPPORT); } + return SUCCESS; +#else + return ERR_IMAGE_DATA_UNSUPPORT; +#endif +} +uint32_t ExtDecoder::DoHeifToSingleHdrDecode(DecodeContext &context) +{ +#ifdef HEIF_HW_DECODE_ENABLE + auto decoder = reinterpret_cast(codec_->getHeifContext()); + bool cond = decoder == nullptr; + CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_DATA_UNSUPPORT, "SingleHdrDecode, HeifDecoder is nullptr"); + uint32_t ret = AllocHeifSingleHdrBuffer(context); + CHECK_ERROR_RETURN_RET_LOG(ret != SUCCESS, ret, "SingleHdrDecode, alloc dstBuffer failed"); auto dstBuffer = reinterpret_cast(context.pixelsBuffer.context); - bool cond = dstBuffer == nullptr; + cond = dstBuffer == nullptr; CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_DATA_UNSUPPORT, "SingleHdrDecode, dstBuffer is nullptr"); SkHeifColorFormat heifFormat = kHeifColorFormat_RGBA_1010102; auto formatSearch = HEIF_FORMAT_MAP.find(context.info.pixelFormat); heifFormat = (formatSearch != HEIF_FORMAT_MAP.end()) ? formatSearch->second : kHeifColorFormat_RGBA_1010102; decoder->setOutputColor(heifFormat); + if (IsHeifRegionDecode()) { + decoder->SetDecodeRegion(heifGridRegionInfo_.colCount, heifGridRegionInfo_.rowCount, + desiredRegion_.left, desiredRegion_.top, dstBuffer->GetStride()); + } decoder->SetSampleFormat(DEFAULT_SAMPLE_SIZE, heifColorSpaceName_, heifIsColorSpaceFromCicp_); decoder->setDstBuffer(reinterpret_cast(context.pixelsBuffer.buffer), dstBuffer->GetStride(), context.pixelsBuffer.context); @@ -2724,6 +2985,50 @@ bool ExtDecoder::GetHeifFragmentMetadata(Media::Rect &metadata) return false; } +bool ExtDecoder::HeifGainMapRegionCrop(DecodeContext &gainmapRegionContext, int32_t rowStride, uint8_t* dstBuffer, + uint32_t gainmapWidth, uint32_t gainmapHeight) +{ +#ifdef HEIF_HW_DECODE_ENABLE + bool cond = (gainmapWidth == ZERO || gainmapHeight == ZERO); + CHECK_ERROR_RETURN_RET_LOG(cond, false, "gainmap width or gainmap height is ZERO"); + int32_t gainmapWidthRatio = info_.width() / static_cast(gainmapWidth); + int32_t gainmapHeightRatio = info_.height() / static_cast(gainmapHeight); + cond = (gainmapWidthRatio == ZERO || gainmapHeightRatio == ZERO); + CHECK_ERROR_RETURN_RET_LOG(cond, false, "gainmap widthRatio or gainmap heightRatio is ZERO"); + SkImageInfo dstRegionInfo = SkImageInfo::Make(static_cast(heifGridRegionInfo_.tileWidth * + heifGridRegionInfo_.colCount / gainmapWidthRatio), + static_cast(heifGridRegionInfo_.tileHeight * heifGridRegionInfo_.rowCount / + gainmapHeightRatio), dstInfo_.colorType(), dstInfo_.alphaType(), dstInfo_.refColorSpace()); + uint64_t byteCount = static_cast(dstRegionInfo.computeMinByteSize()); + gainmapRegionContext.info.size.width = heifGridRegionInfo_.tileWidth * + heifGridRegionInfo_.colCount / gainmapWidthRatio; + gainmapRegionContext.info.size.height = heifGridRegionInfo_.tileHeight * + heifGridRegionInfo_.rowCount / gainmapHeightRatio; + cond = DmaMemAlloc(gainmapRegionContext, byteCount, dstRegionInfo) != SUCCESS; + CHECK_ERROR_RETURN_RET(cond, false); + auto* sbBuffer = reinterpret_cast(gainmapRegionContext.pixelsBuffer.context); + int32_t rowRegionStride = sbBuffer->GetStride(); + auto* dstRegionBuffer = static_cast(gainmapRegionContext.pixelsBuffer.buffer); + int32_t left = desiredRegion_.left / heifGridRegionInfo_.tileWidth * + heifGridRegionInfo_.tileWidth / gainmapWidthRatio; + int32_t top = desiredRegion_.top / heifGridRegionInfo_.tileHeight * + heifGridRegionInfo_.tileHeight / gainmapHeightRatio; + int32_t srcOffset = rowStride * top + left * RGBA8888_PIXEL_BYTE_SIZE; + for (int32_t index = 0; index < (heifGridRegionInfo_.tileHeight * heifGridRegionInfo_.rowCount - + heifGridRegionInfo_.heightPadding) / gainmapHeightRatio; index++) { + uint8_t* srcRow = dstBuffer + srcOffset + index * rowStride; + uint8_t* dstRow = dstRegionBuffer + index * rowRegionStride; + int32_t cropLength = (heifGridRegionInfo_.tileWidth * heifGridRegionInfo_.colCount - + heifGridRegionInfo_.widthPadding) / gainmapWidthRatio * RGBA8888_PIXEL_BYTE_SIZE; + errno_t err = memcpy_s(dstRow, cropLength, srcRow, cropLength); + cond = err != EOK; + CHECK_ERROR_RETURN_RET_LOG(cond, false, "handle heifgainmap memcpy failed."); + } + return true; +#endif + return false; +} + bool ExtDecoder::DecodeHeifGainMap(DecodeContext& context) { #ifdef HEIF_HW_DECODE_ENABLE @@ -2740,9 +3045,9 @@ bool ExtDecoder::DecodeHeifGainMap(DecodeContext& context) CHECK_INFO_RETURN_RET_LOG(cond, false, "DecodeHeifGainmap size exceeds the maximum value"); IMAGE_LOGD("DecodeHeifGainmap size:%{public}d-%{public}d", width, height); uint32_t dstGainmapWidth = width / sampleSize_; - uint32_t dstGianmapHeight = height / sampleSize_; - IMAGE_LOGD("DecodeHeifGainmap dstsize:%{public}d-%{public}d", dstGainmapWidth, dstGianmapHeight); - SkImageInfo dstInfo = SkImageInfo::Make(static_cast(dstGainmapWidth), static_cast(dstGianmapHeight), + uint32_t dstGainmapHeight = height / sampleSize_; + IMAGE_LOGD("DecodeHeifGainmap sample size:%{public}d-%{public}d", dstGainmapWidth, dstGainmapHeight); + SkImageInfo dstInfo = SkImageInfo::Make(static_cast(dstGainmapWidth), static_cast(dstGainmapHeight), dstInfo_.colorType(), dstInfo_.alphaType(), dstInfo_.refColorSpace()); uint64_t byteCount = static_cast(dstInfo.computeMinByteSize()); context.info.size.width = static_cast(dstGainmapWidth); @@ -2761,6 +3066,19 @@ bool ExtDecoder::DecodeHeifGainMap(DecodeContext& context) FreeContextBuffer(context.freeFunc, context.allocatorType, context.pixelsBuffer); return false; } + if (IsHeifRegionDecode()) { + DecodeContext gainmapRegionContext; + if (HeifGainMapRegionCrop(gainmapRegionContext, rowStride, dstBuffer, width, height)) { + context = gainmapRegionContext; + IMAGE_LOGI("Do Heif GainMap Region Decode success"); + } else { + FreeContextBuffer(context.freeFunc, context.allocatorType, context.pixelsBuffer); + FreeContextBuffer(gainmapRegionContext.freeFunc, gainmapRegionContext.allocatorType, + gainmapRegionContext.pixelsBuffer); + IMAGE_LOGE("Heif gainmap region decode failed."); + return false; + } + } return true; #endif return false; diff --git a/plugins/common/libs/image/libextplugin/src/heif_impl/HeifDecoderImpl.cpp b/plugins/common/libs/image/libextplugin/src/heif_impl/HeifDecoderImpl.cpp index adc8359226d66f53b4d675cef27c0adf1f7d2a04..421bac593cdf0e906819a83f98791c0637e2a3be 100644 --- a/plugins/common/libs/image/libextplugin/src/heif_impl/HeifDecoderImpl.cpp +++ b/plugins/common/libs/image/libextplugin/src/heif_impl/HeifDecoderImpl.cpp @@ -44,6 +44,8 @@ #undef LOG_TAG #define LOG_TAG "HeifDecoderImpl" +#define IS_VALID_GAINMAP_DIVISOR(x) ((x) == 1 || (x) == 2 || (x) == 4) + namespace OHOS { namespace ImagePlugin { using namespace Media; @@ -120,6 +122,14 @@ static sptr GetCodecManager() return g_codecMgrDecode; } +static void ReinitGridinfo(GridInfo &gridInfo, GridInfo tempGridInfo) +{ + gridInfo.displayWidth = tempGridInfo.displayWidth; + gridInfo.displayHeight = tempGridInfo.displayHeight; + gridInfo.cols = tempGridInfo.cols; + gridInfo.rows = tempGridInfo.rows; +} + static PixelFormat SkHeifColorFormat2PixelFormat(SkHeifColorFormat format) { PixelFormat res = PixelFormat::UNKNOWN; @@ -158,10 +168,11 @@ static PixelFormat SkHeifColorFormat2PixelFormat(SkHeifColorFormat format) HeifDecoderImpl::HeifDecoderImpl() : outPixelFormat_(PixelFormat::RGBA_8888), dstMemory_(nullptr), dstRowStride_(0), dstHwBuffer_(nullptr), + regionInfo_({0, 0, 0, 0, 0, 0, 0, false}), gainmapDstMemory_(nullptr), gainmapDstRowStride_(0), auxiliaryDstMemory_(nullptr), auxiliaryDstRowStride_(0), auxiliaryDstMemorySize_(0), isAuxiliaryDecode_(false), - auxiliaryDstHwBuffer_(nullptr), gainMapDstHwBuffer_(nullptr) {} + auxiliaryDstHwbuffer_(nullptr), gainMapDstHwbuffer_(nullptr) {} HeifDecoderImpl::~HeifDecoderImpl() { @@ -578,6 +589,15 @@ bool HeifDecoderImpl::decodeAuxiliaryMap() return DoDecodeAuxiliaryImage(auxiliaryImage_, auxiliaryGridInfo_, auxiliaryDstMemory_, auxiliaryDstRowStride_); } +bool HeifDecoderImpl::IsRegionDecode() +{ + std::shared_ptr alphaImage = primaryImage_->GetAlphaImage(); + if (regionInfo_.colCount > 0 && regionInfo_.rowCount > 0 && alphaImage == nullptr && !IsGainmapGrid()) { + return true; + } + return false; +} + void HeifDecoderImpl::AllocateHwOutputBuffer(sptr &hwBuffer, bool isPrimary) { //hardware decode buffer. @@ -632,6 +652,39 @@ bool HeifDecoderImpl::HwDecodeImage(std::shared_ptr &image, GridInfo return res; } +void HeifDecoderImpl::DoRegionDecodeForUnpacked(std::vector> tileImages, + uint32_t decodeIndex, std::vector> &unPackedInput, std::shared_ptr &tileImage) +{ + for (uint32_t indexRow = 0; indexRow < regionInfo_.rowCount; indexRow++) { + for (uint32_t indexCol = 0; indexCol < regionInfo_.colCount; indexCol++) { + tileImage = tileImages[indexRow * gridInfo_.cols + decodeIndex + indexCol]; + parser_->GetItemData(tileImage->GetItemId(), + &unPackedInput[indexCol + indexRow * regionInfo_.colCount + 1], heif_no_header); + ProcessChunkHead(unPackedInput[indexCol + indexRow * regionInfo_.colCount + 1].data(), + unPackedInput[indexCol + indexRow * regionInfo_.colCount + 1].size()); + } + } +} + +void HeifDecoderImpl::HwRegionDecodeForUnPacked(std::vector> tileImages, + std::vector> &unPackedInput, size_t gridCount) +{ + unPackedInput.resize(regionInfo_.colCount * regionInfo_.rowCount + 1); + uint32_t rowIndex = regionInfo_.top / gridInfo_.tileHeight; + uint32_t colIndex = regionInfo_.left / gridInfo_.tileWidth; + uint32_t decodeIndex = rowIndex * gridInfo_.cols + colIndex; + for (uint32_t index = 0; index < gridCount; ++index) { + std::shared_ptr &tileImage = tileImages[index]; + if (index == 0) { + parser_->GetItemData(tileImage->GetItemId(), &unPackedInput[index], heif_only_header); + ProcessChunkHead(unPackedInput[index].data(), unPackedInput[index].size()); + } + if (index == decodeIndex) { + DoRegionDecodeForUnpacked(tileImages, decodeIndex, unPackedInput, tileImage); + } + } +} + void HeifDecoderImpl::HwPrepareUnPackedInput(std::vector> tileImages, std::vector> &unPackedInput, size_t gridCount) { @@ -648,9 +701,25 @@ void HeifDecoderImpl::HwPrepareUnPackedInput(std::vector> tileImages, + std::vector> &inputs, size_t gridCount) +{ + if (IsRegionDecode()) { + HwRegionDecodeForUnPacked(tileImages, inputs, gridCount); + } else { + HwPrepareUnPackedInput(tileImages, inputs, gridCount); + } +} + void HeifDecoderImpl::SetHwDecodeInfo(GridInfo &gridInfo, OHOS::HDI::Codec::Image::V2_1::CodecHeifDecInfo &heifDecodeInfo) { + if (IsRegionDecode() && !isGainmapDecode_) { + gridInfo.displayWidth = regionInfo_.colCount * gridInfo.tileWidth; + gridInfo.displayHeight = regionInfo_.rowCount * gridInfo.tileHeight; + gridInfo.cols = regionInfo_.colCount; + gridInfo.rows = regionInfo_.rowCount; + } OHOS::HDI::Codec::Image::V2_1::GridInfo hwGridInfo = { gridInfo.displayWidth, gridInfo.displayHeight, @@ -660,6 +729,7 @@ void HeifDecoderImpl::SetHwDecodeInfo(GridInfo &gridInfo, gridInfo.tileWidth, gridInfo.tileHeight, }; + heifDecodeInfo = { .gridInfo = hwGridInfo, .sampleSize = sampleSize_, @@ -669,10 +739,8 @@ void HeifDecoderImpl::SetHwDecodeInfo(GridInfo &gridInfo, bool HeifDecoderImpl::HwDecodeGrids(std::shared_ptr &image, GridInfo &gridInfo, sptr &hwBuffer) { - if (image == nullptr) { - IMAGE_LOGE("HeifDecoderImpl::DecodeGrids image is nullptr"); - return false; - } + bool cond = image == nullptr; + CHECK_ERROR_RETURN_RET_LOG(cond, false, "HeifDecoderImpl::DecodeGrids image is nullptr"); std::vector> tileImages; parser_->GetTileImages(image->GetItemId(), tileImages); if (tileImages.empty()) { @@ -685,7 +753,7 @@ bool HeifDecoderImpl::HwDecodeGrids(std::shared_ptr &image, return false; } std::vector> inputs; - HwPrepareUnPackedInput(tileImages, inputs, gridCount); + PrepareInput(tileImages, inputs, gridCount); GridInfo tempGridInfo = gridInfo; std::vector> hwInputs; if (!copyToAshmem(inputs, hwInputs)) { @@ -709,8 +777,13 @@ bool HeifDecoderImpl::HwDecodeGrids(std::shared_ptr &image, result, gridInfo.displayWidth, gridInfo.displayHeight, hwBuffer->GetFormat(), gridInfo.cols, gridInfo.rows, gridInfo.tileWidth, gridInfo.tileHeight, inputs[0].size()); SetHardwareDecodeErrMsg(gridInfo.tileWidth, gridInfo.tileHeight); + if (IsRegionDecode()) { + ReinitGridinfo(gridInfo, tempGridInfo); + } return false; } + ReinitGridinfo(gridInfo, tempGridInfo); + regionInfo_ = {0, 0, 0, 0, 0, 0, 0, false}; return true; } @@ -819,6 +892,36 @@ bool HeifDecoderImpl::SwDecodeImage(std::shared_ptr &image, HevcSoftD return res; } +void HeifDecoderImpl::DoSwRegionDecode(std::vector> tileImages, + std::vector> &inputs, std::shared_ptr &tileImage, uint32_t decodeIndex) +{ + for (uint32_t indexRow = 0; indexRow < regionInfo_.rowCount; indexRow++) { + for (uint32_t indexCol = 0; indexCol < regionInfo_.colCount; indexCol++) { + tileImage = tileImages[indexRow * gridInfo_.cols + decodeIndex + indexCol]; + parser_->GetItemData(tileImage->GetItemId(), + &inputs[indexCol + indexRow * regionInfo_.colCount], indexCol + indexRow * + regionInfo_.colCount == 0 ? heif_header_data : heif_no_header); + ProcessChunkHead(inputs[indexCol + indexRow * regionInfo_.colCount].data(), + inputs[indexCol + indexRow * regionInfo_.colCount].size()); + } + } +} + +void HeifDecoderImpl::SwRegionDecode(std::vector> tileImages, + std::vector> &inputs, size_t numGrid) +{ + inputs.resize(regionInfo_.colCount * regionInfo_.rowCount); + uint32_t rowIndex = regionInfo_.top / gridInfo_.tileHeight; + uint32_t colIndex = regionInfo_.left / gridInfo_.tileWidth; + uint32_t decodeIndex = rowIndex * gridInfo_.cols + colIndex; + for (uint32_t index = 0; index < numGrid; ++index) { + std::shared_ptr &tileImage = tileImages[index]; + if (index == decodeIndex) { + DoSwRegionDecode(tileImages, inputs, tileImage, decodeIndex); + } + } +} + bool HeifDecoderImpl::SwDecodeGrids(ImageFwkExtManager &extManager, std::shared_ptr &image, HevcSoftDecodeParam ¶m) { @@ -831,13 +934,31 @@ bool HeifDecoderImpl::SwDecodeGrids(ImageFwkExtManager &extManager, cond = tileImages.empty(); CHECK_ERROR_RETURN_RET_LOG(cond, false, "grid image has no tile image"); size_t numGrid = tileImages.size(); - std::vector> inputs(numGrid); - - for (size_t index = 0; index < numGrid; ++index) { - std::shared_ptr &tileImage = tileImages[index]; - parser_->GetItemData(tileImage->GetItemId(), - &inputs[index], index == 0 ? heif_header_data : heif_no_header); - ProcessChunkHead(inputs[index].data(), inputs[index].size()); + size_t inputsize = 0; + std::vector> inputs; + if (IsRegionDecode()) { + SwRegionDecode(tileImages, inputs, numGrid); + } else { + inputs.resize(numGrid); + for (size_t index = 0; index < numGrid; ++index) { + std::shared_ptr &tileImage = tileImages[index]; + parser_->GetItemData(tileImage->GetItemId(), + &inputs[index], index == 0 ? heif_header_data : heif_no_header); + ProcessChunkHead(inputs[index].data(), inputs[index].size()); + inputsize += inputs[index].size(); + } + } + if (IsRegionDecode()) { + param.gridInfo.cols = regionInfo_.colCount; + param.gridInfo.rows = regionInfo_.rowCount; + param.gridInfo.displayWidth = regionInfo_.colCount * gridInfo_.tileWidth; + param.gridInfo.displayHeight = regionInfo_.rowCount * gridInfo_.tileHeight; + if (param.isSharedMemory) { + param.gridInfo.displayWidth = regionInfo_.colCount * + gridInfo_.tileWidth - regionInfo_.widthPadding; + param.gridInfo.displayHeight = regionInfo_.rowCount * + gridInfo_.tileHeight - regionInfo_.heightPadding; + } } int32_t retCode = extManager.hevcSoftwareDecodeFunc_(inputs, param); @@ -897,6 +1018,7 @@ bool HeifDecoderImpl::SwDecodeAuxiliaryImage(std::shared_ptr &gainmap CHECK_ERROR_RETURN_RET_LOG(cond, false, "output->alloc(config)faild, GSError=%{public}d", ret); if (!DoSwDecodeAuxiliaryImage(gainmapImage, gainmapGridInfo, output, auxiliaryDstMemory)) { IMAGE_LOGE("HDR-IMAGE SwDecodeGainmap failed"); + return false; } return true; } @@ -1135,23 +1257,109 @@ bool HeifDecoderImpl::IsDirectYUVDecode() return outPixelFormat_ == Media::PixelFormat::NV21 || outPixelFormat_ == Media::PixelFormat::NV12; } -bool HeifDecoderImpl::IsAuxiliaryDirectYUVDecode(std::shared_ptr &auxiliaryImage) +bool HeifDecoderImpl::decodeSequence(int frameIndex, HeifFrameInfo *frameInfo) +{ + // unimplemented + return false; +} + +bool HeifDecoderImpl::IsHeifHasAlphaImage() { - if (auxiliaryDstHwBuffer_ == nullptr || isGainmapDecode_) { + std::shared_ptr alphaImage = primaryImage_->GetAlphaImage(); + if (alphaImage == nullptr) { return false; } - if (auxiliaryImage->GetLumaBitNum() == LUMA_10_BIT) { - return outPixelFormat_ == Media::PixelFormat::YCRCB_P010 || outPixelFormat_ == Media::PixelFormat::YCBCR_P010; + return true; +} + +bool HeifDecoderImpl::IsHeifAlphaYuv400() +{ + std::shared_ptr alphaImage = primaryImage_->GetAlphaImage(); + if (alphaImage == nullptr) { + return false; } - return outPixelFormat_ == Media::PixelFormat::NV21 || outPixelFormat_ == Media::PixelFormat::NV12; + if (alphaImage->GetDefaultPixelFormat() != HeifPixelFormat::YUV420) { + IMAGE_LOGD("heif alphaImage is not YUV420"); + return true; + } + return false; } -bool HeifDecoderImpl::decodeSequence(int frameIndex, HeifFrameInfo *frameInfo) +bool HeifDecoderImpl::IsGainmapDivisibleBySampleSize(uint32_t sampleSize) { - // unimplemented + if (gainmapImage_ == nullptr) { + return true; + } + return gainmapImage_->GetOriginalWidth() % sampleSize == 0 && + gainmapImage_->GetOriginalHeight() % sampleSize == 0; +} + +bool HeifDecoderImpl::IsHeifGainmapYuv400() +{ + if (gainmapImage_ == nullptr) { + return false; + } + if (gainmapImage_->GetDefaultPixelFormat() != HeifPixelFormat::YUV420) { + IMAGE_LOGD("heif gainmapImage is not YUV420"); + return true; + } + return false; +} + +int32_t HeifDecoderImpl::GetPrimaryLumaBitNum() +{ + return primaryImage_->GetLumaBitNum(); +} + +bool HeifDecoderImpl::IsGainmapGrid() +{ + if (!regionInfo_.isGainmapImage) { + return false; + } + if (parser_ == nullptr || gainmapImage_ == nullptr) { + return false; + } + std::string imageType = parser_->GetItemType(gainmapImage_->GetItemId()); + if (imageType == "grid") { + return true; + } + return false; +} + +bool HeifDecoderImpl::IsHeifGainmapDivisibility(int32_t primaryDisplayWidth, int32_t primaryDisplayHeight) +{ + if (gainmapImage_ == nullptr) { + return true; + } + bool isMultiple = (primaryDisplayWidth % static_cast(gainmapGridInfo_.displayWidth) == 0 && + primaryDisplayHeight % static_cast(gainmapGridInfo_.displayHeight) == 0); + if (isMultiple) { + int divisorDisplayWidth = primaryDisplayWidth / static_cast(gainmapGridInfo_.displayWidth); + int divisorDisplayHeight = primaryDisplayHeight / static_cast(gainmapGridInfo_.displayHeight); + bool isValidDivisor = IS_VALID_GAINMAP_DIVISOR(divisorDisplayWidth) && + IS_VALID_GAINMAP_DIVISOR(divisorDisplayHeight); + if (isValidDivisor) { + return true; + } + } return false; } +void HeifDecoderImpl::SetDecodeRegion(int32_t colCount, int32_t rowCount, int32_t left, int32_t top, size_t rowStride) +{ + regionInfo_.colCount = static_cast(colCount); + regionInfo_.rowCount = static_cast(rowCount); + regionInfo_.left = static_cast(left); + regionInfo_.top = static_cast(top); + regionInfo_.rowStride = rowStride; +} + +void HeifDecoderImpl::SetPadding(int32_t widthPadding, int32_t heightPadding) +{ + regionInfo_.widthPadding = static_cast(widthPadding); + regionInfo_.heightPadding = static_cast(heightPadding); +} + void HeifDecoderImpl::SetSampleFormat(uint32_t sampleSize, ColorManager::ColorSpaceName colorSpaceName, bool isColorSpaceFromCicp) { @@ -1160,6 +1368,19 @@ void HeifDecoderImpl::SetSampleFormat(uint32_t sampleSize, ColorManager::ColorSp isColorSpaceFromCicp_ = isColorSpaceFromCicp; } +void HeifDecoderImpl::setDstBuffer(uint8_t *dstBuffer, size_t rowStride, void *context) +{ + dstMemory_ = dstBuffer; + std::shared_ptr alphaImage = primaryImage_->GetAlphaImage(); + std::string imageType = parser_->GetItemType(primaryImage_->GetItemId()); + if (regionInfo_.colCount > 0 && regionInfo_.rowCount > 0 && alphaImage == nullptr && imageType == "grid") { + dstRowStride_ = regionInfo_.rowStride; + } else { + dstRowStride_ = rowStride; + } + dstHwBuffer_ = reinterpret_cast(context); +} + void HeifDecoderImpl::GetGainmapColorSpace(ColorManager::ColorSpaceName &gainmapColor) { if (gainmapImageInfo_.hasNclxColor) { @@ -1169,13 +1390,6 @@ void HeifDecoderImpl::GetGainmapColorSpace(ColorManager::ColorSpaceName &gainmap } } -void HeifDecoderImpl::setDstBuffer(uint8_t *dstBuffer, size_t rowStride, void *context) -{ - dstMemory_ = dstBuffer; - dstRowStride_ = rowStride; - dstHwBuffer_ = reinterpret_cast(context); -} - void HeifDecoderImpl::setGainmapDstBuffer(uint8_t* dstBuffer, size_t rowStride, void *context) { gainmapDstMemory_ = dstBuffer; @@ -1193,7 +1407,7 @@ void HeifDecoderImpl::setAuxiliaryDstBuffer(uint8_t* dstBuffer, size_t dstSize, auxiliaryDstRowStride_ = rowStride; isAuxiliaryDecode_ = true; isGainmapDecode_ = false; - auxiliaryDstHwBuffer_ = reinterpret_cast(context); + auxiliaryDstHwbuffer_ = reinterpret_cast(context); sampleSize_ = DEFAULT_SCALE_SIZE; } diff --git a/plugins/manager/include/image/abs_image_decoder.h b/plugins/manager/include/image/abs_image_decoder.h index d86822c42a8ae4d783dcc682e3878e39c20fe4e2..b1b58e7e1dda4e983be794becea51ac3a8ff94a4 100644 --- a/plugins/manager/include/image/abs_image_decoder.h +++ b/plugins/manager/include/image/abs_image_decoder.h @@ -253,6 +253,11 @@ public: return false; } + virtual OHOS::Media::Size GetHeifRegionGridSize() + { + return {0, 0}; + } + virtual bool GetHeifHdrColorSpace(ColorManager::ColorSpaceName &gainmap, ColorManager::ColorSpaceName &hdr) { return false;