Jpeg Decode Performance Optimization

Issue: https://gitee.com/openharmony/multimedia_image_framework/issues/IAZ2X5

Signed-off-by: caochuan <caochuan@huawei.com>
Change-Id: If79d805d7057116e371bcd038f976457e1e7f927
This commit is contained in:
caochuan 2024-10-23 09:32:50 +08:00
parent ea69e9f32d
commit 5a7b2f22ba
4 changed files with 96 additions and 70 deletions

View File

@ -158,6 +158,7 @@ static const uint32_t MAX_SOURCE_SIZE = 300 * 1024 * 1024;
constexpr uint8_t ASTC_EXTEND_INFO_TLV_NUM = 1; // curren only one group TLV
constexpr uint32_t ASTC_EXTEND_INFO_SIZE_DEFINITION_LENGTH = 4; // 4 bytes to discripte for extend info summary bytes
constexpr uint32_t ASTC_EXTEND_INFO_LENGTH_LENGTH = 4; // 4 bytes to discripte the content bytes for every TLV group
static constexpr uint32_t SINGLE_FRAME_SIZE = 1;
struct AstcExtendInfo {
uint32_t extendBufferSumBytes = 0;
@ -4442,31 +4443,57 @@ void ImageSource::DecodeHeifAuxiliaryPictures(
}
}
void ImageSource::DecodeJpegAuxiliaryPicture(
std::set<AuxiliaryPictureType> &auxTypes, std::unique_ptr<Picture> &picture, uint32_t &errorCode)
static bool OnlyDecodeGainmap(std::set<AuxiliaryPictureType> &auxTypes)
{
uint8_t *streamBuffer = sourceStreamPtr_->GetDataPtr();
uint32_t streamSize = sourceStreamPtr_->GetStreamSize();
auto jpegMpfParser = std::make_unique<JpegMpfParser>();
if (!jpegMpfParser->ParsingAuxiliaryPictures(streamBuffer, streamSize, false)) {
IMAGE_LOGE("Jpeg parse auxiliary pictures failed!");
errorCode = ERR_IMAGE_DATA_ABNORMAL;
return;
return auxTypes.size() == SINGLE_FRAME_SIZE && auxTypes.find(AuxiliaryPictureType::GAINMAP) != auxTypes.end();
}
static std::vector<SingleJpegImage> ParsingJpegAuxiliaryPictures(uint8_t *stream, uint32_t streamSize,
std::set<AuxiliaryPictureType> &auxTypes, ImageHdrType hdrType)
{
ImageTrace imageTrace("%s", __func__);
if (stream == nullptr || streamSize == 0) {
IMAGE_LOGE("No source stream when parsing auxiliary pictures");
return {};
}
if (sourceHdrType_ > ImageHdrType::SDR) {
auto jpegMpfParser = std::make_unique<JpegMpfParser>();
if (!OnlyDecodeGainmap(auxTypes) && !jpegMpfParser->ParsingAuxiliaryPictures(stream, streamSize, false)) {
IMAGE_LOGE("JpegMpfParser parse auxiliary pictures failed!");
jpegMpfParser->images_.clear();
}
if (hdrType > ImageHdrType::SDR) {
uint32_t gainmapStreamSize = streamSize;
for (auto &image : jpegMpfParser->images_) {
gainmapStreamSize = std::min(gainmapStreamSize, image.offset);
}
SingleJpegImage gainmapImage = {
.offset = mainDecoder_->GetGainMapOffset(),
.size = streamSize - mainDecoder_->GetGainMapOffset(),
.offset = 0,
.size = gainmapStreamSize,
.auxType = AuxiliaryPictureType::GAINMAP,
.auxTagName = AUXILIARY_TAG_GAINMAP,
};
jpegMpfParser->images_.push_back(gainmapImage);
}
return jpegMpfParser->images_;
}
void ImageSource::DecodeJpegAuxiliaryPicture(
std::set<AuxiliaryPictureType> &auxTypes, std::unique_ptr<Picture> &picture, uint32_t &errorCode)
{
uint8_t *streamBuffer = sourceStreamPtr_->GetDataPtr();
uint32_t streamSize = sourceStreamPtr_->GetStreamSize();
if (streamBuffer == nullptr || streamSize == 0) {
IMAGE_LOGE("Jpeg source stream is invalid!");
errorCode = ERR_IMAGE_DATA_ABNORMAL;
return;
}
streamBuffer += mainDecoder_->GetGainMapOffset();
streamSize -= mainDecoder_->GetGainMapOffset();
auto auxInfos = ParsingJpegAuxiliaryPictures(streamBuffer, streamSize, auxTypes, sourceHdrType_);
MainPictureInfo mainInfo;
mainInfo.hdrType = sourceHdrType_;
picture->GetMainPixel()->GetImageInfo(mainInfo.imageInfo);
for (auto &auxInfo : jpegMpfParser->images_) {
for (auto &auxInfo : auxInfos) {
if (auxTypes.find(auxInfo.auxType) == auxTypes.end()) {
continue;
}

View File

@ -71,7 +71,6 @@ public:
static void FloatToBytes(float data, std::vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian = true);
static void Int32ToBytes(int32_t data, std::vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian = true);
static void ArrayToBytes(const uint8_t* data, uint32_t length, std::vector<uint8_t>& bytes, uint32_t& offset);
static int32_t KMPFind(const uint8_t* target, uint32_t targetLen, const uint8_t* pattern, uint32_t patternLen);
static void FlushSurfaceBuffer(PixelMap* pixelMap);
static void FlushContextSurfaceBuffer(ImagePlugin::DecodeContext& context);
static void InvalidateContextSurfaceBuffer(ImagePlugin::DecodeContext& context);

View File

@ -726,53 +726,6 @@ void ImageUtils::ArrayToBytes(const uint8_t* data, uint32_t length, vector<uint8
}
}
static void GetNextArray(const uint8_t* pattern, uint32_t patternLen, std::vector<uint32_t>& next)
{
uint32_t prefixEnd = 0;
next[0] = prefixEnd;
for (uint32_t i = 1; i < patternLen; ++i) {
// if not match, move prefixEnd to next position
while (prefixEnd > 0 && pattern[prefixEnd] != pattern[i]) {
prefixEnd = next[prefixEnd - 1];
}
// if match, update prefixEnd
if (pattern[prefixEnd] == pattern[i]) {
prefixEnd++;
}
//update next array
next[i] = prefixEnd;
}
}
int32_t ImageUtils::KMPFind(const uint8_t* target, uint32_t targetLen,
const uint8_t* pattern, uint32_t patternLen)
{
if (target == nullptr || pattern == nullptr || patternLen == 0) {
IMAGE_LOGE("ImageUtils FindFirstMatchingStringByKMP failed, patternLen is zero");
return ERR_MEDIA_INVALID_VALUE;
}
std::vector<uint32_t> next(patternLen, 0);
GetNextArray(pattern, patternLen, next);
uint32_t targetIndex = 0;
uint32_t patternIndex = 0;
for (; targetIndex < targetLen; ++targetIndex) {
// if not match, move patternIndex to next position
while (patternIndex > 0 && target[targetIndex] != pattern[patternIndex]) {
patternIndex = next[patternIndex - 1];
}
// if match, update patternIndex
if (target[targetIndex] == pattern[patternIndex]) {
++patternIndex;
}
// find the first matching string success
if (patternIndex == patternLen) {
return static_cast<int32_t>(targetIndex) - static_cast<int32_t>(patternLen) + static_cast<int32_t>(NUM_1);
}
}
return ERR_MEDIA_INVALID_VALUE;
}
void ImageUtils::FlushSurfaceBuffer(PixelMap* pixelMap)
{
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)

View File

@ -188,30 +188,77 @@ bool JpegMpfParser::ParsingMpEntry(uint8_t* data, uint32_t size, bool isBigEndia
return true;
}
static bool FindAuxiliaryTags(const uint8_t* data, uint32_t size, std::string& foundTag)
{
if (data == nullptr || size < AUXILIARY_TAG_NAME_LENGTH) {
return false;
}
for (const auto &[tagName, _] : AUXILIARY_TAG_TYPE_MAP) {
if (memcmp(data, tagName.c_str(), tagName.size()) == 0) {
foundTag = tagName;
return true;
}
}
return false;
}
// |<------------------ Auxiliary picture structure ----------------->|
// |<- Image data ->|<- Image size(4 Bytes) ->|<- Tag name(8 Bytes) ->|
static int32_t GetLastAuxiliaryTagOffset(const uint8_t* data, uint32_t size, std::string& foundTag)
{
if (data == nullptr || size < AUXILIARY_TAG_NAME_LENGTH) {
return ERR_MEDIA_INVALID_VALUE;
}
uint32_t offset = size - AUXILIARY_TAG_NAME_LENGTH;
while (offset > 0) {
if (FindAuxiliaryTags(data + offset, size - offset, foundTag)) {
return static_cast<int32_t>(offset);
}
--offset;
}
return ERR_MEDIA_INVALID_VALUE;
}
// Parse the following types of auxiliary pictures: DEPTH_MAP, UNREFOCUS_MAP, LINEAR_MAP, FRAGMENT_MAP
bool JpegMpfParser::ParsingAuxiliaryPictures(uint8_t* data, uint32_t dataSize, bool isBigEndian)
{
if (data == nullptr || dataSize == 0) {
return false;
}
images_.clear();
for (const auto& it : AUXILIARY_TAG_TYPE_MAP) {
int32_t matchedPos = ImageUtils::KMPFind(data, dataSize,
reinterpret_cast<const uint8_t*>(it.first.c_str()), it.first.size());
uint32_t offset = dataSize;
while (offset > 0) {
std::string foundTag("");
int32_t matchedPos = GetLastAuxiliaryTagOffset(data, offset, foundTag);
if (matchedPos == ERR_MEDIA_INVALID_VALUE) {
IMAGE_LOGI("%{public}s no more auxiliary pictures", __func__);
break;
}
offset = static_cast<uint32_t>(matchedPos);
auto it = AUXILIARY_TAG_TYPE_MAP.find(foundTag);
if (it == AUXILIARY_TAG_TYPE_MAP.end()) {
IMAGE_LOGW("%{public}s unknown auxiliary tag: %{public}s", __func__, foundTag.c_str());
continue;
}
uint32_t offset = static_cast<uint32_t>(matchedPos);
if (offset > dataSize) {
if (offset < UINT32_BYTE_SIZE) {
IMAGE_LOGW("%{public}s invalid offset: %{public}u, auxiliary tag: %{public}s",
__func__, offset, foundTag.c_str());
continue;
}
offset -= UINT32_BYTE_SIZE;
uint32_t imageSize = ImageUtils::BytesToUint32(data, offset, isBigEndian);
if (offset < imageSize + UINT32_BYTE_SIZE) {
IMAGE_LOGW("%{public}s invalid image size: %{public}u, offset: %{public}u, auxiliary tag: %{public}s",
__func__, imageSize, offset, foundTag.c_str());
continue;
}
offset = offset - imageSize - UINT32_BYTE_SIZE;
SingleJpegImage auxImage = {
.offset = offset - UINT32_BYTE_SIZE - imageSize,
.offset = offset,
.size = imageSize,
.auxType = it.second,
.auxTagName = it.first,
.auxType = it->second,
.auxTagName = it->first,
};
images_.push_back(auxImage);
IMAGE_LOGD("[%{public}s] auxType=%{public}d, offset=%{public}u, size=%{public}u, tagName=%{public}s",