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