• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ext_decoder.h"
17 
18 #include <algorithm>
19 
20 #include "ext_pixel_convert.h"
21 #include "hilog/log.h"
22 #include "image_utils.h"
23 #include "log_tags.h"
24 #include "media_errors.h"
25 #include "securec.h"
26 #include "string_ex.h"
27 #if !defined(IOS_PLATFORM) && !defined(A_PLATFORM)
28 #include "surface_buffer.h"
29 #endif
30 
31 namespace {
32     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "ExtDecoder"};
33     constexpr static int32_t ZERO = 0;
34     constexpr static int32_t NUM_3 = 3;
35     constexpr static int32_t NUM_4 = 4;
36     constexpr static int32_t OFFSET = 1;
37     constexpr static size_t SIZE_ZERO = 0;
38     constexpr static uint32_t DEFAULT_SAMPLE_SIZE = 1;
39     constexpr static uint32_t NO_EXIF_TAG = 1;
40 }
41 
42 namespace OHOS {
43 namespace ImagePlugin {
44 using namespace Media;
45 using namespace OHOS::HiviewDFX;
46 using namespace std;
47 const static string CODEC_INITED_KEY = "CodecInited";
48 const static string ENCODED_FORMAT_KEY = "EncodedFormat";
49 const static string SUPPORT_SCALE_KEY = "SupportScale";
50 const static string SUPPORT_CROP_KEY = "SupportCrop";
51 const static string EXT_SHAREMEM_NAME = "EXT RawData";
52 const static string TAG_ORIENTATION_STRING = "Orientation";
53 const static string TAG_ORIENTATION_INT = "OrientationInt";
54 const static string GIF_IMAGE_DELAY_TIME = "GIFDelayTime";
55 
56 struct ColorTypeOutput {
57     PlPixelFormat outFormat;
58     SkColorType skFormat;
59 };
60 
61 static const map<PlPixelFormat, ColorTypeOutput> COLOR_TYPE_MAP = {
62     { PlPixelFormat::UNKNOWN, { PlPixelFormat::RGBA_8888, kRGBA_8888_SkColorType } },
63     { PlPixelFormat::RGBA_8888, { PlPixelFormat::RGBA_8888, kRGBA_8888_SkColorType } },
64     { PlPixelFormat::BGRA_8888, { PlPixelFormat::BGRA_8888, kBGRA_8888_SkColorType } },
65     { PlPixelFormat::ALPHA_8, { PlPixelFormat::ALPHA_8, kAlpha_8_SkColorType } },
66     { PlPixelFormat::RGB_565, { PlPixelFormat::RGB_565, kRGB_565_SkColorType } },
67     { PlPixelFormat::RGB_888, { PlPixelFormat::RGB_888, kRGB_888x_SkColorType } },
68 };
69 
70 static const map<PlAlphaType, SkAlphaType> ALPHA_TYPE_MAP = {
71     { PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE, kOpaque_SkAlphaType },
72     { PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL, kPremul_SkAlphaType },
73     { PlAlphaType::IMAGE_ALPHA_TYPE_UNPREMUL, kUnpremul_SkAlphaType },
74 };
75 
76 static const map<SkEncodedImageFormat, string> FORMAT_NAME = {
77     { SkEncodedImageFormat::kBMP, "image/bmp" },
78     { SkEncodedImageFormat::kGIF, "image/gif" },
79     { SkEncodedImageFormat::kICO, "image/png" },
80     { SkEncodedImageFormat::kJPEG, "image/jpeg" },
81     { SkEncodedImageFormat::kPNG, "image/png" },
82     { SkEncodedImageFormat::kWBMP, "image/bmp" },
83     { SkEncodedImageFormat::kWEBP, "image/webp" },
84     { SkEncodedImageFormat::kPKM, "" },
85     { SkEncodedImageFormat::kKTX, "" },
86     { SkEncodedImageFormat::kASTC, "" },
87     { SkEncodedImageFormat::kDNG, "" },
88     { SkEncodedImageFormat::kHEIF, "image/heif" },
89 };
90 
SetDecodeContextBuffer(DecodeContext & context,AllocatorType type,uint8_t * ptr,uint64_t count,void * fd)91 static void SetDecodeContextBuffer(DecodeContext &context,
92     AllocatorType type, uint8_t* ptr, uint64_t count, void* fd)
93 {
94     context.allocatorType = type;
95     context.freeFunc = nullptr;
96     context.pixelsBuffer.buffer = ptr;
97     context.pixelsBuffer.bufferSize = count;
98     context.pixelsBuffer.context = fd;
99 }
100 
ShareMemAlloc(DecodeContext & context,uint64_t count)101 static uint32_t ShareMemAlloc(DecodeContext &context, uint64_t count)
102 {
103 #if defined(_WIN32) || defined(_APPLE) || defined(A_PLATFORM) || defined(IOS_PLATFORM)
104     HiLog::Error(LABEL, "Unsupport share mem alloc");
105     return ERR_IMAGE_DATA_UNSUPPORT;
106 #else
107     auto fd = make_unique<int32_t>();
108     *fd = AshmemCreate(EXT_SHAREMEM_NAME.c_str(), count);
109     if (*fd < 0) {
110         HiLog::Error(LABEL, "AshmemCreate failed");
111         return ERR_SHAMEM_DATA_ABNORMAL;
112     }
113     int result = AshmemSetProt(*fd, PROT_READ | PROT_WRITE);
114     if (result < 0) {
115         ::close(*fd);
116         HiLog::Error(LABEL, "AshmemSetProt failed");
117         return ERR_SHAMEM_DATA_ABNORMAL;
118     }
119     void* ptr = ::mmap(nullptr, count, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, ZERO);
120     if (ptr == MAP_FAILED) {
121         ::close(*fd);
122         HiLog::Error(LABEL, "::mmap failed");
123         return ERR_SHAMEM_DATA_ABNORMAL;
124     }
125     SetDecodeContextBuffer(context,
126         AllocatorType::SHARE_MEM_ALLOC, static_cast<uint8_t*>(ptr), count, fd.release());
127     return SUCCESS;
128 #endif
129 }
130 
DmaMemAlloc(DecodeContext & context,uint64_t count,SkImageInfo & dstInfo)131 static uint32_t DmaMemAlloc(DecodeContext &context, uint64_t count, SkImageInfo &dstInfo)
132 {
133 #if defined(_WIN32) || defined(_APPLE) || defined(A_PLATFORM) || defined(IOS_PLATFORM)
134     HiLog::Error(LABEL, "Unsupport dma mem alloc");
135     return ERR_IMAGE_DATA_UNSUPPORT;
136 #else
137     sptr<SurfaceBuffer> sb = SurfaceBuffer::Create();
138     BufferRequestConfig requestConfig = {
139         .width = dstInfo.width(),
140         .height = dstInfo.height(),
141         .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
142         .format = GRAPHIC_PIXEL_FMT_RGBA_8888, // PixelFormat
143         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
144         .timeout = 0,
145         .colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB,
146         .transform = GraphicTransformType::GRAPHIC_ROTATE_NONE,
147     };
148     GSError ret = sb->Alloc(requestConfig);
149     if (ret != GSERROR_OK) {
150         HiLog::Error(LABEL, "SurfaceBuffer Alloc failed, %{public}s", GSErrorStr(ret).c_str());
151         return ERR_DMA_NOT_EXIST;
152     }
153     void* nativeBuffer = sb.GetRefPtr();
154     int32_t err = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
155     if (err != OHOS::GSERROR_OK) {
156         HiLog::Error(LABEL, "NativeBufferReference failed");
157         return ERR_DMA_DATA_ABNORMAL;
158     }
159 
160     SetDecodeContextBuffer(context,
161         AllocatorType::DMA_ALLOC, static_cast<uint8_t*>(sb->GetVirAddr()), count, nativeBuffer);
162     return SUCCESS;
163 #endif
164 }
165 
HeapMemAlloc(DecodeContext & context,uint64_t count)166 static uint32_t HeapMemAlloc(DecodeContext &context, uint64_t count)
167 {
168     if (count == 0 || count > PIXEL_MAP_MAX_RAM_SIZE) {
169         HiLog::Error(LABEL, "HeapMemAlloc Invalid value of bufferSize");
170         return ERR_IMAGE_DATA_ABNORMAL;
171     }
172     auto out = static_cast<uint8_t *>(malloc(count));
173 #ifdef _WIN32
174     if (memset_s(out, ZERO, count) != EOK) {
175 #else
176     if (memset_s(out, count, ZERO, count) != EOK) {
177 #endif
178         HiLog::Error(LABEL, "Decode failed, memset buffer failed");
179         free(out);
180         return ERR_IMAGE_DECODE_FAILED;
181     }
182     SetDecodeContextBuffer(context, AllocatorType::HEAP_ALLOC, out, count, nullptr);
183     return SUCCESS;
184 }
185 
186 ExtDecoder::ExtDecoder() : codec_(nullptr), frameCount_(ZERO)
187 {
188 }
189 
190 ExtDecoder::~ExtDecoder()
191 {
192     if (gifCache_ != nullptr) {
193         free(gifCache_);
194         gifCache_ = nullptr;
195     }
196 }
197 
198 void ExtDecoder::SetSource(InputDataStream &sourceStream)
199 {
200     stream_ = &sourceStream;
201     streamOff_ = sourceStream.Tell();
202     if (streamOff_ >= sourceStream.GetStreamSize()) {
203         streamOff_ = ZERO;
204     }
205 }
206 
207 void ExtDecoder::Reset()
208 {
209     stream_ = nullptr;
210     codec_ = nullptr;
211     dstInfo_.reset();
212     dstSubset_ = SkIRect::MakeEmpty();
213     info_.reset();
214 }
215 
216 static inline float Max(float a, float b)
217 {
218     return (a > b) ? a : b;
219 }
220 
221 bool ExtDecoder::GetScaledSize(int &dWidth, int &dHeight, float &scale)
222 {
223     if (info_.isEmpty() && !DecodeHeader()) {
224         return false;
225     }
226     float finalScale = scale;
227     if (scale == ZERO) {
228         finalScale = Max(static_cast<float>(dWidth)/info_.width(),
229             static_cast<float>(dHeight) / info_.height());
230     }
231     auto scaledDimension = codec_->getScaledDimensions(finalScale);
232     dWidth = scaledDimension.width();
233     dHeight = scaledDimension.height();
234     scale = finalScale;
235     HiLog::Debug(LABEL, "IsSupportScaleOnDecode info [%{public}d x %{public}d]", info_.width(), info_.height());
236     HiLog::Debug(LABEL, "IsSupportScaleOnDecode [%{public}d x %{public}d]", dWidth, dHeight);
237     HiLog::Debug(LABEL, "IsSupportScaleOnDecode [%{public}f]", scale);
238     return true;
239 }
240 
241 bool ExtDecoder::IsSupportScaleOnDecode()
242 {
243     constexpr float HALF_SCALE = 0.5f;
244     int w = ZERO;
245     int h = ZERO;
246     float scale = HALF_SCALE;
247     return GetScaledSize(w, h, scale);
248 }
249 
250 bool ExtDecoder::IsSupportCropOnDecode()
251 {
252     if (info_.isEmpty() && !DecodeHeader()) {
253         return false;
254     }
255     SkIRect innerRect = info_.bounds().makeInset(OFFSET, OFFSET);
256     return IsSupportCropOnDecode(innerRect);
257 }
258 
259 bool ExtDecoder::IsSupportCropOnDecode(SkIRect &target)
260 {
261     if (info_.isEmpty() && !DecodeHeader()) {
262         return false;
263     }
264     SkIRect orgbounds = info_.bounds();
265     SkIRect source = target;
266     if (orgbounds.contains(target) && codec_->getValidSubset(&target)) {
267         return source == target;
268     }
269     return false;
270 }
271 
272 bool ExtDecoder::HasProperty(string key)
273 {
274     if (CODEC_INITED_KEY.compare(key) == ZERO) {
275         return CheckCodec();
276     } else if (ENCODED_FORMAT_KEY.compare(key) == ZERO) {
277         return true;
278     } else if (SUPPORT_SCALE_KEY.compare(key) == ZERO) {
279         return IsSupportScaleOnDecode();
280     } else if (SUPPORT_CROP_KEY.compare(key) == ZERO) {
281         return IsSupportCropOnDecode();
282     }
283     return false;
284 }
285 
286 uint32_t ExtDecoder::GetImageSize(uint32_t index, PlSize &size)
287 {
288     HiLog::Debug(LABEL, "GetImageSize index:%{public}u", index);
289     if (!CheckIndexValied(index)) {
290         HiLog::Error(LABEL, "Invalid index:%{public}u, range:%{public}d", index, frameCount_);
291         return ERR_IMAGE_INVALID_PARAMETER;
292     }
293     HiLog::Error(LABEL, "GetImageSize index:%{public}u, range:%{public}d", index, frameCount_);
294     // Info has been get in check process, or empty on get failed.
295     if (info_.isEmpty()) {
296         HiLog::Error(LABEL, "GetImageSize failed, decode header failed.");
297         return ERR_IMAGE_DECODE_HEAD_ABNORMAL;
298     }
299     size.width = info_.width();
300     size.height = info_.height();
301     return SUCCESS;
302 }
303 
304 static inline bool IsLowDownScale(const PlSize &size, SkImageInfo &info)
305 {
306     return size.width <static_cast<uint32_t>(info.width()) &&
307         size.height <static_cast<uint32_t>(info.height());
308 }
309 
310 static inline bool IsValidCrop(const PlRect &crop, SkImageInfo &info, SkIRect &out)
311 {
312     out = SkIRect::MakeXYWH(crop.left, crop.top, crop.width, crop.height);
313     if (out.fLeft < ZERO || out.fTop < ZERO) {
314         return false;
315     }
316     if (out.fRight > info.width()) {
317         out.fRight = info.width();
318     }
319     if (out.fBottom > info.height()) {
320         out.fBottom = info.height();
321     }
322     return true;
323 }
324 
325 uint32_t ExtDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
326 {
327     if (!CheckIndexValied(index)) {
328         HiLog::Error(LABEL, "Invalid index:%{public}u, range:%{public}d", index, frameCount_);
329         return ERR_IMAGE_INVALID_PARAMETER;
330     }
331     if (opts.sampleSize != DEFAULT_SAMPLE_SIZE) {
332         HiLog::Error(LABEL, "Do not support sample size now!");
333         return ERR_IMAGE_INVALID_PARAMETER;
334     }
335     auto desireColor = ConvertToColorType(opts.desiredPixelFormat, info.pixelFormat);
336     auto desireAlpha = ConvertToAlphaType(opts.desireAlphaType, info.alphaType);
337     // SK only support low down scale
338     int dstWidth = opts.desiredSize.width;
339     int dstHeight = opts.desiredSize.height;
340     float scale = ZERO;
341     if (IsLowDownScale(opts.desiredSize, info_) && GetScaledSize(dstWidth, dstHeight, scale)) {
342         dstInfo_ = SkImageInfo::Make(dstWidth, dstHeight, desireColor, desireAlpha, info_.refColorSpace());
343     } else {
344         dstInfo_ = SkImageInfo::Make(info_.width(), info_.height(),
345             desireColor, desireAlpha, info_.refColorSpace());
346     }
347     if (ImageUtils::CheckMulOverflow(dstInfo_.width(), dstInfo_.height(), dstInfo_.bytesPerPixel())) {
348         HiLog::Error(LABEL, "SetDecodeOptions failed, width:%{public}d, height:%{public}d is too large",
349                      dstInfo_.width(), dstInfo_.height());
350         return ERR_IMAGE_INVALID_PARAMETER;
351     }
352     dstOptions_.fFrameIndex = index;
353 
354     if (!IsValidCrop(opts.CropRect, info_, dstSubset_)) {
355         HiLog::Error(LABEL,
356             "Invalid crop rect xy [%{public}d x %{public}d], wh [%{public}d x %{public}d]",
357             dstSubset_.left(), dstSubset_.top(), dstSubset_.width(), dstSubset_.height());
358         return ERR_IMAGE_INVALID_PARAMETER;
359     }
360     if (IsSupportCropOnDecode(dstSubset_)) {
361         dstOptions_.fSubset = &dstSubset_;
362     }
363 
364     info.size.width = dstInfo_.width();
365     info.size.height = dstInfo_.height();
366     return SUCCESS;
367 }
368 
369 uint32_t ExtDecoder::SetContextPixelsBuffer(uint64_t byteCount, DecodeContext &context)
370 {
371     if (byteCount == ZERO) {
372         return ERR_IMAGE_INVALID_PARAMETER;
373     }
374     if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
375         return ShareMemAlloc(context, byteCount);
376     } else if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
377         return DmaMemAlloc(context, byteCount, dstInfo_);
378     }
379     return HeapMemAlloc(context, byteCount);
380 }
381 
382 static void DebugInfo(SkImageInfo &info, SkImageInfo &dstInfo, SkCodec::Options &opts)
383 {
384     HiLog::Debug(LABEL, "Decode source info: WH[%{public}d x %{public}d], A %{public}d, C %{public}d.",
385         info.width(), info.height(),
386         info.alphaType(), info.colorType());
387     HiLog::Debug(LABEL, "Decode dst info: WH[%{public}d x %{public}d], A %{public}d, C %{public}d.",
388         dstInfo.width(), dstInfo.height(), dstInfo.alphaType(), dstInfo.colorType());
389     if (opts.fSubset != nullptr) {
390         HiLog::Debug(LABEL, "Decode dstOpts sub: (%{public}d, %{public}d), WH[%{public}d x %{public}d]",
391             opts.fSubset->fLeft, opts.fSubset->fTop,
392             opts.fSubset->width(), opts.fSubset->height());
393     }
394 }
395 
396 static uint32_t RGBxToRGB(uint8_t* srcBuffer, size_t srsSize,
397     uint8_t* dstBuffer, size_t dstSize, size_t pixelCount)
398 {
399     ExtPixels src = {srcBuffer, srsSize, pixelCount};
400     ExtPixels dst = {dstBuffer, dstSize, pixelCount};
401     auto res = ExtPixelConvert::RGBxToRGB(src, dst);
402     if (res != SUCCESS) {
403         HiLog::Error(LABEL, "RGBxToRGB failed %{public}d", res);
404     }
405     return res;
406 }
407 
408 uint32_t ExtDecoder::PreDecodeCheck(uint32_t index)
409 {
410     if (!CheckIndexValied(index)) {
411         HiLog::Error(LABEL, "Decode failed, invalid index:%{public}u, range:%{public}d", index, frameCount_);
412         return ERR_IMAGE_INVALID_PARAMETER;
413     }
414     if (codec_ == nullptr) {
415         HiLog::Error(LABEL, "Decode failed, codec is null");
416         return ERR_IMAGE_DECODE_FAILED;
417     }
418     if (dstInfo_.isEmpty()) {
419         HiLog::Error(LABEL, "Decode failed, dst info is empty");
420         return ERR_IMAGE_DECODE_FAILED;
421     }
422         return SUCCESS;
423 }
424 
425 bool ExtDecoder::ResetCodec()
426 {
427     codec_ = nullptr;
428     stream_->Seek(streamOff_);
429     return ExtDecoder::CheckCodec();
430 }
431 
432 uint32_t ExtDecoder::Decode(uint32_t index, DecodeContext &context)
433 {
434     uint32_t res = PreDecodeCheck(index);
435     if (res != SUCCESS) {
436         return res;
437     }
438     uint64_t byteCount = static_cast<uint64_t>(dstInfo_.computeMinByteSize());
439     uint8_t *dstBuffer = nullptr;
440     if (dstInfo_.colorType() == SkColorType::kRGB_888x_SkColorType) {
441         auto tmpBuffer = make_unique<uint8_t[]>(byteCount);
442         dstBuffer = tmpBuffer.get();
443         byteCount = byteCount / NUM_4 * NUM_3;
444     }
445     if (context.pixelsBuffer.buffer == nullptr) {
446         HiLog::Debug(LABEL, "Decode alloc byte count.");
447         res = SetContextPixelsBuffer(byteCount, context);
448         if (res != SUCCESS) {
449             return res;
450         }
451         if (dstBuffer == nullptr) {
452             dstBuffer = static_cast<uint8_t *>(context.pixelsBuffer.buffer);
453         }
454     }
455     dstOptions_.fFrameIndex = index;
456     DebugInfo(info_, dstInfo_, dstOptions_);
457     uint64_t rowStride = dstInfo_.minRowBytes64();
458     if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
459         SurfaceBuffer* sbBuffer = reinterpret_cast<SurfaceBuffer*> (context.pixelsBuffer.context);
460         rowStride = sbBuffer->GetStride();
461     }
462     if (codec_->getEncodedFormat() == SkEncodedImageFormat::kGIF) {
463         return GifDecode(index, context, rowStride);
464     }
465     SkCodec::Result ret = codec_->getPixels(dstInfo_, dstBuffer, rowStride, &dstOptions_);
466     if (ret != SkCodec::kSuccess && ResetCodec()) {
467         // Try again
468         ret = codec_->getPixels(dstInfo_, dstBuffer, rowStride, &dstOptions_);
469     }
470     if (ret != SkCodec::kSuccess) {
471         HiLog::Error(LABEL, "Decode failed, get pixels failed, ret=%{public}d", ret);
472         return ERR_IMAGE_DECODE_ABNORMAL;
473     }
474     if (dstInfo_.colorType() == SkColorType::kRGB_888x_SkColorType) {
475         return RGBxToRGB(dstBuffer, dstInfo_.computeMinByteSize(),
476             static_cast<uint8_t*>(context.pixelsBuffer.buffer),
477             byteCount, dstInfo_.width() * dstInfo_.height());
478     }
479     return SUCCESS;
480 }
481 
482 uint32_t ExtDecoder::GifDecode(uint32_t index, DecodeContext &context, const uint64_t rowStride)
483 {
484     int dstHeight = dstInfo_.height();
485     int rowBytes = dstInfo_.minRowBytes64();
486     uint64_t byteCount = rowStride * dstHeight;
487     SkCodec::FrameInfo info {};
488     codec_->getFrameInfo(index, &info);
489     if (info.fRequiredFrame != SkCodec::kNoFrame && index == gifCacheIndex_ + 1 && gifCache_ != nullptr) {
490         // frame requires a previous frame as background layer
491         dstOptions_.fPriorFrame = info.fRequiredFrame;
492     } else {
493         dstOptions_.fPriorFrame = SkCodec::kNoFrame;
494     }
495     if (gifCache_ == nullptr) {
496         HiLog::Debug(LABEL, "malloc Gif cacahe memory");
497         gifCache_ = static_cast<uint8_t *>(calloc(byteCount, 1));
498     }
499     SkCodec::Result ret = codec_->getPixels(dstInfo_, gifCache_, rowStride, &dstOptions_);
500     if (ret != SkCodec::kSuccess && ResetCodec()) {
501         // Try again
502         ret = codec_->getPixels(dstInfo_, gifCache_, rowStride, &dstOptions_);
503     }
504     if (ret == SkCodec::kSuccess) {
505         gifCacheIndex_ = index;
506     }
507     for (int i = 0; i < dstHeight; i++) {
508         uint8_t* srcRow = gifCache_ + i * rowStride;
509         uint8_t* dstRow = static_cast<uint8_t *>(context.pixelsBuffer.buffer) + i * rowStride;
510         errno_t err = memcpy_s(dstRow, rowBytes, srcRow, rowBytes);
511         if (err != EOK) {
512             HiLog::Error(LABEL, "memcpy failed. errno:%{public}d", err);
513             return ERR_IMAGE_DECODE_ABNORMAL;
514         }
515     }
516 
517     if (ret != SkCodec::kSuccess) {
518         HiLog::Error(LABEL, "Gif decode failed, get pixels failed, ret=%{public}d", ret);
519         return ERR_IMAGE_DECODE_ABNORMAL;
520     }
521     return SUCCESS;
522 }
523 
524 uint32_t ExtDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
525 {
526     // currently not support increment decode
527     return ERR_IMAGE_DATA_UNSUPPORT;
528 }
529 
530 bool ExtDecoder::CheckCodec()
531 {
532     if (codec_ != nullptr) {
533         return true;
534     } else if (stream_ == nullptr) {
535         HiLog::Error(LABEL, "create codec: input stream is nullptr.");
536         return false;
537     } else if (stream_->GetStreamSize() == SIZE_ZERO) {
538         HiLog::Error(LABEL, "create codec: input stream size is zero.");
539         return false;
540     }
541     codec_ = SkCodec::MakeFromStream(make_unique<ExtStream>(stream_));
542     if (codec_ == nullptr) {
543         HiLog::Error(LABEL, "create codec from stream failed");
544         return false;
545     }
546     return codec_ != nullptr;
547 }
548 
549 bool ExtDecoder::DecodeHeader()
550 {
551     if (!CheckCodec()) {
552         HiLog::Error(LABEL, "Check codec failed");
553         return false;
554     }
555     info_ = codec_->getInfo();
556     frameCount_ = codec_->getFrameCount();
557     HiLog::Debug(LABEL, "DecodeHeader: get frame count %{public}d.", frameCount_);
558     return true;
559 }
560 
561 bool ExtDecoder::CheckIndexValied(uint32_t index)
562 {
563     if (frameCount_ == ZERO && !DecodeHeader()) {
564         return false;
565     }
566     return static_cast<int32_t>(index) >= ZERO && static_cast<int32_t>(index) < frameCount_;
567 }
568 
569 static uint32_t GetFormatName(SkEncodedImageFormat format, std::string &name)
570 {
571     auto formatNameIter = FORMAT_NAME.find(format);
572     if (formatNameIter != FORMAT_NAME.end() && !formatNameIter->second.empty()) {
573         name = formatNameIter->second;
574         HiLog::Debug(LABEL, "GetFormatName: get encoded format name (%{public}d)=>[%{public}s].",
575             format, name.c_str());
576         return SUCCESS;
577     }
578     HiLog::Error(LABEL, "GetFormatName: get encoded format name failed %{public}d.", format);
579     return ERR_IMAGE_DATA_UNSUPPORT;
580 }
581 
582 bool ExtDecoder::ConvertInfoToAlphaType(SkAlphaType &alphaType, PlAlphaType &outputType)
583 {
584     if (info_.isEmpty()) {
585         return false;
586     }
587     alphaType = info_.alphaType();
588     auto findItem = std::find_if(ALPHA_TYPE_MAP.begin(), ALPHA_TYPE_MAP.end(),
589         [alphaType](const map<PlAlphaType, SkAlphaType>::value_type item) {
590         return item.second == alphaType;
591     });
592     if (findItem == ALPHA_TYPE_MAP.end()) {
593         return false;
594     }
595     outputType = findItem->first;
596     alphaType = findItem->second;
597     return true;
598 }
599 
600 bool ExtDecoder::ConvertInfoToColorType(SkColorType &format, PlPixelFormat &outputFormat)
601 {
602     if (info_.isEmpty()) {
603         return false;
604     }
605     auto colorType = info_.colorType();
606     auto findItem = std::find_if(COLOR_TYPE_MAP.begin(), COLOR_TYPE_MAP.end(),
607         [colorType](const map<PlPixelFormat, ColorTypeOutput>::value_type item) {
608         return item.second.skFormat == colorType;
609     });
610     if (findItem == COLOR_TYPE_MAP.end()) {
611         return false;
612     }
613     format = findItem->second.skFormat;
614     outputFormat = findItem->second.outFormat;
615     return true;
616 }
617 
618 SkAlphaType ExtDecoder::ConvertToAlphaType(PlAlphaType desiredType, PlAlphaType &outputType)
619 {
620     if (desiredType != PlAlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) {
621         auto alphaType = ALPHA_TYPE_MAP.find(desiredType);
622         if (alphaType != ALPHA_TYPE_MAP.end()) {
623             outputType = alphaType->first;
624             return alphaType->second;
625         }
626     }
627     HiLog::Debug(LABEL, "Unknown alpha type:%{public}d", desiredType);
628     SkAlphaType res;
629     if (ConvertInfoToAlphaType(res, outputType)) {
630         HiLog::Debug(LABEL, "Using alpha type:%{public}d", outputType);
631         return res;
632     }
633     HiLog::Debug(LABEL, "Using default alpha type:%{public}d", PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL);
634     outputType = PlAlphaType::IMAGE_ALPHA_TYPE_PREMUL;
635     return SkAlphaType::kPremul_SkAlphaType;
636 }
637 
638 SkColorType ExtDecoder::ConvertToColorType(PlPixelFormat format, PlPixelFormat &outputFormat)
639 {
640     if (format != PlPixelFormat::UNKNOWN) {
641         auto colorType = COLOR_TYPE_MAP.find(format);
642         if (colorType != COLOR_TYPE_MAP.end()) {
643             outputFormat = colorType->second.outFormat;
644             return colorType->second.skFormat;
645         }
646     }
647     HiLog::Debug(LABEL, "Unknown pixel format:%{public}d", format);
648     SkColorType res;
649     if (ConvertInfoToColorType(res, outputFormat)) {
650         HiLog::Debug(LABEL, "Using pixel format:%{public}d", outputFormat);
651         return res;
652     }
653     HiLog::Debug(LABEL, "Using default pixel format:%{public}d", PlPixelFormat::RGBA_8888);
654     outputFormat = PlPixelFormat::RGBA_8888;
655     return kRGBA_8888_SkColorType;
656 }
657 
658 #ifdef IMAGE_COLORSPACE_FLAG
659 OHOS::ColorManager::ColorSpace ExtDecoder::getGrColorSpace()
660 {
661     return OHOS::ColorManager::ColorSpace(info_.refColorSpace());
662 }
663 
664 bool ExtDecoder::IsSupportICCProfile()
665 {
666     if (info_.isEmpty()) {
667         return false;
668     }
669     return info_.refColorSpace() != nullptr;
670 }
671 #endif
672 
673 static uint32_t ProcessWithStreamData(InputDataStream *input,
674     std::function<uint32_t(uint8_t*, size_t)> process)
675 {
676     size_t inputSize = input->GetStreamSize();
677     if (inputSize == SIZE_ZERO) {
678         return Media::ERR_MEDIA_INVALID_VALUE;
679     }
680 
681     if (input->GetDataPtr() == nullptr) {
682         auto tmpBuffer = std::make_unique<uint8_t[]>(inputSize);
683         auto savePos = input->Tell();
684         input->Seek(SIZE_ZERO);
685         uint32_t readSize = 0;
686         input->Read(inputSize, tmpBuffer.get(), inputSize, readSize);
687         input->Seek(savePos);
688         return process(tmpBuffer.get(), inputSize);
689     }
690     return process(input->GetDataPtr(), inputSize);
691 }
692 
693 static bool ParseExifData(InputDataStream *input, EXIFInfo &info)
694 {
695     if (info.IsExifDataParsed()) {
696         return true;
697     }
698     HiLog::Debug(LABEL, "ParseExifData enter");
699     auto code = ProcessWithStreamData(input, [&info](uint8_t* buffer, size_t size) {
700         return info.ParseExifData(buffer, size);
701     });
702     if (code != SUCCESS) {
703         HiLog::Error(LABEL, "Error parsing EXIF: code %{public}d", code);
704     }
705     return code == SUCCESS;
706 }
707 
708 bool ExtDecoder::GetPropertyCheck(uint32_t index, const std::string &key, uint32_t &res)
709 {
710     if (IsSameTextStr(key, ACTUAL_IMAGE_ENCODED_FORMAT)) {
711         res = Media::ERR_MEDIA_VALUE_INVALID;
712         return false;
713     }
714     if (!CheckIndexValied(index)) {
715         res = Media::ERR_IMAGE_DECODE_HEAD_ABNORMAL;
716         return false;
717     }
718     SkEncodedImageFormat format = codec_->getEncodedFormat();
719     if (format != SkEncodedImageFormat::kJPEG) {
720         res = Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
721         return true;
722     }
723     auto result = ParseExifData(stream_, exifInfo_);
724     if (!result) {
725         res = Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
726     }
727     return result;
728 }
729 
730 static uint32_t GetDelayTime(SkCodec * codec, uint32_t index, int32_t &value)
731 {
732     if (codec->getEncodedFormat() != SkEncodedImageFormat::kGIF) {
733         HiLog::Error(LABEL, "[GetDelayTime] Should not get delay time in %{public}d", codec->getEncodedFormat());
734         return ERR_MEDIA_INVALID_PARAM;
735     }
736     auto frameInfos = codec->getFrameInfo();
737     if (index > frameInfos.size() - 1) {
738         HiLog::Error(LABEL, "[GetDelayTime] frame size %{public}zu, index:%{public}d", frameInfos.size(), index);
739         return ERR_MEDIA_INVALID_PARAM;
740     }
741     value = frameInfos[index].fDuration;
742     HiLog::Debug(LABEL, "[GetDelayTime] index[%{public}d]:%{public}d", index, value);
743     return SUCCESS;
744 }
745 
746 uint32_t ExtDecoder::GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value)
747 {
748     HiLog::Debug(LABEL, "[GetImagePropertyInt] enter ExtDecoder plugin, key:%{public}s", key.c_str());
749     uint32_t res = Media::ERR_IMAGE_DATA_ABNORMAL;
750     if (!GetPropertyCheck(index, key, res)) {
751         return res;
752     }
753     if (GIF_IMAGE_DELAY_TIME.compare(key) == ZERO) {
754         return GetDelayTime(codec_.get(), index, value);
755     }
756     // There can add some not need exif property
757     if (res == Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT) {
758         return res;
759     }
760     // Need exif property following
761     if (IsSameTextStr(key, TAG_ORIENTATION_STRING)) {
762         std::string strValue;
763         res = exifInfo_.GetExifData(TAG_ORIENTATION_INT, strValue);
764         if (res != SUCCESS) {
765             return res;
766         }
767         value = atoi(strValue.c_str());
768         return value;
769     }
770     HiLog::Error(LABEL, "[GetImagePropertyInt] The key:%{public}s is not supported int32_t", key.c_str());
771     return Media::ERR_MEDIA_VALUE_INVALID;
772 }
773 
774 uint32_t ExtDecoder::GetImagePropertyString(uint32_t index, const std::string &key, std::string &value)
775 {
776     HiLog::Debug(LABEL, "[GetImagePropertyString] enter jpeg plugin, key:%{public}s", key.c_str());
777     uint32_t res = Media::ERR_IMAGE_DATA_ABNORMAL;
778     if (!GetPropertyCheck(index, key, res)) {
779         return res;
780     }
781     // There can add some not need exif property
782     if (ENCODED_FORMAT_KEY.compare(key) == ZERO) {
783         SkEncodedImageFormat format = codec_->getEncodedFormat();
784         return GetFormatName(format, value);
785     } else if (GIF_IMAGE_DELAY_TIME.compare(key) == ZERO) {
786         int delayTime = ZERO;
787         res = GetDelayTime(codec_.get(), index, delayTime);
788         value = std::to_string(delayTime);
789         return res;
790     }
791     if (res == Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT) {
792         return res;
793     }
794     // Need exif property following
795     res = exifInfo_.GetExifData(key, value);
796     HiLog::Debug(LABEL, "[GetImagePropertyString] enter jpeg plugin, value:%{public}s", value.c_str());
797     return res;
798 }
799 
800 uint32_t ExtDecoder::ModifyImageProperty(uint32_t index, const std::string &key,
801     const std::string &value, const std::string &path)
802 {
803     HiLog::Debug(LABEL, "[ModifyImageProperty] with path:%{public}s, key:%{public}s, value:%{public}s",
804         path.c_str(), key.c_str(), value.c_str());
805     return exifInfo_.ModifyExifData(key, value, path);
806 }
807 
808 uint32_t ExtDecoder::ModifyImageProperty(uint32_t index, const std::string &key,
809     const std::string &value, const int fd)
810 {
811     HiLog::Debug(LABEL, "[ModifyImageProperty] with fd:%{public}d, key:%{public}s, value:%{public}s",
812         fd, key.c_str(), value.c_str());
813     return exifInfo_.ModifyExifData(key, value, fd);
814 }
815 
816 uint32_t ExtDecoder::ModifyImageProperty(uint32_t index, const std::string &key,
817     const std::string &value, uint8_t *data, uint32_t size)
818 {
819     HiLog::Debug(LABEL, "[ModifyImageProperty] with key:%{public}s, value:%{public}s",
820         key.c_str(), value.c_str());
821     return exifInfo_.ModifyExifData(key, value, data, size);
822 }
823 
824 uint32_t ExtDecoder::GetFilterArea(const int &privacyType, std::vector<std::pair<uint32_t, uint32_t>> &ranges)
825 {
826     HiLog::Debug(LABEL, "[GetFilterArea] with privacyType:%{public}d ", privacyType);
827     if (!CheckCodec()) {
828         HiLog::Error(LABEL, "Check codec failed");
829         return NO_EXIF_TAG;
830     }
831     SkEncodedImageFormat format = codec_->getEncodedFormat();
832     if (format != SkEncodedImageFormat::kJPEG) {
833         return NO_EXIF_TAG;
834     }
835     constexpr size_t APP1_SIZE_H_OFF = 4;
836     constexpr size_t APP1_SIZE_L_OFF = 5;
837     constexpr size_t U8_SHIFT = 8;
838     return ProcessWithStreamData(stream_, [this, &privacyType, &ranges](uint8_t* buffer, size_t size) {
839         size_t appSize = (static_cast<size_t>(buffer[APP1_SIZE_H_OFF]) << U8_SHIFT) | buffer[APP1_SIZE_L_OFF];
840         HiLog::Debug(LABEL, "[GetFilterArea]: get app1 area size");
841         appSize += APP1_SIZE_H_OFF;
842         auto ret = exifInfo_.GetFilterArea(buffer, (appSize < size) ? appSize : size, privacyType, ranges);
843         if (ret != Media::SUCCESS) {
844             HiLog::Error(LABEL, "[GetFilterArea]: failed to get area %{public}d", ret);
845         }
846         return ret;
847     });
848 }
849 
850 uint32_t ExtDecoder::GetTopLevelImageNum(uint32_t &num)
851 {
852     if (!CheckIndexValied(SIZE_ZERO) && frameCount_ <= ZERO) {
853         return ERR_IMAGE_DECODE_HEAD_ABNORMAL;
854     }
855     num = frameCount_;
856     return SUCCESS;
857 }
858 } // namespace ImagePlugin
859 } // namespace OHOS
860