/* * Copyright (C) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "image_source.h" #include #include #include "buffer_source_stream.h" #if !defined(_WIN32) && !defined(_APPLE) #include "hitrace_meter.h" #endif #include "file_source_stream.h" #include "image/abs_image_decoder.h" #include "image/abs_image_format_agent.h" #include "image/image_plugin_type.h" #include "image_log.h" #include "image_utils.h" #include "incremental_source_stream.h" #include "istream_source_stream.h" #include "media_errors.h" #include "pixel_map.h" #include "plugin_server.h" #include "post_proc.h" #include "source_stream.h" #if defined(_ANDROID) || defined(_IOS) #include "include/jpeg_decoder.h" #endif #include "include/utils/SkBase64.h" #include "image_trace.h" namespace OHOS { namespace Media { using namespace OHOS::HiviewDFX; using namespace std; using namespace ImagePlugin; using namespace MultimediaPlugin; static const map PIXEL_FORMAT_MAP = { { PixelFormat::UNKNOWN, PlPixelFormat::UNKNOWN }, { PixelFormat::ARGB_8888, PlPixelFormat::ARGB_8888 }, { PixelFormat::ALPHA_8, PlPixelFormat::ALPHA_8 }, { PixelFormat::RGB_565, PlPixelFormat::RGB_565 }, { PixelFormat::RGBA_F16, PlPixelFormat::RGBA_F16 }, { PixelFormat::RGBA_8888, PlPixelFormat::RGBA_8888 }, { PixelFormat::BGRA_8888, PlPixelFormat::BGRA_8888 }, { PixelFormat::RGB_888, PlPixelFormat::RGB_888 }, { PixelFormat::NV21, PlPixelFormat::NV21 }, { PixelFormat::NV12, PlPixelFormat::NV12 }, { PixelFormat::CMYK, PlPixelFormat::CMYK } }; static const map COLOR_SPACE_MAP = { { ColorSpace::UNKNOWN, PlColorSpace::UNKNOWN }, { ColorSpace::DISPLAY_P3, PlColorSpace::DISPLAY_P3 }, { ColorSpace::SRGB, PlColorSpace::SRGB }, { ColorSpace::LINEAR_SRGB, PlColorSpace::LINEAR_SRGB }, { ColorSpace::EXTENDED_SRGB, PlColorSpace::EXTENDED_SRGB }, { ColorSpace::LINEAR_EXTENDED_SRGB, PlColorSpace::LINEAR_EXTENDED_SRGB }, { ColorSpace::GENERIC_XYZ, PlColorSpace::GENERIC_XYZ }, { ColorSpace::GENERIC_LAB, PlColorSpace::GENERIC_LAB }, { ColorSpace::ACES, PlColorSpace::ACES }, { ColorSpace::ACES_CG, PlColorSpace::ACES_CG }, { ColorSpace::ADOBE_RGB_1998, PlColorSpace::ADOBE_RGB_1998 }, { ColorSpace::DCI_P3, PlColorSpace::DCI_P3 }, { ColorSpace::ITU_709, PlColorSpace::ITU_709 }, { ColorSpace::ITU_2020, PlColorSpace::ITU_2020 }, { ColorSpace::ROMM_RGB, PlColorSpace::ROMM_RGB }, { ColorSpace::NTSC_1953, PlColorSpace::NTSC_1953 }, { ColorSpace::SMPTE_C, PlColorSpace::SMPTE_C } }; namespace InnerFormat { const string RAW_FORMAT = "image/x-raw"; const string EXTENDED_FORMAT = "image/x-skia"; const string RAW_EXTENDED_FORMATS[] = { "image/x-sony-arw", "image/x-canon-cr2", "image/x-adobe-dng", "image/x-nikon-nef", "image/x-nikon-nrw", "image/x-olympus-orf", "image/x-fuji-raf", "image/x-panasonic-rw2", "image/x-pentax-pef", "image/x-samsung-srw", }; } // namespace InnerFormat // BASE64 image prefix type data:image/;base64, static const std::string IMAGE_URL_PREFIX = "data:image/"; static const std::string BASE64_URL_PREFIX = ";base64,"; static const int INT_2 = 2; static const int INT_8 = 8; static const uint8_t NUM_0 = 0; static const uint8_t NUM_1 = 1; static const uint8_t NUM_2 = 2; static const uint8_t NUM_3 = 3; PluginServer &ImageSource::pluginServer_ = ImageUtils::GetPluginServer(); ImageSource::FormatAgentMap ImageSource::formatAgentMap_ = InitClass(); uint32_t ImageSource::GetSupportedFormats(set &formats) { IMAGE_LOGD("[ImageSource]get supported image type."); formats.clear(); vector classInfos; uint32_t ret = pluginServer_.PluginServerGetClassInfo(AbsImageDecoder::SERVICE_DEFAULT, classInfos); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource]get class info from plugin server,ret:%{public}u.", ret); return ret; } for (auto &info : classInfos) { map &capbility = info.capabilities; auto iter = capbility.find(IMAGE_ENCODE_FORMAT); if (iter == capbility.end()) { continue; } AttrData &attr = iter->second; const string *format = nullptr; if (attr.GetValue(format) != SUCCESS) { IMAGE_LOGE("[ImageSource]attr data get format failed."); continue; } if (*format == InnerFormat::RAW_FORMAT) { formats.insert(std::begin(InnerFormat::RAW_EXTENDED_FORMATS), std::end(InnerFormat::RAW_EXTENDED_FORMATS)); } else { formats.insert(*format); } } return SUCCESS; } unique_ptr ImageSource::CreateImageSource(unique_ptr is, const SourceOptions &opts, uint32_t &errorCode) { #if !defined(_WIN32) && !defined(_APPLE) StartTrace(HITRACE_TAG_ZIMAGE, "CreateImageSource by istream"); #endif IMAGE_LOGD("[ImageSource]create Imagesource with stream."); unique_ptr streamPtr = IstreamSourceStream::CreateSourceStream(move(is)); if (streamPtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create istream source stream."); errorCode = ERR_IMAGE_SOURCE_DATA; return nullptr; } ImageSource *sourcePtr = new (std::nothrow) ImageSource(std::move(streamPtr), opts); if (sourcePtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create ImageSource with stream."); errorCode = ERR_IMAGE_SOURCE_DATA; return nullptr; } errorCode = SUCCESS; #if !defined(_WIN32) && !defined(_APPLE) FinishTrace(HITRACE_TAG_ZIMAGE); #endif return unique_ptr(sourcePtr); } unique_ptr ImageSource::CreateImageSource(const uint8_t *data, uint32_t size, const SourceOptions &opts, uint32_t &errorCode) { #if !defined(_WIN32) && !defined(_APPLE) StartTrace(HITRACE_TAG_ZIMAGE, "CreateImageSource by data"); #endif IMAGE_LOGD("[ImageSource]create Imagesource with buffer."); if (data == nullptr || size == 0) { IMAGE_LOGE("[ImageSource]parameter error."); errorCode = ERR_IMAGE_DATA_ABNORMAL; return nullptr; } unique_ptr streamPtr = DecodeBase64(data, size); if (streamPtr == nullptr) { streamPtr = BufferSourceStream::CreateSourceStream(data, size); } if (streamPtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create buffer source stream."); errorCode = ERR_IMAGE_SOURCE_DATA; return nullptr; } ImageSource *sourcePtr = new (std::nothrow) ImageSource(std::move(streamPtr), opts); if (sourcePtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create ImageSource with buffer."); errorCode = ERR_IMAGE_SOURCE_DATA; return nullptr; } errorCode = SUCCESS; #if !defined(_WIN32) && !defined(_APPLE) FinishTrace(HITRACE_TAG_ZIMAGE); #endif return unique_ptr(sourcePtr); } unique_ptr ImageSource::CreateImageSource(const std::string &pathName, const SourceOptions &opts, uint32_t &errorCode) { #if !defined(_WIN32) && !defined(_APPLE) StartTrace(HITRACE_TAG_ZIMAGE, "CreateImageSource by path"); #endif IMAGE_LOGD("[ImageSource]create Imagesource with pathName."); unique_ptr streamPtr = DecodeBase64(pathName); if (streamPtr == nullptr) { streamPtr = FileSourceStream::CreateSourceStream(pathName); } if (streamPtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create file source stream."); errorCode = ERR_IMAGE_SOURCE_DATA; return nullptr; } ImageSource *sourcePtr = new (std::nothrow) ImageSource(std::move(streamPtr), opts); if (sourcePtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create ImageSource with pathName."); errorCode = ERR_IMAGE_SOURCE_DATA; return nullptr; } errorCode = SUCCESS; #if !defined(_WIN32) && !defined(_APPLE) FinishTrace(HITRACE_TAG_ZIMAGE); #endif return unique_ptr(sourcePtr); } unique_ptr ImageSource::CreateImageSource(const int fd, const SourceOptions &opts, uint32_t &errorCode) { #if !defined(_WIN32) && !defined(_APPLE) StartTrace(HITRACE_TAG_ZIMAGE, "CreateImageSource by fd"); #endif unique_ptr streamPtr = FileSourceStream::CreateSourceStream(fd); if (streamPtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create file source stream."); errorCode = ERR_IMAGE_SOURCE_DATA; return nullptr; } ImageSource *sourcePtr = new (std::nothrow) ImageSource(std::move(streamPtr), opts); if (sourcePtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create ImageSource by fd."); errorCode = ERR_IMAGE_SOURCE_DATA; return nullptr; } errorCode = SUCCESS; #if !defined(_WIN32) && !defined(_APPLE) FinishTrace(HITRACE_TAG_ZIMAGE); #endif return unique_ptr(sourcePtr); } unique_ptr ImageSource::CreateIncrementalImageSource(const IncrementalSourceOptions &opts, uint32_t &errorCode) { IMAGE_LOGD("[ImageSource]create incremental ImageSource."); unique_ptr streamPtr = IncrementalSourceStream::CreateSourceStream(opts.incrementalMode); if (streamPtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create incremental source stream."); errorCode = ERR_IMAGE_SOURCE_DATA; return nullptr; } ImageSource *sourcePtr = new (std::nothrow) ImageSource(std::move(streamPtr), opts.sourceOptions); if (sourcePtr == nullptr) { IMAGE_LOGE("[ImageSource]failed to create incremental ImageSource."); errorCode = ERR_IMAGE_SOURCE_DATA; return nullptr; } sourcePtr->SetIncrementalSource(true); errorCode = SUCCESS; return unique_ptr(sourcePtr); } void ImageSource::Reset() { // if use skia now, no need reset if (mainDecoder_ != nullptr && mainDecoder_->HasProperty(SKIA_DECODER)) { return; } imageStatusMap_.clear(); decodeState_ = SourceDecodingState::UNRESOLVED; sourceStreamPtr_->Seek(0); mainDecoder_ = nullptr; } unique_ptr ImageSource::CreatePixelMapEx(uint32_t index, const DecodeOptions &opts, uint32_t &errorCode) { IMAGE_LOGD("[ImageSource]CreatePixelMapEx srcPixelFormat:%{public}d, srcSize:(%{public}d, %{public}d)", sourceOptions_.pixelFormat, sourceOptions_.size.width, sourceOptions_.size.height); if (IsSpecialYUV()) { return CreatePixelMapForYUV(errorCode); } return CreatePixelMap(index, opts, errorCode); } unique_ptr ImageSource::CreatePixelMap(uint32_t index, const DecodeOptions &opts, uint32_t &errorCode) { #if !defined(_WIN32) && !defined(_APPLE) StartTrace(HITRACE_TAG_ZIMAGE, "CreatePixelMap"); #endif std::unique_lock guard(decodingMutex_); opts_ = opts; bool useSkia = opts_.sampleSize != 1; if (useSkia) { // we need reset to initial state to choose correct decoder Reset(); } auto iter = GetValidImageStatus(index, errorCode); if (iter == imageStatusMap_.end()) { IMAGE_LOGE("[ImageSource]get valid image status fail on create pixel map, ret:%{public}u.", errorCode); return nullptr; } // the mainDecoder_ may be borrowed by Incremental decoding, so needs to be checked. if (InitMainDecoder() != SUCCESS) { IMAGE_LOGE("[ImageSource]image decode plugin is null."); errorCode = ERR_IMAGE_PLUGIN_CREATE_FAILED; return nullptr; } unique_ptr pixelMap = make_unique(); if (pixelMap == nullptr || pixelMap.get() == nullptr) { IMAGE_LOGE("[ImageSource]create the pixel map unique_ptr fail."); errorCode = ERR_IMAGE_MALLOC_ABNORMAL; return nullptr; } ImagePlugin::PlImageInfo plInfo; errorCode = SetDecodeOptions(mainDecoder_, index, opts_, plInfo); if (errorCode != SUCCESS) { IMAGE_LOGE("[ImageSource]set decode options error (index:%{public}u), ret:%{public}u.", index, errorCode); return nullptr; } for (auto listener : decodeListeners_) { guard.unlock(); listener->OnEvent((int)DecodeEvent::EVENT_HEADER_DECODE); guard.lock(); } Size size = { .width = plInfo.size.width, .height = plInfo.size.height }; PostProc::ValidCropValue(opts_.CropRect, size); errorCode = UpdatePixelMapInfo(opts_, plInfo, *(pixelMap.get())); if (errorCode != SUCCESS) { IMAGE_LOGE("[ImageSource]update pixelmap info error ret:%{public}u.", errorCode); return nullptr; } DecodeContext context; FinalOutputStep finalOutputStep = FinalOutputStep::NO_CHANGE; if (!useSkia) { bool hasNinePatch = mainDecoder_->HasProperty(NINE_PATCH); finalOutputStep = GetFinalOutputStep(opts_, *(pixelMap.get()), hasNinePatch); IMAGE_LOGD("[ImageSource]finalOutputStep:%{public}d. opts.allocatorType %{public}d", finalOutputStep, opts_.allocatorType); if (finalOutputStep == FinalOutputStep::NO_CHANGE) { context.allocatorType = opts_.allocatorType; } else { context.allocatorType = AllocatorType::HEAP_ALLOC; } } errorCode = mainDecoder_->Decode(index, context); if (context.ifPartialOutput) { for (auto partialListener : decodeListeners_) { guard.unlock(); partialListener->OnEvent((int)DecodeEvent::EVENT_PARTIAL_DECODE); guard.lock(); } } if (!useSkia) { ninePatchInfo_.ninePatch = context.ninePatchContext.ninePatch; ninePatchInfo_.patchSize = context.ninePatchContext.patchSize; } guard.unlock(); if (errorCode != SUCCESS) { IMAGE_LOGE("[ImageSource]decode source fail, ret:%{public}u.", errorCode); if (context.pixelsBuffer.buffer != nullptr) { if (context.freeFunc != nullptr) { context.freeFunc(context.pixelsBuffer.buffer, context.pixelsBuffer.context, context.pixelsBuffer.bufferSize); } else { free(context.pixelsBuffer.buffer); context.pixelsBuffer.buffer = nullptr; } } return nullptr; } #ifdef IMAGE_COLORSPACE_FLAG // add graphic colorspace object to pixelMap. bool isSupportICCProfile = mainDecoder_->IsSupportICCProfile(); if (isSupportICCProfile) { OHOS::ColorManager::ColorSpace grColorSpace = mainDecoder_->getGrColorSpace(); pixelMap->InnerSetColorSpace(grColorSpace); } #endif pixelMap->SetPixelsAddr(context.pixelsBuffer.buffer, context.pixelsBuffer.context, context.pixelsBuffer.bufferSize, context.allocatorType, context.freeFunc); DecodeOptions procOpts; CopyOptionsToProcOpts(opts_, procOpts, *(pixelMap.get())); PostProc postProc; errorCode = postProc.DecodePostProc(procOpts, *(pixelMap.get()), finalOutputStep); if (errorCode != SUCCESS) { return nullptr; } if (!context.ifPartialOutput) { for (auto listener : decodeListeners_) { listener->OnEvent((int)DecodeEvent::EVENT_COMPLETE_DECODE); } } #if !defined(_WIN32) && !defined(_APPLE) FinishTrace(HITRACE_TAG_ZIMAGE); #endif return pixelMap; } unique_ptr ImageSource::CreateIncrementalPixelMap(uint32_t index, const DecodeOptions &opts, uint32_t &errorCode) { IncrementalPixelMap *incPixelMapPtr = new (std::nothrow) IncrementalPixelMap(index, opts, this); if (incPixelMapPtr == nullptr) { IMAGE_LOGE("[ImageSource]create the incremental pixel map unique_ptr fail."); errorCode = ERR_IMAGE_MALLOC_ABNORMAL; return nullptr; } errorCode = SUCCESS; return unique_ptr(incPixelMapPtr); } uint32_t ImageSource::PromoteDecoding(uint32_t index, const DecodeOptions &opts, PixelMap &pixelMap, ImageDecodingState &state, uint8_t &decodeProgress) { state = ImageDecodingState::UNRESOLVED; decodeProgress = 0; uint32_t ret = SUCCESS; std::unique_lock guard(decodingMutex_); opts_ = opts; auto imageStatusIter = GetValidImageStatus(index, ret); if (imageStatusIter == imageStatusMap_.end()) { IMAGE_LOGE("[ImageSource]get valid image status fail on promote decoding, ret:%{public}u.", ret); return ret; } auto incrementalRecordIter = incDecodingMap_.find(&pixelMap); if (incrementalRecordIter == incDecodingMap_.end()) { ret = AddIncrementalContext(pixelMap, incrementalRecordIter); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource]failed to add context on incremental decoding, ret:%{public}u.", ret); return ret; } } if (incrementalRecordIter->second.IncrementalState == ImageDecodingState::BASE_INFO_PARSED) { IMAGE_LOGD("[ImageSource]promote decode : set decode options."); ImagePlugin::PlImageInfo plInfo; ret = SetDecodeOptions(incrementalRecordIter->second.decoder, index, opts_, plInfo); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource]set decode options error (image index:%{public}u), ret:%{public}u.", index, ret); return ret; } auto iterator = decodeEventMap_.find((int)DecodeEvent::EVENT_HEADER_DECODE); if (iterator == decodeEventMap_.end()) { decodeEventMap_.insert(std::pair((int)DecodeEvent::EVENT_HEADER_DECODE, 1)); for (auto callback : decodeListeners_) { guard.unlock(); callback->OnEvent((int)DecodeEvent::EVENT_HEADER_DECODE); guard.lock(); } } Size size = { .width = plInfo.size.width, .height = plInfo.size.height }; PostProc::ValidCropValue(opts_.CropRect, size); ret = UpdatePixelMapInfo(opts_, plInfo, pixelMap); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource]update pixelmap info error (image index:%{public}u), ret:%{public}u.", index, ret); return ret; } incrementalRecordIter->second.IncrementalState = ImageDecodingState::IMAGE_DECODING; } if (incrementalRecordIter->second.IncrementalState == ImageDecodingState::IMAGE_DECODING) { ret = DoIncrementalDecoding(index, opts_, pixelMap, incrementalRecordIter->second); decodeProgress = incrementalRecordIter->second.decodingProgress; state = incrementalRecordIter->second.IncrementalState; if (isIncrementalCompleted_) { PostProc postProc; ret = postProc.DecodePostProc(opts_, pixelMap); if (state == ImageDecodingState::IMAGE_DECODED) { auto iter = decodeEventMap_.find((int)DecodeEvent::EVENT_COMPLETE_DECODE); if (iter == decodeEventMap_.end()) { decodeEventMap_.insert(std::pair((int)DecodeEvent::EVENT_COMPLETE_DECODE, 1)); for (auto listener : decodeListeners_) { guard.unlock(); listener->OnEvent((int)DecodeEvent::EVENT_COMPLETE_DECODE); guard.lock(); } } } } return ret; } // IMAGE_ERROR or IMAGE_DECODED. state = incrementalRecordIter->second.IncrementalState; decodeProgress = incrementalRecordIter->second.decodingProgress; if (incrementalRecordIter->second.IncrementalState == ImageDecodingState::IMAGE_ERROR) { IMAGE_LOGE("[ImageSource]invalid imageState %{public}d on incremental decoding.", incrementalRecordIter->second.IncrementalState); return ERR_IMAGE_DECODE_ABNORMAL; } return SUCCESS; } void ImageSource::DetachIncrementalDecoding(PixelMap &pixelMap) { std::lock_guard guard(decodingMutex_); auto iter = incDecodingMap_.find(&pixelMap); if (iter == incDecodingMap_.end()) { return; } if (mainDecoder_ == nullptr) { // return back the decoder to mainDecoder_. mainDecoder_ = std::move(iter->second.decoder); iter->second.decoder = nullptr; } incDecodingMap_.erase(iter); } uint32_t ImageSource::UpdateData(const uint8_t *data, uint32_t size, bool isCompleted) { if (sourceStreamPtr_ == nullptr) { IMAGE_LOGE("[ImageSource]image source update data, source stream is null."); return ERR_IMAGE_INVALID_PARAMETER; } std::lock_guard guard(decodingMutex_); if (isCompleted) { isIncrementalCompleted_ = isCompleted; } return sourceStreamPtr_->UpdateData(data, size, isCompleted); } DecodeEvent ImageSource::GetDecodeEvent() { return decodeEvent_; } uint32_t ImageSource::GetImageInfo(uint32_t index, ImageInfo &imageInfo) { #if !defined(_WIN32) && !defined(_APPLE) StartTrace(HITRACE_TAG_ZIMAGE, "GetImageInfo by index"); #endif uint32_t ret = SUCCESS; std::unique_lock guard(decodingMutex_); auto iter = GetValidImageStatus(index, ret); if (iter == imageStatusMap_.end()) { guard.unlock(); IMAGE_LOGE("[ImageSource]get valid image status fail on get image info, ret:%{public}u.", ret); return ret; } ImageInfo &info = (iter->second).imageInfo; if (info.size.width == 0 || info.size.height == 0) { IMAGE_LOGE("[ImageSource]get the image size fail on get image info, width:%{public}d, height:%{public}d.", info.size.width, info.size.height); return ERR_IMAGE_DECODE_FAILED; } imageInfo = info; #if !defined(_WIN32) && !defined(_APPLE) FinishTrace(HITRACE_TAG_ZIMAGE); #endif return SUCCESS; } uint32_t ImageSource::ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value, const std::string &path) { std::unique_lock guard(decodingMutex_); uint32_t ret; auto iter = GetValidImageStatus(0, ret); if (iter == imageStatusMap_.end()) { IMAGE_LOGE("[ImageSource]get valid image status fail on modify image property, ret:%{public}u.", ret); return ret; } ret = mainDecoder_->ModifyImageProperty(index, key, value, path); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource] ModifyImageProperty fail, ret:%{public}u", ret); return ret; } return SUCCESS; } uint32_t ImageSource::ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value, const int fd) { std::unique_lock guard(decodingMutex_); uint32_t ret; auto iter = GetValidImageStatus(0, ret); if (iter == imageStatusMap_.end()) { IMAGE_LOGE("[ImageSource]get valid image status fail on modify image property, ret:%{public}u.", ret); return ret; } ret = mainDecoder_->ModifyImageProperty(index, key, value, fd); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource] ModifyImageProperty fail, ret:%{public}u", ret); return ret; } return SUCCESS; } uint32_t ImageSource::ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value, uint8_t *data, uint32_t size) { std::unique_lock guard(decodingMutex_); uint32_t ret; auto iter = GetValidImageStatus(0, ret); if (iter == imageStatusMap_.end()) { IMAGE_LOGE("[ImageSource]get valid image status fail on modify image property, ret:%{public}u.", ret); return ret; } ret = mainDecoder_->ModifyImageProperty(index, key, value, data, size); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource] ModifyImageProperty fail, ret:%{public}u", ret); return ret; } return SUCCESS; } uint32_t ImageSource::GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value) { std::unique_lock guard(decodingMutex_); uint32_t ret; auto iter = GetValidImageStatus(0, ret); if (iter == imageStatusMap_.end()) { IMAGE_LOGE("[ImageSource]get valid image status fail on get image property, ret:%{public}u.", ret); return ret; } ret = mainDecoder_->GetImagePropertyInt(index, key, value); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource] GetImagePropertyInt fail, ret:%{public}u", ret); return ret; } return SUCCESS; } uint32_t ImageSource::GetImagePropertyString(uint32_t index, const std::string &key, std::string &value) { std::unique_lock guard(decodingMutex_); uint32_t ret; auto iter = GetValidImageStatus(0, ret); if (iter == imageStatusMap_.end()) { IMAGE_LOGE("[ImageSource]get valid image status fail on get image property, ret:%{public}u.", ret); return ret; } ret = mainDecoder_->GetImagePropertyString(index, key, value); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource] GetImagePropertyString fail, ret:%{public}u", ret); return ret; } return SUCCESS; } const SourceInfo &ImageSource::GetSourceInfo(uint32_t &errorCode) { std::lock_guard guard(decodingMutex_); if (IsSpecialYUV()) { return sourceInfo_; } errorCode = DecodeSourceInfo(true); return sourceInfo_; } void ImageSource::RegisterListener(PeerListener *listener) { if (listener == nullptr) { return; } std::lock_guard guard(listenerMutex_); listeners_.insert(listener); } void ImageSource::UnRegisterListener(PeerListener *listener) { if (listener == nullptr) { return; } std::lock_guard guard(listenerMutex_); auto iter = listeners_.find(listener); if (iter != listeners_.end()) { listeners_.erase(iter); } } void ImageSource::AddDecodeListener(DecodeListener *listener) { if (listener == nullptr) { IMAGE_LOGE("AddDecodeListener listener null"); return; } std::lock_guard guard(listenerMutex_); decodeListeners_.insert(listener); } void ImageSource::RemoveDecodeListener(DecodeListener *listener) { if (listener == nullptr) { IMAGE_LOGE("RemoveDecodeListener listener null"); return; } std::lock_guard guard(listenerMutex_); auto iter = decodeListeners_.find(listener); if (iter != decodeListeners_.end()) { decodeListeners_.erase(iter); } } ImageSource::~ImageSource() { std::lock_guard guard(listenerMutex_); for (const auto &listener : listeners_) { listener->OnPeerDestory(); } } bool ImageSource::IsStreamCompleted() { std::lock_guard guard(decodingMutex_); return sourceStreamPtr_->IsStreamCompleted(); } // ------------------------------- private method ------------------------------- ImageSource::ImageSource(unique_ptr &&stream, const SourceOptions &opts) : sourceStreamPtr_(stream.release()) { sourceInfo_.encodedFormat = opts.formatHint; sourceInfo_.baseDensity = opts.baseDensity; sourceOptions_.formatHint = opts.formatHint; sourceOptions_.baseDensity = opts.baseDensity; sourceOptions_.pixelFormat = opts.pixelFormat; sourceOptions_.size.width = opts.size.width; sourceOptions_.size.height = opts.size.height; } ImageSource::FormatAgentMap ImageSource::InitClass() { vector classInfos; pluginServer_.PluginServerGetClassInfo(AbsImageFormatAgent::SERVICE_DEFAULT, classInfos); set formats; for (auto &info : classInfos) { auto &capabilities = info.capabilities; auto iter = capabilities.find(IMAGE_ENCODE_FORMAT); if (iter == capabilities.end()) { continue; } AttrData &attr = iter->second; string format; if (SUCCESS != attr.GetValue(format)) { IMAGE_LOGE("[ImageSource]attr data get format:[%{public}s] failed.", format.c_str()); continue; } formats.insert(move(format)); } FormatAgentMap tempAgentMap; AbsImageFormatAgent *formatAgent = nullptr; for (auto format : formats) { map capabilities = { { IMAGE_ENCODE_FORMAT, AttrData(format) } }; formatAgent = pluginServer_.CreateObject(AbsImageFormatAgent::SERVICE_DEFAULT, capabilities); if (formatAgent == nullptr) { continue; } tempAgentMap.insert(FormatAgentMap::value_type(std::move(format), formatAgent)); } return tempAgentMap; } uint32_t ImageSource::CheckEncodedFormat(AbsImageFormatAgent &agent) { uint32_t size = agent.GetHeaderSize(); ImagePlugin::DataStreamBuffer outData; if (sourceStreamPtr_ == nullptr) { IMAGE_LOGE("[ImageSource]check image format, source stream is null."); return ERR_IMAGE_INVALID_PARAMETER; } if (!sourceStreamPtr_->Peek(size, outData)) { IMAGE_LOGE("[ImageSource]stream peek the data fail."); return ERR_IMAGE_SOURCE_DATA; } if (outData.inputStreamBuffer == nullptr || outData.dataSize < size) { IMAGE_LOGE("[ImageSource]the ouData is incomplete."); return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; } if (!agent.CheckFormat(outData.inputStreamBuffer, size)) { IMAGE_LOGE("[ImageSource]check mismatched format :%{public}s.", agent.GetFormatType().c_str()); return ERR_IMAGE_MISMATCHED_FORMAT; } return SUCCESS; } uint32_t ImageSource::CheckFormatHint(const string &formatHint, FormatAgentMap::iterator &formatIter) { uint32_t ret = ERROR; formatIter = formatAgentMap_.find(formatHint); if (formatIter == formatAgentMap_.end()) { IMAGE_LOGE("[ImageSource]check input format fail."); return ret; } AbsImageFormatAgent *agent = formatIter->second; ret = CheckEncodedFormat(*agent); if (ret != SUCCESS) { if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { IMAGE_LOGE("[ImageSource]image source incomplete."); } return ret; } return SUCCESS; } uint32_t ImageSource::GetEncodedFormat(const string &formatHint, string &format) { bool streamIncomplete = false; auto hintIter = formatAgentMap_.end(); if (!formatHint.empty()) { uint32_t ret = CheckFormatHint(formatHint, hintIter); if (ret == ERR_IMAGE_SOURCE_DATA) { IMAGE_LOGE("[ImageSource]image source data error."); return ret; } else if (ret == SUCCESS) { format = hintIter->first; IMAGE_LOGD("[ImageSource]check input image format success, format:%{public}s.", format.c_str()); return SUCCESS; } else if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { streamIncomplete = true; IMAGE_LOGE("[ImageSource]image source data error ERR_IMAGE_SOURCE_DATA_INCOMPLETE."); } } for (auto iter = formatAgentMap_.begin(); iter != formatAgentMap_.end(); ++iter) { string curFormat = iter->first; if (iter == hintIter || curFormat == InnerFormat::RAW_FORMAT) { continue; // has been checked before. } AbsImageFormatAgent *agent = iter->second; auto result = CheckEncodedFormat(*agent); if (result == ERR_IMAGE_MISMATCHED_FORMAT) { continue; } else if (result == SUCCESS) { IMAGE_LOGI("[ImageSource]GetEncodedFormat success format :%{public}s.", iter->first.c_str()); format = iter->first; return SUCCESS; } else if (result == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { streamIncomplete = true; } } if (streamIncomplete) { IMAGE_LOGE("[ImageSource]image source incomplete."); return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; } // default return raw image format = InnerFormat::RAW_FORMAT; IMAGE_LOGI("[ImageSource]image default to raw format."); return SUCCESS; } uint32_t ImageSource::OnSourceRecognized(bool isAcquiredImageNum) { uint32_t ret = InitMainDecoder(); if (ret != SUCCESS) { sourceInfo_.state = SourceInfoState::UNSUPPORTED_FORMAT; decodeState_ = SourceDecodingState::UNSUPPORTED_FORMAT; IMAGE_LOGE("[ImageSource]image decode error, ret:[%{public}u].", ret); return ret; } // for raw image, we need check the original format after decoder initialzation string value; ret = mainDecoder_->GetImagePropertyString(0, ACTUAL_IMAGE_ENCODED_FORMAT, value); if (ret == SUCCESS) { // update new format sourceInfo_.encodedFormat = value; IMAGE_LOGI("[ImageSource] update new format, value:%{public}s", value.c_str()); } else { IMAGE_LOGD("[ImageSource] GetImagePropertyString fail, ret:%{public}u", ret); } if (isAcquiredImageNum) { ret = mainDecoder_->GetTopLevelImageNum(sourceInfo_.topLevelImageNum); if (ret != SUCCESS) { if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { sourceInfo_.state = SourceInfoState::SOURCE_INCOMPLETE; IMAGE_LOGE("[ImageSource]image source data incomplete."); return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; } sourceInfo_.state = SourceInfoState::FILE_INFO_ERROR; decodeState_ = SourceDecodingState::FILE_INFO_ERROR; IMAGE_LOGE("[ImageSource]image source error."); return ret; } } sourceInfo_.state = SourceInfoState::FILE_INFO_PARSED; decodeState_ = SourceDecodingState::FILE_INFO_DECODED; return SUCCESS; } uint32_t ImageSource::OnSourceUnresolved() { string formatResult; auto ret = GetEncodedFormat(sourceInfo_.encodedFormat, formatResult); if (ret != SUCCESS) { if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { IMAGE_LOGE("[ImageSource]image source incomplete."); sourceInfo_.state = SourceInfoState::SOURCE_INCOMPLETE; return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; } else if (ret == ERR_IMAGE_UNKNOWN_FORMAT) { IMAGE_LOGE("[ImageSource]image unknown format."); sourceInfo_.state = SourceInfoState::UNKNOWN_FORMAT; decodeState_ = SourceDecodingState::UNKNOWN_FORMAT; return ERR_IMAGE_UNKNOWN_FORMAT; } sourceInfo_.state = SourceInfoState::SOURCE_ERROR; decodeState_ = SourceDecodingState::SOURCE_ERROR; IMAGE_LOGE("[ImageSource]image source error."); return ret; } sourceInfo_.encodedFormat = formatResult; decodeState_ = SourceDecodingState::FORMAT_RECOGNIZED; return SUCCESS; } uint32_t ImageSource::DecodeSourceInfo(bool isAcquiredImageNum) { uint32_t ret = SUCCESS; if (decodeState_ >= SourceDecodingState::FILE_INFO_DECODED) { if (isAcquiredImageNum) { decodeState_ = SourceDecodingState::FORMAT_RECOGNIZED; } else { return SUCCESS; } } if (decodeState_ == SourceDecodingState::UNRESOLVED) { ret = OnSourceUnresolved(); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource]unresolved source: check format failed, ret:[%{public}d].", ret); return ret; } } if (decodeState_ == SourceDecodingState::FORMAT_RECOGNIZED) { ret = OnSourceRecognized(isAcquiredImageNum); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource]recognized source: get source info failed, ret:[%{public}d].", ret); return ret; } return SUCCESS; } IMAGE_LOGE("[ImageSource]invalid source state %{public}d on decode source info.", decodeState_); switch (decodeState_) { case SourceDecodingState::SOURCE_ERROR: { ret = ERR_IMAGE_SOURCE_DATA; break; } case SourceDecodingState::UNKNOWN_FORMAT: { ret = ERR_IMAGE_UNKNOWN_FORMAT; break; } case SourceDecodingState::UNSUPPORTED_FORMAT: { ret = ERR_IMAGE_PLUGIN_CREATE_FAILED; break; } case SourceDecodingState::FILE_INFO_ERROR: { ret = ERR_IMAGE_DECODE_FAILED; break; } default: { ret = ERROR; break; } } return ret; } uint32_t ImageSource::DecodeImageInfo(uint32_t index, ImageStatusMap::iterator &iter) { uint32_t ret = DecodeSourceInfo(false); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource]decode the image fail, ret:%{public}d.", ret); return ret; } if (mainDecoder_ == nullptr) { IMAGE_LOGE("[ImageSource]get image size, image decode plugin is null."); return ERR_IMAGE_PLUGIN_CREATE_FAILED; } ImagePlugin::PlSize size; ret = mainDecoder_->GetImageSize(index, size); if (ret == SUCCESS) { ImageDecodingStatus imageStatus; imageStatus.imageInfo.size.width = size.width; imageStatus.imageInfo.size.height = size.height; imageStatus.imageState = ImageDecodingState::BASE_INFO_PARSED; auto result = imageStatusMap_.insert(ImageStatusMap::value_type(index, imageStatus)); iter = result.first; return SUCCESS; } else if (ret == ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { IMAGE_LOGE("[ImageSource]source data incomplete."); return ERR_IMAGE_SOURCE_DATA_INCOMPLETE; } else { ImageDecodingStatus status; status.imageState = ImageDecodingState::BASE_INFO_ERROR; auto errorResult = imageStatusMap_.insert(ImageStatusMap::value_type(index, status)); iter = errorResult.first; IMAGE_LOGE("[ImageSource]decode the image info fail."); return ERR_IMAGE_DECODE_FAILED; } } uint32_t ImageSource::InitMainDecoder() { if (mainDecoder_ != nullptr) { return SUCCESS; } uint32_t result = SUCCESS; mainDecoder_ = std::unique_ptr(CreateDecoder(result)); return result; } AbsImageDecoder *ImageSource::CreateDecoder(uint32_t &errorCode) { // in normal mode, we can get actual encoded format to the user // but we need transfer to skia codec for adaption, "image/x-skia" std::string encodedFormat = sourceInfo_.encodedFormat; if (opts_.sampleSize != 1) { encodedFormat = InnerFormat::EXTENDED_FORMAT; } #if defined(_ANDROID) || defined(_IOS) auto decoder = new JpegDecoder(); #else map capabilities = { { IMAGE_ENCODE_FORMAT, AttrData(encodedFormat) } }; auto decoder = pluginServer_.CreateObject(AbsImageDecoder::SERVICE_DEFAULT, capabilities); #endif if (decoder == nullptr) { IMAGE_LOGE("[ImageSource]failed to create decoder object."); errorCode = ERR_IMAGE_PLUGIN_CREATE_FAILED; return nullptr; } errorCode = SUCCESS; decoder->SetSource(*sourceStreamPtr_); return decoder; } uint32_t ImageSource::SetDecodeOptions(std::unique_ptr &decoder, uint32_t index, const DecodeOptions &opts, ImagePlugin::PlImageInfo &plInfo) { PixelDecodeOptions plOptions; CopyOptionsToPlugin(opts, plOptions); uint32_t ret = decoder->SetDecodeOptions(index, plOptions, plInfo); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource]decoder plugin set decode options fail (image index:%{public}u), ret:%{public}u.", index, ret); return ret; } auto iter = imageStatusMap_.find(index); if (iter != imageStatusMap_.end()) { ImageInfo &info = (iter->second).imageInfo; IMAGE_LOGD("[ImageSource]SetDecodeOptions plInfo.pixelFormat %{public}d", plInfo.pixelFormat); PlPixelFormat format = plInfo.pixelFormat; auto find_item = std::find_if(PIXEL_FORMAT_MAP.begin(), PIXEL_FORMAT_MAP.end(), [format](const std::map::value_type item) { return item.second == format; }); if (find_item != PIXEL_FORMAT_MAP.end()) { info.pixelFormat = (*find_item).first; } IMAGE_LOGD("[ImageSource]SetDecodeOptions info.pixelFormat %{public}d", info.pixelFormat); } return SUCCESS; } uint32_t ImageSource::UpdatePixelMapInfo(const DecodeOptions &opts, ImagePlugin::PlImageInfo &plInfo, PixelMap &pixelMap) { pixelMap.SetEditable(opts.editable); ImageInfo info; info.baseDensity = sourceInfo_.baseDensity; info.size.width = plInfo.size.width; info.size.height = plInfo.size.height; info.pixelFormat = static_cast(plInfo.pixelFormat); info.alphaType = static_cast(plInfo.alphaType); return pixelMap.SetImageInfo(info); } void ImageSource::CopyOptionsToPlugin(const DecodeOptions &opts, PixelDecodeOptions &plOpts) { plOpts.CropRect.left = opts.CropRect.left; plOpts.CropRect.top = opts.CropRect.top; plOpts.CropRect.width = opts.CropRect.width; plOpts.CropRect.height = opts.CropRect.height; plOpts.desiredSize.width = opts.desiredSize.width; plOpts.desiredSize.height = opts.desiredSize.height; plOpts.rotateDegrees = opts.rotateDegrees; plOpts.sampleSize = opts.sampleSize; auto formatSearch = PIXEL_FORMAT_MAP.find(opts.desiredPixelFormat); plOpts.desiredPixelFormat = (formatSearch != PIXEL_FORMAT_MAP.end()) ? formatSearch->second : PlPixelFormat::RGBA_8888; auto colorSearch = COLOR_SPACE_MAP.find(opts.desiredColorSpace); plOpts.desiredColorSpace = (colorSearch != COLOR_SPACE_MAP.end()) ? colorSearch->second : PlColorSpace::UNKNOWN; plOpts.allowPartialImage = opts.allowPartialImage; plOpts.editable = opts.editable; } void ImageSource::CopyOptionsToProcOpts(const DecodeOptions &opts, DecodeOptions &procOpts, PixelMap &pixelMap) { procOpts.fitDensity = opts.fitDensity; procOpts.CropRect.left = opts.CropRect.left; procOpts.CropRect.top = opts.CropRect.top; procOpts.CropRect.width = opts.CropRect.width; procOpts.CropRect.height = opts.CropRect.height; procOpts.desiredSize.width = opts.desiredSize.width; procOpts.desiredSize.height = opts.desiredSize.height; procOpts.rotateDegrees = opts.rotateDegrees; procOpts.sampleSize = opts.sampleSize; procOpts.desiredPixelFormat = opts.desiredPixelFormat; if (opts.allocatorType == AllocatorType::DEFAULT) { procOpts.allocatorType = AllocatorType::HEAP_ALLOC; } else { procOpts.allocatorType = opts.allocatorType; } procOpts.desiredColorSpace = opts.desiredColorSpace; procOpts.allowPartialImage = opts.allowPartialImage; procOpts.editable = opts.editable; // we need preference_ when post processing procOpts.preference = preference_; } ImageSource::ImageStatusMap::iterator ImageSource::GetValidImageStatus(uint32_t index, uint32_t &errorCode) { auto iter = imageStatusMap_.find(index); if (iter == imageStatusMap_.end()) { errorCode = DecodeImageInfo(index, iter); if (errorCode != SUCCESS) { IMAGE_LOGE("[ImageSource]image info decode fail, ret:%{public}u.", errorCode); return imageStatusMap_.end(); } } else if (iter->second.imageState < ImageDecodingState::BASE_INFO_PARSED) { IMAGE_LOGE("[ImageSource]invalid imageState %{public}d on get image status.", iter->second.imageState); errorCode = ERR_IMAGE_DECODE_FAILED; return imageStatusMap_.end(); } errorCode = SUCCESS; return iter; } uint32_t ImageSource::AddIncrementalContext(PixelMap &pixelMap, IncrementalRecordMap::iterator &iterator) { uint32_t ret = SUCCESS; IncrementalDecodingContext context; if (mainDecoder_ != nullptr) { // borrowed decoder from the mainDecoder_. context.decoder = std::move(mainDecoder_); } else { context.decoder = std::unique_ptr(CreateDecoder(ret)); } if (context.decoder == nullptr) { IMAGE_LOGE("[ImageSource]failed to create decoder on add incremental context, ret:%{public}u.", ret); return ret; } // mainDecoder has parsed base info in DecodeImageInfo(); context.IncrementalState = ImageDecodingState::BASE_INFO_PARSED; auto result = incDecodingMap_.insert(IncrementalRecordMap::value_type(&pixelMap, std::move(context))); iterator = result.first; return SUCCESS; } uint32_t ImageSource::DoIncrementalDecoding(uint32_t index, const DecodeOptions &opts, PixelMap &pixelMap, IncrementalDecodingContext &recordContext) { IMAGE_LOGD("[ImageSource]do incremental decoding: begin."); uint8_t *pixelAddr = static_cast(pixelMap.GetWritablePixels()); ProgDecodeContext context; context.decodeContext.pixelsBuffer.buffer = pixelAddr; uint32_t ret = recordContext.decoder->PromoteIncrementalDecode(index, context); if (context.decodeContext.pixelsBuffer.buffer != nullptr && pixelAddr == nullptr) { pixelMap.SetPixelsAddr(context.decodeContext.pixelsBuffer.buffer, context.decodeContext.pixelsBuffer.context, context.decodeContext.pixelsBuffer.bufferSize, context.decodeContext.allocatorType, context.decodeContext.freeFunc); } IMAGE_LOGD("[ImageSource]do incremental decoding progress:%{public}u.", context.totalProcessProgress); recordContext.decodingProgress = context.totalProcessProgress; if (ret != SUCCESS && ret != ERR_IMAGE_SOURCE_DATA_INCOMPLETE) { recordContext.IncrementalState = ImageDecodingState::IMAGE_ERROR; IMAGE_LOGE("[ImageSource]do incremental decoding source fail, ret:%{public}u.", ret); return ret; } if (ret == SUCCESS) { recordContext.IncrementalState = ImageDecodingState::IMAGE_DECODED; IMAGE_LOGI("[ImageSource]do incremental decoding success."); } return ret; } const NinePatchInfo &ImageSource::GetNinePatchInfo() const { return ninePatchInfo_; } void ImageSource::SetMemoryUsagePreference(const MemoryUsagePreference preference) { preference_ = preference; } MemoryUsagePreference ImageSource::GetMemoryUsagePreference() { return preference_; } uint32_t ImageSource::GetFilterArea(const int &privacyType, std::vector> &ranges) { std::unique_lock guard(decodingMutex_); uint32_t ret; auto iter = GetValidImageStatus(0, ret); if (iter == imageStatusMap_.end()) { IMAGE_LOGE("[ImageSource]get valid image status fail on get filter area, ret:%{public}u.", ret); return ret; } ret = mainDecoder_->GetFilterArea(privacyType, ranges); if (ret != SUCCESS) { IMAGE_LOGE("[ImageSource] GetFilterArea fail, ret:%{public}u", ret); return ret; } return SUCCESS; } void ImageSource::SetIncrementalSource(const bool isIncrementalSource) { isIncrementalSource_ = isIncrementalSource; } bool ImageSource::IsIncrementalSource() { return isIncrementalSource_; } FinalOutputStep ImageSource::GetFinalOutputStep(const DecodeOptions &opts, PixelMap &pixelMap, bool hasNinePatch) { ImageInfo info; pixelMap.GetImageInfo(info); ImageInfo dstImageInfo; dstImageInfo.size = opts.desiredSize; dstImageInfo.pixelFormat = opts.desiredPixelFormat; if (opts.desiredPixelFormat == PixelFormat::UNKNOWN) { if (preference_ == MemoryUsagePreference::LOW_RAM && info.alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) { dstImageInfo.pixelFormat = PixelFormat::RGB_565; } else { dstImageInfo.pixelFormat = PixelFormat::RGBA_8888; } } // decode use, this value may be changed by real pixelFormat if (pixelMap.GetAlphaType() == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL) { dstImageInfo.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL; } else { dstImageInfo.alphaType = pixelMap.GetAlphaType(); } bool densityChange = HasDensityChange(opts, info, hasNinePatch); bool sizeChange = ImageSizeChange(pixelMap.GetWidth(), pixelMap.GetHeight(), opts.desiredSize.width, opts.desiredSize.height); bool rotateChange = !ImageUtils::FloatCompareZero(opts.rotateDegrees); bool convertChange = ImageConverChange(opts.CropRect, dstImageInfo, info); if (sizeChange) { return FinalOutputStep::SIZE_CHANGE; } if (densityChange) { return FinalOutputStep::DENSITY_CHANGE; } if (rotateChange) { return FinalOutputStep::ROTATE_CHANGE; } if (convertChange) { return FinalOutputStep::CONVERT_CHANGE; } return FinalOutputStep::NO_CHANGE; } bool ImageSource::HasDensityChange(const DecodeOptions &opts, ImageInfo &srcImageInfo, bool hasNinePatch) { return !hasNinePatch && (srcImageInfo.baseDensity > 0) && (opts.fitDensity > 0) && (srcImageInfo.baseDensity != opts.fitDensity); } bool ImageSource::ImageSizeChange(int32_t width, int32_t height, int32_t desiredWidth, int32_t desiredHeight) { bool sizeChange = false; if (desiredWidth > 0 && desiredHeight > 0 && width > 0 && height > 0) { float scaleX = static_cast(desiredWidth) / static_cast(width); float scaleY = static_cast(desiredHeight) / static_cast(height); if ((fabs(scaleX - 1.0f) >= EPSILON) && (fabs(scaleY - 1.0f) >= EPSILON)) { sizeChange = true; } } return sizeChange; } bool ImageSource::ImageConverChange(const Rect &cropRect, ImageInfo &dstImageInfo, ImageInfo &srcImageInfo) { bool hasPixelConvert = false; dstImageInfo.alphaType = ImageUtils::GetValidAlphaTypeByFormat(dstImageInfo.alphaType, dstImageInfo.pixelFormat); if (dstImageInfo.pixelFormat != srcImageInfo.pixelFormat || dstImageInfo.alphaType != srcImageInfo.alphaType) { hasPixelConvert = true; } CropValue value = PostProc::GetCropValue(cropRect, srcImageInfo.size); if (value == CropValue::NOCROP && !hasPixelConvert) { IMAGE_LOGD("[ImageSource]no need crop and pixel convert."); return false; } else if (value == CropValue::INVALID) { IMAGE_LOGE("[ImageSource]invalid corp region, top:%{public}d, left:%{public}d, " "width:%{public}d, height:%{public}d", cropRect.top, cropRect.left, cropRect.width, cropRect.height); return false; } return true; } unique_ptr ImageSource::DecodeBase64(const uint8_t *data, uint32_t size) { string data1(reinterpret_cast(data), size); return DecodeBase64(data1); } unique_ptr ImageSource::DecodeBase64(const string &data) { if (data.size() < IMAGE_URL_PREFIX.size() || (data.compare(0, IMAGE_URL_PREFIX.size(), IMAGE_URL_PREFIX) != 0)) { IMAGE_LOGD("[ImageSource]Base64 image header mismatch."); return nullptr; } size_t encoding = data.find(BASE64_URL_PREFIX, IMAGE_URL_PREFIX.size()); if (encoding == data.npos) { IMAGE_LOGE("[ImageSource]Base64 mismatch."); return nullptr; } string b64Data = data.substr(encoding + BASE64_URL_PREFIX.size()); size_t rawDataLen = b64Data.size() - count(b64Data.begin(), b64Data.end(), '='); rawDataLen -= (rawDataLen / INT_8) * INT_2; SkBase64 base64Decoder; if (base64Decoder.decode(b64Data.data(), b64Data.size()) != SkBase64::kNoError) { IMAGE_LOGE("[ImageSource]base64 image decode failed!"); return nullptr; } auto base64Data = base64Decoder.getData(); const uint8_t* imageData = reinterpret_cast(base64Data); IMAGE_LOGD("[ImageSource]Create BufferSource from decoded base64 string."); auto result = BufferSourceStream::CreateSourceStream(imageData, rawDataLen); if (base64Data != nullptr) { delete[] base64Data; base64Data = nullptr; } return result; } bool ImageSource::IsSpecialYUV() { const bool isBufferSource = (sourceStreamPtr_ != nullptr) && (sourceStreamPtr_->GetStreamType() == ImagePlugin::BUFFER_SOURCE_TYPE); const bool isSizeValid = (sourceOptions_.size.width > 0) && (sourceOptions_.size.height > 0); const bool isYUV = (sourceOptions_.pixelFormat == PixelFormat::NV12) || (sourceOptions_.pixelFormat == PixelFormat::NV21); return (isBufferSource && isSizeValid && isYUV); } static inline uint8_t FloatToUint8(float f) { int data = static_cast(f + 0.5f); if (data < 0) { data = 0; } else if (data > UINT8_MAX) { data = UINT8_MAX; } return static_cast(data); } bool ImageSource::ConvertYUV420ToRGBA(uint8_t *data, uint32_t size, bool isSupportOdd, bool isAddUV, uint32_t &errorCode) { IMAGE_LOGD("[ImageSource]ConvertYUV420ToRGBA IN srcPixelFormat:%{public}d, srcSize:(%{public}d, %{public}d)", sourceOptions_.pixelFormat, sourceOptions_.size.width, sourceOptions_.size.height); if ((!isSupportOdd) && (sourceOptions_.size.width & 1) == 1) { IMAGE_LOGE("[ImageSource]ConvertYUV420ToRGBA odd width, %{public}d", sourceOptions_.size.width); errorCode = ERR_IMAGE_DATA_UNSUPPORT; return false; } const size_t width = sourceOptions_.size.width; const size_t height = sourceOptions_.size.height; const size_t uvwidth = (isSupportOdd && isAddUV) ? (width + (width & 1)) : width; const uint8_t *yuvPlane = sourceStreamPtr_->GetDataPtr(); const size_t yuvSize = sourceStreamPtr_->GetStreamSize(); const size_t ubase = width * height + ((sourceOptions_.pixelFormat == PixelFormat::NV21) ? 0 : 1); const size_t vbase = width * height + ((sourceOptions_.pixelFormat == PixelFormat::NV21) ? 1 : 0); IMAGE_LOGD("[ImageSource]ConvertYUV420ToRGBA uvbase:(%{public}zu, %{public}zu), width:(%{public}zu, %{public}zu)", ubase, vbase, width, uvwidth); for (size_t h = 0; h < height; h++) { const size_t yline = h * width; const size_t uvline = (h >> 1) * uvwidth; for (size_t w = 0; w < width; w++) { const size_t ypos = yline + w; const size_t upos = ubase + uvline + (w & (~1)); const size_t vpos = vbase + uvline + (w & (~1)); const uint8_t y = (ypos < yuvSize) ? yuvPlane[ypos] : 0; const uint8_t u = (upos < yuvSize) ? yuvPlane[upos] : 0; const uint8_t v = (vpos < yuvSize) ? yuvPlane[vpos] : 0; // jpeg const uint8_t r = FloatToUint8((1.0f * y) + (1.402f * v) - (0.703749f * UINT8_MAX)); const uint8_t g = FloatToUint8((1.0f * y) - (0.344136f * u) - (0.714136f * v) + (0.531211f * UINT8_MAX)); const uint8_t b = FloatToUint8((1.0f * y) + (1.772f * u) - (0.889475f * UINT8_MAX)); const size_t rgbpos = ypos << 2; if ((rgbpos + NUM_3) < size) { data[rgbpos + NUM_0] = r; data[rgbpos + NUM_1] = g; data[rgbpos + NUM_2] = b; data[rgbpos + NUM_3] = UINT8_MAX; } } } IMAGE_LOGD("[ImageSource]ConvertYUV420ToRGBA OUT"); return true; } unique_ptr ImageSource::CreatePixelMapForYUV(uint32_t &errorCode) { IMAGE_LOGD("[ImageSource]CreatePixelMapForYUV IN srcPixelFormat:%{public}d, srcSize:(%{public}d, %{public}d)", sourceOptions_.pixelFormat, sourceOptions_.size.width, sourceOptions_.size.height); unique_ptr pixelMap = make_unique(); if (pixelMap == nullptr) { IMAGE_LOGE("[ImageSource]create the pixel map unique_ptr fail."); errorCode = ERR_IMAGE_MALLOC_ABNORMAL; return nullptr; } ImageInfo info; info.baseDensity = sourceOptions_.baseDensity; info.size.width = sourceOptions_.size.width; info.size.height = sourceOptions_.size.height; info.pixelFormat = PixelFormat::RGBA_8888; info.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE; errorCode = pixelMap->SetImageInfo(info); if (errorCode != SUCCESS) { IMAGE_LOGE("[ImageSource]update pixelmap info error ret:%{public}u.", errorCode); return nullptr; } size_t bufferSize = static_cast(pixelMap->GetWidth() * pixelMap->GetHeight() * pixelMap->GetPixelBytes()); auto buffer = malloc(bufferSize); if (buffer == nullptr) { HiLog::Error(LABEL, "allocate memory size %{public}zu fail", bufferSize); errorCode = ERR_IMAGE_MALLOC_ABNORMAL; return nullptr; } pixelMap->SetEditable(false); pixelMap->SetPixelsAddr(buffer, nullptr, bufferSize, AllocatorType::HEAP_ALLOC, nullptr); if (!ConvertYUV420ToRGBA(static_cast(buffer), bufferSize, false, false, errorCode)) { HiLog::Error(LABEL, "convert yuv420 to rgba issue"); errorCode = ERROR; return nullptr; } IMAGE_LOGD("[ImageSource]CreatePixelMapForYUV OUT"); return pixelMap; } } // namespace Media } // namespace OHOS