From a2cbb9cfee7ecf0ae9e09490770823e1be88e62a Mon Sep 17 00:00:00 2001 From: "lichengcheng (L)" Date: Tue, 12 Aug 2025 14:11:43 +0800 Subject: [PATCH] JPEGD security rectification Signed-off-by: lichengcheng (L) --- frameworks/innerkitsimpl/test/BUILD.gn | 1 - .../unittest/jpeg_hw_decode/demo/BUILD.gn | 1 + .../common/libs/image/libextplugin/BUILD.gn | 5 +- .../include/hardware/jpeg_dma_pool.h | 65 +++++ .../include/hardware/jpeg_hw_decoder.h | 44 +--- .../src/hardware/jpeg_dma_pool.cpp | 208 +++++++++++++++ .../src/hardware/jpeg_hw_decoder.cpp | 242 ++---------------- 7 files changed, 304 insertions(+), 262 deletions(-) create mode 100644 plugins/common/libs/image/libextplugin/include/hardware/jpeg_dma_pool.h create mode 100644 plugins/common/libs/image/libextplugin/src/hardware/jpeg_dma_pool.cpp diff --git a/frameworks/innerkitsimpl/test/BUILD.gn b/frameworks/innerkitsimpl/test/BUILD.gn index c199a65bf..0bdf6f63a 100644 --- a/frameworks/innerkitsimpl/test/BUILD.gn +++ b/frameworks/innerkitsimpl/test/BUILD.gn @@ -1261,7 +1261,6 @@ ohos_unittest("jpeg_hw_decoder_test") { sources = [ "${image_subsystem}/frameworks/innerkitsimpl/test/unittest/plugin_test/ext_decoder_test.cpp", "${image_subsystem}/plugins/common/libs/image/libextplugin/src/ext_stream.cpp", - "${image_subsystem}/plugins/common/libs/image/libextplugin/src/hardware/jpeg_hw_decoder.cpp", "unittest/jpeg_hw_decode/common/mock_jpeg_hw_decode_flow.cpp", "unittest/jpeg_hw_decode/unittest/jpeg_hw_decoder_test.cpp", ] diff --git a/frameworks/innerkitsimpl/test/unittest/jpeg_hw_decode/demo/BUILD.gn b/frameworks/innerkitsimpl/test/unittest/jpeg_hw_decode/demo/BUILD.gn index b72152868..964fa7f59 100644 --- a/frameworks/innerkitsimpl/test/unittest/jpeg_hw_decode/demo/BUILD.gn +++ b/frameworks/innerkitsimpl/test/unittest/jpeg_hw_decode/demo/BUILD.gn @@ -31,6 +31,7 @@ ohos_executable("jpeg_hw_decoder_demo") { "${image_subsystem}/frameworks/innerkitsimpl/test/unittest/jpeg_hw_decode/common/mock_jpeg_hw_decode_flow.cpp", "${image_subsystem}/plugins/common/libs/image/libextplugin/src/ext_stream.cpp", "${image_subsystem}/plugins/common/libs/image/libextplugin/src/hardware/jpeg_hw_decoder.cpp", + "${image_subsystem}/plugins/common/libs/image/libextplugin/src/hardware/jpeg_dma_pool.cpp", "jpeg_hw_decoder_demo.cpp", ] include_dirs = [ diff --git a/plugins/common/libs/image/libextplugin/BUILD.gn b/plugins/common/libs/image/libextplugin/BUILD.gn index 97b6f43c7..375bdcd4d 100644 --- a/plugins/common/libs/image/libextplugin/BUILD.gn +++ b/plugins/common/libs/image/libextplugin/BUILD.gn @@ -169,7 +169,10 @@ ohos_shared_library("extplugin") { "src/texture_encode/astc_codec.cpp", ] if (enable_jpeg_hw_decode) { - sources += [ "src/hardware/jpeg_hw_decoder.cpp" ] + sources += [ + "src/hardware/jpeg_hw_decoder.cpp", + "src/hardware/jpeg_dma_pool.cpp" + ] } configs = [ ":plugins_includes", diff --git a/plugins/common/libs/image/libextplugin/include/hardware/jpeg_dma_pool.h b/plugins/common/libs/image/libextplugin/include/hardware/jpeg_dma_pool.h new file mode 100644 index 000000000..937fa3f97 --- /dev/null +++ b/plugins/common/libs/image/libextplugin/include/hardware/jpeg_dma_pool.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 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. + */ + +#ifndef JPEG_DMA_POOL_H +#define JPEG_DMA_POOL_H +#include "jpeg_hw_decoder.h" +#include + +namespace OHOS { +namespace ImagePlugin { +using namespace OHOS::HDI::Codec::Image::V2_1; + +struct DmaBufferInfo { + uint32_t allocatedBufferSize; + uint32_t allocatedBufferOffsetOfPool; +}; + +struct PureStreamInfo { + uint32_t dataPos; + uint32_t dataSize; +}; + +class DmaPool { +public: + ~DmaPool() = default; + static DmaPool& GetInstance(); + bool AllocBufferInDmaPool(sptr hwDecoder_, ImagePlugin::InputDataStream* srcStream, + CodecImageBuffer& inBuffer, PureStreamInfo streamInfo, DmaBufferInfo& bufferInfo); + void RecycleBufferInDmaPool(DmaBufferInfo bufferInfo); +private: + DmaPool() = default; + bool Init(sptr hwDecoder_); + bool CopySrcToDmaPool(ImagePlugin::InputDataStream* srcStream, PureStreamInfo streamInfo, + DmaBufferInfo bufferInfo); + bool PackingBufferHandle(DmaBufferInfo bufferInfo, CodecImageBuffer& inBuffer); + void UpdateDmaPoolInfo(PureStreamInfo streamInfo, DmaBufferInfo bufferInfo); + void RunDmaPoolDestroy(); +private: + std::mutex dmaPoolMtx_; + bool inited_ {false}; + std::condition_variable dmaPoolCond_; + uint32_t remainCapacity_ {0}; + uint32_t remainOffset_ {0}; + sptr nativeBuf_ {nullptr}; + BufferHandle *bufferHandle_ {nullptr}; + std::unordered_map usedSpace_; /* */ + std::unordered_map releaseSpace_; /* */ + std::chrono::steady_clock::time_point activeTime_ {std::chrono::steady_clock::now()}; /* active time */ +}; +} // namespace ImagePlugin +} // namespace OHOS + +#endif // JPEG_DMA_POOL_H diff --git a/plugins/common/libs/image/libextplugin/include/hardware/jpeg_hw_decoder.h b/plugins/common/libs/image/libextplugin/include/hardware/jpeg_hw_decoder.h index 9e184857e..b4e1abfc6 100644 --- a/plugins/common/libs/image/libextplugin/include/hardware/jpeg_hw_decoder.h +++ b/plugins/common/libs/image/libextplugin/include/hardware/jpeg_hw_decoder.h @@ -17,7 +17,6 @@ #define JPEG_HARDWARE_DECODER_H #include -#include #include "v2_1/icodec_image.h" #include "v1_0/include/idisplay_buffer.h" #include "image/image_plugin_type.h" @@ -48,27 +47,10 @@ #define JPEG_HW_LOGD(x, ...) \ IMAGE_LOGD(LOG_FMT x, FILENAME, __FUNCTION__, __LINE__, ##__VA_ARGS__) -#define KILO_BYTE 1024 -#define MAX_SIZE_USE_DMA_POOL 256 /* max size of jpeg bitstream to use DMA Pool */ -#define BUFFER_UNIT_SIZE 32 /* Input buffer alignment size */ -#define DMA_POOL_SIZE 1024 /* the size of DMA Pool is 1M */ -#define DMA_POOL_WAIT_SECONDS 10 /* Destroy the DMA pool if it is not used for more than 10s */ -#define DMA_POOL_QUERY_INTERVAL 5 /* Query the active time of the DMA pool every 5 seconds */ - namespace OHOS { namespace ImagePlugin { -class DmaPool { -public: - DmaPool(); - ~DmaPool(); -public: - OHOS::HDI::Codec::Image::V2_1::CodecImageBuffer buffer; - BufferHandle *bufferHandle; - std::pair remainSpace; /* */ - std::unordered_map usedSpace; /* */ - std::unordered_map releaseSpace; /* */ -}; + class JpegHardwareDecoder { public: JpegHardwareDecoder(); @@ -101,36 +83,24 @@ private: bool PrepareInputData(SkCodec *codec, ImagePlugin::InputDataStream *srcStream); bool DoDecode(OHOS::HDI::Codec::Image::V2_1::CodecImageBuffer& outputBufferHandle); void RecycleAllocatedResource(); - static OHOS::HDI::Display::Buffer::V1_0::IDisplayBuffer* GetBufferMgr(); bool CheckInputColorFmt(SkCodec *codec); bool GetCompressedDataStart(ImagePlugin::InputDataStream* srcStream); bool CopySrcToInputBuff(ImagePlugin::InputDataStream* srcStream, BufferHandle* inputBufferHandle); bool TryDmaPoolInBuff(ImagePlugin::InputDataStream* srcStream); - bool AllocDmaPool(); - bool AllocSpace(); - void UpdateSpaceInfo(); - bool PackingInputBufferHandle(BufferHandle* inputBufferHandle); bool TryNormalInBuff(ImagePlugin::InputDataStream* srcStream); - bool RecycleSpace(); - void ReleaseSpace(uint32_t& offset, uint32_t& usedSize); uint16_t ReadTwoBytes(ImagePlugin::InputDataStream* srcStream, unsigned int pos, bool& flag); - static void RunDmaPoolRecycle(); private: static constexpr char JPEG_FORMAT_DESC[] = "image/jpeg"; - static std::vector capList_; static std::mutex capListMtx_; - static std::pair dmaPool_; - static std::mutex dmaPoolMtx_; - static uint32_t dmaPoolRefCnt_; + static std::vector capList_; OHOS::sptr hwDecoder_; - OHOS::HDI::Display::Buffer::V1_0::IDisplayBuffer* bufferMgr_; OHOS::HDI::Codec::Image::V2_1::CodecImageBuffer inputBuffer_; OHOS::HDI::Codec::Image::V2_1::CodecJpegDecInfo decodeInfo_; - uint32_t compressDataPos_; - uint32_t compressDataSize_; - bool useDmaPool_; - uint32_t usedSizeInPool_; - uint32_t usedOffsetInPool_; + uint32_t compressDataPos_ {0}; + uint32_t compressDataSize_ {0}; + bool useDmaPool_ {false}; + uint32_t usedSizeInPool_ {0}; + uint32_t usedOffsetInPool_ {0}; }; } // namespace ImagePlugin } // namespace OHOS diff --git a/plugins/common/libs/image/libextplugin/src/hardware/jpeg_dma_pool.cpp b/plugins/common/libs/image/libextplugin/src/hardware/jpeg_dma_pool.cpp new file mode 100644 index 000000000..de076462d --- /dev/null +++ b/plugins/common/libs/image/libextplugin/src/hardware/jpeg_dma_pool.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2025 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 "hardware/jpeg_dma_pool.h" + #include + #include +namespace OHOS::ImagePlugin { +using namespace OHOS::HDI::Codec::Image::V2_1; + +constexpr uint32_t DMA_POOL_SIZE = 1024 * 1024; /* the size of DMA Pool is 1M */ +constexpr uint32_t DMA_POOL_ALIGN_SIZE = 32 * 1024; /* Input buffer alignment size is 32K */ + +DmaPool& DmaPool::GetInstance() +{ + static DmaPool singleton; + return singleton; +} + +bool DmaPool::AllocBufferInDmaPool(sptr hwDecoder_, ImagePlugin::InputDataStream* srcStream, + CodecImageBuffer& inBuffer, PureStreamInfo streamInfo, DmaBufferInfo& bufferInfo) +{ + std::lock_guard lock(dmaPoolMtx_); + // step1. decide whether to alloc dma pool + if (!Init(hwDecoder_)) { + JPEG_HW_LOGE("failed to init dma pool"); + return false; + } + // step2. determine whether remainCapacity_ is sufficient + bufferInfo.allocatedBufferSize = ((streamInfo.dataSize + DMA_POOL_ALIGN_SIZE - 1) / DMA_POOL_ALIGN_SIZE) + * DMA_POOL_ALIGN_SIZE; + bufferInfo.allocatedBufferOffsetOfPool = remainOffset_; + if (bufferInfo.allocatedBufferSize > remainCapacity_) { + JPEG_HW_LOGI("The space left in dma pool isn't enough"); + return false; + } + // step3. try to copy src data to alloc buffer in dma pool + if (!CopySrcToDmaPool(srcStream, streamInfo, bufferInfo)) { + return false; + } + // step4. try to packing bufferhandle to inbuffer + if (!PackingBufferHandle(bufferInfo, inBuffer)) { + return false; + } + // step5. try to alloc buffer in dmapool + UpdateDmaPoolInfo(streamInfo, bufferInfo); + return true; +} + +bool DmaPool::Init(sptr hwDecoder_) +{ + if (inited_) { + return true; + } + CodecImageBuffer tempPool{}; + int32_t ret = hwDecoder_->AllocateInBuffer(tempPool, DMA_POOL_SIZE, CODEC_IMAGE_JPEG); + if (ret != HDF_SUCCESS || tempPool.buffer == nullptr) { + JPEG_HW_LOGE("failed to allocate dma pool, err=%{public}d", ret); + return false; + } + bufferHandle_ = tempPool.buffer->GetBufferHandle(); + if (bufferHandle_ == nullptr) { + JPEG_HW_LOGE("dma pool bufferHandle is null"); + return false; + } + bufferHandle_->virAddr = mmap(nullptr, DMA_POOL_SIZE, PROT_READ | PROT_WRITE, + MAP_SHARED, bufferHandle_->fd, 0); + if (bufferHandle_->virAddr == MAP_FAILED) { + JPEG_HW_LOGE("failed to map dma pool"); + return false; + } + std::thread lifeManageThread([this]{this->RunDmaPoolDestroy();}); + if (!lifeManageThread.joinable()) { + if (munmap(bufferHandle_->virAddr, DMA_POOL_SIZE) != 0) { + JPEG_HW_LOGE("failed to unmap dma pool"); + } + JPEG_HW_LOGE("failed to create lifeManageThread_"); + bufferHandle_ = nullptr; + return false; + } + lifeManageThread.detach(); + inited_ = true; + remainCapacity_ = DMA_POOL_SIZE; + nativeBuf_ = tempPool.buffer; + JPEG_HW_LOGI("creta dma pool success!"); + return true; +} + +bool DmaPool::CopySrcToDmaPool(ImagePlugin::InputDataStream* srcStream, PureStreamInfo streamInfo, + DmaBufferInfo bufferInfo) +{ + uint32_t positionRecord = srcStream->Tell(); + srcStream->Seek(streamInfo.dataPos); + uint32_t readSize = 0; + bool flag = srcStream->Read(streamInfo.dataSize, + static_cast(bufferHandle_->virAddr) + bufferInfo.allocatedBufferOffsetOfPool, + static_cast(bufferHandle_->size) - bufferInfo.allocatedBufferOffsetOfPool, + readSize); + srcStream->Seek(positionRecord); + if (!flag || readSize != streamInfo.dataSize) { + JPEG_HW_LOGE("failed to read input data, readSize=%{public}u", readSize); + return false; + } + return true; +} + +bool DmaPool::PackingBufferHandle(DmaBufferInfo bufferInfo, CodecImageBuffer& inBuffer) +{ + BufferHandle* curHandle = new (std::nothrow) BufferHandle; + if (curHandle == nullptr) { + JPEG_HW_LOGE("failed to new bufferHandle!"); + return false; + } + curHandle->fd = bufferHandle_->fd; + curHandle->size = static_cast(bufferInfo.allocatedBufferSize); + curHandle->width = static_cast(bufferInfo.allocatedBufferSize); + curHandle->stride = static_cast(bufferInfo.allocatedBufferSize); + curHandle->height = 1; + curHandle->reserveFds = 0; + curHandle->reserveInts = 0; + inBuffer.buffer = new NativeBuffer(); + inBuffer.buffer->SetBufferHandle(curHandle, true, [this](BufferHandle* freeBuffer) { + delete freeBuffer; + }); + inBuffer.bufferRole = CODEC_IMAGE_JPEG; + return true; +} + +void DmaPool::UpdateDmaPoolInfo(PureStreamInfo streamInfo, DmaBufferInfo bufferInfo) +{ + remainCapacity_ -= bufferInfo.allocatedBufferSize; + remainOffset_ += bufferInfo.allocatedBufferSize; + usedSpace_[remainOffset_] = bufferInfo.allocatedBufferSize; + activeTime_ = std::chrono::steady_clock::now(); + JPEG_HW_LOGI("upadteSpaceInfo: aligend size:%{public}u buffer usedOffset:%{public}u usedNum:%{public}lu", + bufferInfo.allocatedBufferSize, bufferInfo.allocatedBufferOffsetOfPool, usedSpace_.size()); +} + +void DmaPool::RunDmaPoolDestroy() +{ + using namespace std::literals; + std::unique_lock lck(dmaPoolMtx_); + /* Destroy the DMA pool if it is not used for more than 10s */ + while (true) { + bool ret = dmaPoolCond_.wait_for(lck, 5s, [this]() { + auto curTime = std::chrono::steady_clock::now(); + auto diffDuration = std::chrono::duration_cast(curTime - activeTime_); + return usedSpace_.empty() && diffDuration >= 10s; + }); + if (ret) { + break; + } + JPEG_HW_LOGI("wait to destroy dma pool"); + } + if (bufferHandle_ != nullptr && bufferHandle_->virAddr != nullptr) { + if (munmap(bufferHandle_->virAddr, DMA_POOL_SIZE) != 0) { + JPEG_HW_LOGE("failed to unmap dma pool"); + } + } else { + JPEG_HW_LOGE("dma pool bufferhandle or viraddr is nullptr!"); + } + inited_ = false; + remainCapacity_ = 0; + remainOffset_ = 0; + nativeBuf_ = nullptr; + bufferHandle_ = nullptr; + JPEG_HW_LOGI("dma pool destroyed!"); + return; +} + +void DmaPool::RecycleBufferInDmaPool(DmaBufferInfo bufferInfo) +{ + std::lock_guard lock(dmaPoolMtx_); + activeTime_ = std::chrono::steady_clock::now(); + uint32_t endOffset = bufferInfo.allocatedBufferOffsetOfPool + bufferInfo.allocatedBufferSize; + // 1.push used space to release space + auto it = usedSpace_.find(endOffset); + if (it != usedSpace_.end()) { + releaseSpace_[endOffset] = bufferInfo.allocatedBufferSize; + usedSpace_.erase(it); + } + + // 2.recycle continuous release space adjacent to remainOffset_ + while (true) { + auto it = releaseSpace_.find(remainOffset_); + if (it != releaseSpace_.end()) { + remainOffset_ -= it->second; + remainCapacity_ += it->second; + releaseSpace_.erase(it); + continue; + } + break; + } + JPEG_HW_LOGI("remainCapacity_: size:%{public}u remainOffset_:%{public}u unRecycleNum:%{public}lu + %{public}lu", + remainCapacity_, remainOffset_, usedSpace_.size(), releaseSpace_.size()); +} +} \ No newline at end of file diff --git a/plugins/common/libs/image/libextplugin/src/hardware/jpeg_hw_decoder.cpp b/plugins/common/libs/image/libextplugin/src/hardware/jpeg_hw_decoder.cpp index 45629d4a3..9dbbc287b 100644 --- a/plugins/common/libs/image/libextplugin/src/hardware/jpeg_hw_decoder.cpp +++ b/plugins/common/libs/image/libextplugin/src/hardware/jpeg_hw_decoder.cpp @@ -18,11 +18,11 @@ #include #include #include -#include #include #include #include "hardware/jpeg_marker_define.h" +#include "hardware/jpeg_dma_pool.h" #include "hdf_base.h" #include "iremote_object.h" #include "iproxy_broker.h" @@ -34,17 +34,11 @@ namespace OHOS::ImagePlugin { using namespace OHOS::HDI::Codec::Image::V2_1; -using namespace OHOS::HDI::Display::Buffer::V1_0; using namespace Media; static std::mutex g_codecMtx; static sptr g_codecMgr; -static constexpr std::chrono::duration THRESHIOLD_DURATION(DMA_POOL_WAIT_SECONDS); std::vector JpegHardwareDecoder::capList_ = {}; -std::pair JpegHardwareDecoder::dmaPool_ = - std::make_pair(nullptr, std::chrono::steady_clock::now()); -uint32_t JpegHardwareDecoder::dmaPoolRefCnt_ = 0; -std::mutex JpegHardwareDecoder::dmaPoolMtx_; std::mutex JpegHardwareDecoder::capListMtx_; class CodecJpegDeathRecipient : public IRemoteObject::DeathRecipient { @@ -80,24 +74,6 @@ static sptr GetCodecManager() return g_codecMgr; } -DmaPool::DmaPool() -{ - buffer = {0}; - remainSpace = {}; - usedSpace = {}; - releaseSpace = {}; - bufferHandle = nullptr; -} - -DmaPool::~DmaPool() -{ - buffer = {0}; - remainSpace = {}; - usedSpace = {}; - releaseSpace = {}; - bufferHandle = nullptr; -} - JpegHardwareDecoder::LifeSpanTimer::LifeSpanTimer(std::string desc) : desc_(desc) { startTimeInUs_ = GetCurrentTimeInUs(); @@ -121,13 +97,11 @@ JpegHardwareDecoder::JpegHardwareDecoder() { inputBuffer_.fenceFd = -1; hwDecoder_ = GetCodecManager(); - bufferMgr_ = GetBufferMgr(); } JpegHardwareDecoder::~JpegHardwareDecoder() { hwDecoder_ = nullptr; - bufferMgr_ = nullptr; } bool JpegHardwareDecoder::IsHardwareDecodeSupported(const std::string& srcImgFormat, OHOS::Media::Size srcImgSize) @@ -207,8 +181,8 @@ uint32_t JpegHardwareDecoder::Decode(SkCodec *codec, ImagePlugin::InputDataStrea LifeSpanTimer decodeTimer("jpeg hardware decode"); JPEG_HW_LOGD("img=[%{public}ux%{public}u], sampleSize=%{public}u", srcImgSize.width, srcImgSize.height, sampleSize); - if (hwDecoder_ == nullptr || bufferMgr_ == nullptr) { - JPEG_HW_LOGE("failed to get hardware decoder or failed to get buffer manager!"); + if (hwDecoder_ == nullptr) { + JPEG_HW_LOGE("failed to get hardware decoder!"); return Media::ERR_IMAGE_DECODE_ABNORMAL; } if (!IsHardwareDecodeSupported(JPEG_FORMAT_DESC, srcImgSize) || !CheckInputColorFmt(codec)) { @@ -236,7 +210,7 @@ bool JpegHardwareDecoder::AssembleComponentInfo(jpeg_decompress_struct* jpegComp JPEG_HW_LOGE("unsupported component number: %{public}d!", jpegCompressInfo->num_components); return false; } - decodeInfo_.numComponents = jpegCompressInfo->num_components; + decodeInfo_.numComponents = static_cast(jpegCompressInfo->num_components); for (int i = 0; i < jpegCompressInfo->num_components; ++i) { decodeInfo_.compInfo.emplace_back(CodecJpegCompInfo { .componentId = jpegCompressInfo->comp_info[i].component_id, @@ -316,7 +290,7 @@ bool JpegHardwareDecoder::AssembleJpegImgHeader(jpeg_decompress_struct* jpegComp { decodeInfo_.imageWidth = jpegCompressInfo->image_width; decodeInfo_.imageHeight = jpegCompressInfo->image_height; - decodeInfo_.dataPrecision = jpegCompressInfo->data_precision; + decodeInfo_.dataPrecision = static_cast(jpegCompressInfo->data_precision); decodeInfo_.restartInterval = jpegCompressInfo->restart_interval; decodeInfo_.arithCode = jpegCompressInfo->arith_code; decodeInfo_.progressiveMode = jpegCompressInfo->progressive_mode; @@ -330,60 +304,14 @@ bool JpegHardwareDecoder::AssembleJpegImgHeader(jpeg_decompress_struct* jpegComp return true; } -bool JpegHardwareDecoder::AllocDmaPool() -{ - dmaPool_.first = new DmaPool(); - dmaPoolRefCnt_ = 0; - int32_t ret = hwDecoder_->AllocateInBuffer(dmaPool_.first->buffer, (DMA_POOL_SIZE * KILO_BYTE), - CODEC_IMAGE_JPEG); - if (ret != HDF_SUCCESS) { - JPEG_HW_LOGE("failed to allocate DMA pool, err=%{public}d", ret); - delete dmaPool_.first; - dmaPool_.first = nullptr; - return false; - } - dmaPool_.first->remainSpace = std::make_pair(DMA_POOL_SIZE * KILO_BYTE, 0); - dmaPool_.first->bufferHandle = (dmaPool_.first->buffer).buffer->GetBufferHandle(); - if (dmaPool_.first->bufferHandle == nullptr) { - JPEG_HW_LOGE("inputBufferHandle is nullptr"); - delete dmaPool_.first; - dmaPool_.first = nullptr; - return false; - } - dmaPool_.first->bufferHandle->virAddr = mmap(nullptr, (DMA_POOL_SIZE * KILO_BYTE), PROT_READ | PROT_WRITE, - MAP_SHARED, dmaPool_.first->bufferHandle->fd, 0); - if (dmaPool_.first->bufferHandle->virAddr == MAP_FAILED) { - JPEG_HW_LOGE("failed to map input buffer"); - delete dmaPool_.first; - dmaPool_.first = nullptr; - return false; - } - JPEG_HW_LOGI("alloc DMA pool success!"); - return true; -} - -void JpegHardwareDecoder::UpdateSpaceInfo() -{ - if (dmaPool_.first != nullptr) { - dmaPoolRefCnt_++; - usedOffsetInPool_ = (dmaPool_.first->remainSpace).second; - uint32_t newSize = (dmaPool_.first->remainSpace).first - usedSizeInPool_; - uint32_t newStart = (dmaPool_.first->remainSpace).second + usedSizeInPool_; - dmaPool_.first->remainSpace = std::make_pair(newSize, newStart); - (dmaPool_.first->usedSpace)[newStart] = usedSizeInPool_; - JPEG_HW_LOGI("upadteSpaceInfo: aligend size:%{public}u buffer offset:%{public}u refCnt:%{public}u", - usedSizeInPool_, usedOffsetInPool_, dmaPoolRefCnt_); - } -} - bool JpegHardwareDecoder::CopySrcToInputBuff(ImagePlugin::InputDataStream* srcStream, BufferHandle* inputBufferHandle) { uint32_t positionRecord = srcStream->Tell(); srcStream->Seek(compressDataPos_); uint32_t readSize = 0; bool flag = srcStream->Read(compressDataSize_, - static_cast(inputBufferHandle->virAddr) + usedOffsetInPool_, - static_cast(inputBufferHandle->size) - usedOffsetInPool_, + static_cast(inputBufferHandle->virAddr), + static_cast(inputBufferHandle->size), readSize); srcStream->Seek(positionRecord); if (!flag || readSize != compressDataSize_) { @@ -392,65 +320,6 @@ bool JpegHardwareDecoder::CopySrcToInputBuff(ImagePlugin::InputDataStream* srcSt } return true; } -void JpegHardwareDecoder::RunDmaPoolRecycle() -{ - dmaPoolMtx_.lock(); - while (true) { - std::chrono::steady_clock::time_point curTime = std::chrono::steady_clock::now(); - std::chrono::duration diffDuration = - std::chrono::duration_cast>(curTime - dmaPool_.second); - if ((dmaPoolRefCnt_ == 0) && (diffDuration >= THRESHIOLD_DURATION)) { - break; - } else { - dmaPoolMtx_.unlock(); - JPEG_HW_LOGI("wait to recycle DMA pool"); - std::this_thread::sleep_for(std::chrono::seconds(DMA_POOL_QUERY_INTERVAL)); - dmaPoolMtx_.lock(); - } - } - if (munmap(dmaPool_.first->bufferHandle->virAddr, (DMA_POOL_SIZE * KILO_BYTE)) != 0) { - JPEG_HW_LOGE("failed to unmap input buffer"); - } - delete dmaPool_.first; - dmaPool_.first = nullptr; - JPEG_HW_LOGI("DMA pool has been destroyed."); - dmaPoolMtx_.unlock(); -} - -bool JpegHardwareDecoder::AllocSpace() -{ - // step1. decide whether to alloc buffer - if (dmaPool_.first == nullptr) { - if (!AllocDmaPool()) { - return false; - } - std::thread dmaPoolRecycleThread(RunDmaPoolRecycle); - if (dmaPoolRecycleThread.joinable()) { - dmaPoolRecycleThread.detach(); - } else { - JPEG_HW_LOGE("failed to create dmaPoolRecycleThread"); - dmaPoolMtx_.lock(); - if (munmap(dmaPool_.first->bufferHandle->virAddr, (DMA_POOL_SIZE * KILO_BYTE)) != 0) { - JPEG_HW_LOGE("failed to unmap input buffer"); - } - delete dmaPool_.first; - dmaPool_.first = nullptr; - dmaPoolMtx_.unlock(); - return false; - } - } - dmaPool_.second = std::chrono::steady_clock::now(); - // step2. try to alloc space - uint32_t uintNum = (compressDataSize_ + BUFFER_UNIT_SIZE * KILO_BYTE - 1) / (BUFFER_UNIT_SIZE * KILO_BYTE); - usedSizeInPool_ = uintNum * (BUFFER_UNIT_SIZE * KILO_BYTE); - if (usedSizeInPool_ <= (dmaPool_.first->remainSpace).first) { - UpdateSpaceInfo(); - } else { - JPEG_HW_LOGI("The space left in DMA pool isn't enough"); - return false; - } - return true; -} uint16_t JpegHardwareDecoder::ReadTwoBytes(ImagePlugin::InputDataStream* srcStream, unsigned int pos, bool& flag) { @@ -514,47 +383,17 @@ bool JpegHardwareDecoder::GetCompressedDataStart(ImagePlugin::InputDataStream* s return findFlag; } -bool JpegHardwareDecoder::PackingInputBufferHandle(BufferHandle* inputBufferHandle) -{ - BufferHandle* curHandle = new (std::nothrow) BufferHandle; - if (curHandle == nullptr) { - JPEG_HW_LOGE("failed to new bufferHandle!"); - return false; - } - curHandle->fd = inputBufferHandle->fd; - curHandle->size = usedSizeInPool_; - curHandle->width = usedSizeInPool_; - curHandle->stride = usedSizeInPool_; - curHandle->height = 1; - curHandle->reserveFds = 0; - curHandle->reserveInts = 0; - inputBuffer_.buffer = new NativeBuffer(); - inputBuffer_.buffer->SetBufferHandle(curHandle, true, [this](BufferHandle* freeBuffer) { - delete freeBuffer; - }); - inputBuffer_.bufferRole = CODEC_IMAGE_JPEG; - JPEG_HW_LOGI("inputBuffer size:%{public}d DMA pool size:%{public}d", - inputBuffer_.buffer->GetBufferHandle()->size, dmaPool_.first->bufferHandle->size); - return true; -} - bool JpegHardwareDecoder::TryDmaPoolInBuff(ImagePlugin::InputDataStream* srcStream) { ImageTrace imageTrace("JpegHardwareDecoder::TryDmaPoolInBuff"); - // step1. alloc Buffer - std::lock_guard lock(dmaPoolMtx_); - if (!AllocSpace()) { - return false; - } - // step2. copysrc to buffer - BufferHandle *inputBufferHandle = dmaPool_.first->bufferHandle; - if (!CopySrcToInputBuff(srcStream, inputBufferHandle)) { - return false; - } - // step3. packing a inputBuffer_ - if (!PackingInputBufferHandle(inputBufferHandle)) { + PureStreamInfo curStreamInfo {compressDataPos_, compressDataSize_}; + DmaBufferInfo allocBufferInfo {0, 0}; + if (!DmaPool::GetInstance().AllocBufferInDmaPool(hwDecoder_, srcStream, inputBuffer_, + curStreamInfo, allocBufferInfo)) { return false; } + usedOffsetInPool_ = allocBufferInfo.allocatedBufferOffsetOfPool; + usedSizeInPool_ = allocBufferInfo.allocatedBufferSize; return true; } @@ -595,17 +434,18 @@ bool JpegHardwareDecoder::TryNormalInBuff(ImagePlugin::InputDataStream* srcStrea bool JpegHardwareDecoder::CopySrcImgToDecodeInputBuffer(ImagePlugin::InputDataStream* srcStream) { - useDmaPool_ = false; + // max size of pure jpeg bitstream to use DMA Pool is 256KB + constexpr uint32_t MAX_SIZE_USE_DMA_POOL = 256 * 1024; if (!GetCompressedDataStart(srcStream)) { JPEG_HW_LOGE("get compressed data start failed"); return false; } - if (compressDataSize_ <= (MAX_SIZE_USE_DMA_POOL * KILO_BYTE)) { + if (compressDataSize_ <= MAX_SIZE_USE_DMA_POOL) { if (TryDmaPoolInBuff(srcStream)) { useDmaPool_ = true; } } - if (compressDataSize_ > (MAX_SIZE_USE_DMA_POOL * KILO_BYTE) || !useDmaPool_) { + if ((compressDataSize_ > MAX_SIZE_USE_DMA_POOL) || (!useDmaPool_)) { if (!TryNormalInBuff(srcStream)) { return false; } @@ -689,56 +529,12 @@ bool JpegHardwareDecoder::DoDecode(CodecImageBuffer& outputBuffer) return true; } -void JpegHardwareDecoder::ReleaseSpace(uint32_t& offset, uint32_t& usedSize) -{ - std::lock_guard lock(dmaPoolMtx_); - if (dmaPool_.first != nullptr) { - dmaPoolRefCnt_--; - dmaPool_.second = std::chrono::steady_clock::now(); - auto it = (dmaPool_.first->usedSpace).find(offset); - if (it != (dmaPool_.first->usedSpace).end()) { - (dmaPool_.first->releaseSpace)[offset] = usedSize; - (dmaPool_.first->usedSpace).erase(it); - } - } -} - -bool JpegHardwareDecoder::RecycleSpace() -{ - std::lock_guard lock(dmaPoolMtx_); - if (dmaPool_.first != nullptr) { - auto it = (dmaPool_.first->releaseSpace).find((dmaPool_.first->remainSpace).second); - if (it != (dmaPool_.first->releaseSpace).end()) { - uint32_t newStart = (dmaPool_.first->remainSpace).second - it->second; - uint32_t newSize = it->second + (dmaPool_.first->remainSpace).first; - dmaPool_.first->remainSpace = std::make_pair(newSize, newStart); - (dmaPool_.first->releaseSpace).erase(it); - return true; - } - } - return false; -} - void JpegHardwareDecoder::RecycleAllocatedResource() { ImageTrace imageTrace("JpegHardwareDecoder::RecycleAllocatedResource"); if (useDmaPool_) { - // merge continuous remain space in DMA pool - uint32_t newEnd = usedOffsetInPool_ + usedSizeInPool_; - uint32_t newSize = usedSizeInPool_; - ReleaseSpace(newEnd, newSize); - bool findEnd = true; - while (findEnd) { - findEnd = RecycleSpace(); - } - JPEG_HW_LOGI("remianSpace info: size:%{public}u start:%{public}u refCnt:%{public}u", - (dmaPool_.first->remainSpace).first, (dmaPool_.first->remainSpace).second, dmaPoolRefCnt_); + DmaBufferInfo bufferInfo {usedSizeInPool_, usedOffsetInPool_}; + DmaPool::GetInstance().RecycleBufferInDmaPool(bufferInfo); } } - -OHOS::HDI::Display::Buffer::V1_0::IDisplayBuffer* JpegHardwareDecoder::GetBufferMgr() -{ - static OHOS::HDI::Display::Buffer::V1_0::IDisplayBuffer* staticBufferMgr = IDisplayBuffer::Get(); - return staticBufferMgr; -} } // namespace OHOS::ImagePlugin -- Gitee