1 /*
2  * Copyright (C) 2021 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 "image_utils.h"
17 
18 #include <sys/stat.h>
19 #include <cerrno>
20 #include <climits>
21 #include <cmath>
22 #include <cstdint>
23 #include <cstdlib>
24 #include <string>
25 #include <fstream>
26 #include <sstream>
27 #include <chrono>
28 
29 #include "__config"
30 #include "image_log.h"
31 #include "ios"
32 #include "istream"
33 #include "media_errors.h"
34 #include "new"
35 #include "plugin_server.h"
36 #include "singleton.h"
37 #include "string"
38 #include "type_traits"
39 #include "vector"
40 #include "image_trace.h"
41 #include "hitrace_meter.h"
42 #include "image_system_properties.h"
43 #include "image/abs_image_decoder.h"
44 #include "pixel_map.h"
45 #ifdef IOS_PLATFORM
46 #include <sys/syscall.h>
47 #endif
48 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
49 #include "surface_buffer.h"
50 #else
51 #include "refbase.h"
52 #endif
53 
54 #undef LOG_DOMAIN
55 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
56 
57 #undef LOG_TAG
58 #define LOG_TAG "imageUtils"
59 
60 namespace OHOS {
61 namespace Media {
62 using namespace std;
63 using namespace MultimediaPlugin;
64 
65 constexpr int32_t ALPHA8_BYTES = 1;
66 constexpr int32_t RGB565_BYTES = 2;
67 constexpr int32_t RGB888_BYTES = 3;
68 constexpr int32_t ARGB8888_BYTES = 4;
69 constexpr int32_t RGBA_F16_BYTES = 8;
70 constexpr int32_t NV21_BYTES = 2;  // Each pixel is sorted on 3/2 bytes.
71 constexpr uint8_t MOVE_BITS_8 = 8;
72 constexpr uint8_t MOVE_BITS_16 = 16;
73 constexpr uint8_t MOVE_BITS_24 = 24;
74 constexpr int32_t NV21P010_BYTES = 3;
75 constexpr int32_t ASTC_4X4_BYTES = 1;
76 constexpr int32_t ASTC_4X4_BLOCK = 4;
77 constexpr int32_t ASTC_6X6_BLOCK = 6;
78 constexpr int32_t ASTC_8X8_BLOCK = 8;
79 constexpr int32_t ASTC_BLOCK_SIZE = 16;
80 constexpr int32_t ASTC_HEADER_SIZE = 16;
81 constexpr uint8_t FILL_NUMBER = 3;
82 constexpr uint8_t ALIGN_NUMBER = 4;
83 constexpr int32_t DMA_SIZE = 512 * 512; // DMA minimum effective size
84 constexpr float EPSILON = 1e-6;
85 constexpr int MAX_DIMENSION = INT32_MAX >> 2;
86 static bool g_pluginRegistered = false;
87 static const uint8_t NUM_0 = 0;
88 static const uint8_t NUM_1 = 1;
89 static const uint8_t NUM_2 = 2;
90 static const uint8_t NUM_3 = 3;
91 static const uint8_t NUM_4 = 4;
92 static const uint8_t NUM_5 = 5;
93 static const uint8_t NUM_6 = 6;
94 static const uint8_t NUM_7 = 7;
95 static const uint8_t INT_255 = 255;
96 static const string FILE_DIR_IN_THE_SANDBOX = "/data/storage/el2/base/files/";
97 
GetFileSize(const string &pathName, size_t &size)98 bool ImageUtils::GetFileSize(const string &pathName, size_t &size)
99 {
100     if (pathName.empty()) {
101         IMAGE_LOGE("[ImageUtil]input parameter exception.");
102         return false;
103     }
104     struct stat statbuf;
105     int ret = stat(pathName.c_str(), &statbuf);
106     if (ret != 0) {
107         IMAGE_LOGE("[ImageUtil]get the file size failed, ret:%{public}d, errno:%{public}d.", ret, errno);
108         return false;
109     }
110     size = statbuf.st_size;
111     return true;
112 }
113 
GetFileSize(const int fd, size_t &size)114 bool ImageUtils::GetFileSize(const int fd, size_t &size)
115 {
116     struct stat statbuf;
117 
118     if (fd < 0) {
119         return false;
120     }
121 
122     int ret = fstat(fd, &statbuf);
123     if (ret != 0) {
124         IMAGE_LOGE("[ImageUtil]get the file size failed, ret:%{public}d, errno:%{public}d.", ret, errno);
125         return false;
126     }
127     size = statbuf.st_size;
128     return true;
129 }
130 
GetInputStreamSize(istream &inputStream, size_t &size)131 bool ImageUtils::GetInputStreamSize(istream &inputStream, size_t &size)
132 {
133     if (inputStream.rdbuf() == nullptr) {
134         IMAGE_LOGE("[ImageUtil]input parameter exception.");
135         return false;
136     }
137     size_t original = inputStream.tellg();
138     inputStream.seekg(0, ios_base::end);
139     size = inputStream.tellg();
140     inputStream.seekg(original);
141     return true;
142 }
143 
GetPixelBytes(const PixelFormat &pixelFormat)144 int32_t ImageUtils::GetPixelBytes(const PixelFormat &pixelFormat)
145 {
146     int pixelBytes = 0;
147     switch (pixelFormat) {
148         case PixelFormat::ARGB_8888:
149         case PixelFormat::BGRA_8888:
150         case PixelFormat::RGBA_8888:
151         case PixelFormat::RGBA_1010102:
152         case PixelFormat::CMYK:
153             pixelBytes = ARGB8888_BYTES;
154             break;
155         case PixelFormat::ALPHA_8:
156             pixelBytes = ALPHA8_BYTES;
157             break;
158         case PixelFormat::RGB_888:
159             pixelBytes = RGB888_BYTES;
160             break;
161         case PixelFormat::RGB_565:
162             pixelBytes = RGB565_BYTES;
163             break;
164         case PixelFormat::RGBA_F16:
165         case PixelFormat::RGBA_U16:
166             pixelBytes = RGBA_F16_BYTES;
167             break;
168         case PixelFormat::NV21:
169         case PixelFormat::NV12:
170             pixelBytes = NV21_BYTES;  // perl pixel 1.5 Bytes but return int so return 2
171             break;
172         case PixelFormat::ASTC_4x4:
173         case PixelFormat::ASTC_6x6:
174         case PixelFormat::ASTC_8x8:
175             pixelBytes = ASTC_4X4_BYTES;
176             break;
177         case PixelFormat::YCBCR_P010:
178         case PixelFormat::YCRCB_P010:
179             pixelBytes = NV21P010_BYTES;
180             break;
181         default:
182             IMAGE_LOGE("[ImageUtil]get pixel bytes failed, pixelFormat:%{public}d.",
183                 static_cast<int32_t>(pixelFormat));
184             break;
185     }
186     return pixelBytes;
187 }
188 
GetRowDataSizeByPixelFormat(int32_t width, PixelFormat format)189 int32_t ImageUtils::GetRowDataSizeByPixelFormat(int32_t width, PixelFormat format)
190 {
191     uint64_t uWidth = static_cast<uint64_t>(width);
192     uint64_t pixelBytes = static_cast<uint64_t>(GetPixelBytes(format));
193     uint64_t rowDataSize = 0;
194     switch (format) {
195         case PixelFormat::ALPHA_8:
196             rowDataSize = pixelBytes * ((uWidth + FILL_NUMBER) / ALIGN_NUMBER * ALIGN_NUMBER);
197             break;
198         case PixelFormat::ASTC_4x4:
199             rowDataSize = pixelBytes * (((uWidth + NUM_3) >> NUM_2) << NUM_2);
200             break;
201         case PixelFormat::ASTC_6x6:
202             rowDataSize = pixelBytes * (((uWidth + NUM_5) / NUM_6) * NUM_6);
203             break;
204         case PixelFormat::ASTC_8x8:
205             rowDataSize = pixelBytes * (((uWidth + NUM_7) >> NUM_3) << NUM_3);
206             break;
207         default:
208             rowDataSize = pixelBytes * uWidth;
209     }
210     if (rowDataSize > INT_MAX) {
211         IMAGE_LOGE("GetRowDataSizeByPixelFormat failed: rowDataSize overflowed");
212         return 0;
213     }
214     return static_cast<int32_t>(rowDataSize);
215 }
216 
RegisterPluginServer()217 uint32_t ImageUtils::RegisterPluginServer()
218 {
219 #ifdef _WIN32
220     vector<string> pluginPaths = { "" };
221 #elif defined(_APPLE)
222     vector<string> pluginPaths = { "./" };
223 #elif defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
224     vector<string> pluginPaths = {};
225 #else
226     vector<string> pluginPaths = { "/system/etc/multimediaplugin/image" };
227 #endif
228     PluginServer &pluginServer = DelayedRefSingleton<PluginServer>::GetInstance();
229     uint32_t result = pluginServer.Register(std::move(pluginPaths));
230     if (result != SUCCESS) {
231         IMAGE_LOGE("[ImageUtil]failed to register plugin server, ERRNO: %{public}u.", result);
232     } else {
233         g_pluginRegistered = true;
234         IMAGE_LOGD("[ImageUtil]success to register plugin server");
235     }
236     return result;
237 }
238 
GetPluginServer()239 PluginServer& ImageUtils::GetPluginServer()
240 {
241     if (!g_pluginRegistered) {
242         uint32_t result = RegisterPluginServer();
243         if (result != SUCCESS) {
244             IMAGE_LOGI("[ImageUtil]failed to register plugin server, ERRNO: %{public}u.", result);
245         }
246     }
247     return DelayedRefSingleton<PluginServer>::GetInstance();
248 }
249 
PathToRealPath(const string &path, string &realPath)250 bool ImageUtils::PathToRealPath(const string &path, string &realPath)
251 {
252     if (path.empty()) {
253         IMAGE_LOGE("path is empty!");
254         return false;
255     }
256 
257     if ((path.length() >= PATH_MAX)) {
258         IMAGE_LOGE("path len is error, the len is: [%{public}lu]", static_cast<unsigned long>(path.length()));
259         return false;
260     }
261 
262     char tmpPath[PATH_MAX] = { 0 };
263 
264 #ifdef _WIN32
265     if (_fullpath(tmpPath, path.c_str(), path.length()) == nullptr) {
266         IMAGE_LOGW("path to _fullpath error");
267     }
268 #else
269     if (realpath(path.c_str(), tmpPath) == nullptr) {
270         IMAGE_LOGE("path to realpath is nullptr");
271         return false;
272     }
273 #endif
274 
275     realPath = tmpPath;
276     return true;
277 }
278 
FloatCompareZero(float src)279 bool ImageUtils::FloatCompareZero(float src)
280 {
281     return fabs(src - 0) < EPSILON;
282 }
283 
GetValidAlphaTypeByFormat(const AlphaType &dstType, const PixelFormat &format)284 AlphaType ImageUtils::GetValidAlphaTypeByFormat(const AlphaType &dstType, const PixelFormat &format)
285 {
286     switch (format) {
287         case PixelFormat::RGBA_8888:
288         case PixelFormat::BGRA_8888:
289         case PixelFormat::ARGB_8888:
290         case PixelFormat::RGBA_1010102:
291         case PixelFormat::RGBA_F16: {
292             break;
293         }
294         case PixelFormat::ALPHA_8: {
295             if (dstType != AlphaType::IMAGE_ALPHA_TYPE_PREMUL) {
296                 return AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
297             }
298             break;
299         }
300         case PixelFormat::RGB_888:
301         case PixelFormat::RGB_565: {
302             if (dstType != AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) {
303                 return AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
304             }
305             break;
306         }
307         case PixelFormat::NV21:
308         case PixelFormat::NV12:
309         case PixelFormat::YCBCR_P010:
310         case PixelFormat::YCRCB_P010: {
311             if (dstType != AlphaType::IMAGE_ALPHA_TYPE_PREMUL) {
312                 return AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
313             }
314             break;
315         }
316         case PixelFormat::CMYK:
317         default: {
318             IMAGE_LOGE("GetValidAlphaTypeByFormat unsupport the format(%{public}d).", format);
319             return AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
320         }
321     }
322     return dstType;
323 }
324 
GetPixelMapAllocatorType(const Size &size, const PixelFormat &format, bool preferDma)325 AllocatorType ImageUtils::GetPixelMapAllocatorType(const Size &size, const PixelFormat &format, bool preferDma)
326 {
327 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
328     return IsSizeSupportDma(size) && (preferDma || (IsWidthAligned(size.width) && IsFormatSupportDma(format))) &&
329         (format == PixelFormat::RGBA_8888 || Is10Bit(format)) ?
330         AllocatorType::DMA_ALLOC : AllocatorType::SHARE_MEM_ALLOC;
331 #else
332     return AllocatorType::HEAP_ALLOC;
333 #endif
334 }
335 
IsValidImageInfo(const ImageInfo &info)336 bool ImageUtils::IsValidImageInfo(const ImageInfo &info)
337 {
338     if (info.size.width <= 0 || info.size.height <= 0 || info.size.width > MAX_DIMENSION ||
339         info.size.height > MAX_DIMENSION) {
340         IMAGE_LOGE("width(%{public}d) or height(%{public}d) is invalid.", info.size.width, info.size.height);
341         return false;
342     }
343     if (info.pixelFormat == PixelFormat::UNKNOWN || info.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) {
344         IMAGE_LOGE("check pixelformat and alphatype is invalid.");
345         return false;
346     }
347     return true;
348 }
349 
IsWidthAligned(const int32_t &width)350 bool ImageUtils::IsWidthAligned(const int32_t &width)
351 {
352     return ((static_cast<uint32_t>(width) * NUM_4) & INT_255) == 0;
353 }
354 
IsSizeSupportDma(const Size &size)355 bool ImageUtils::IsSizeSupportDma(const Size &size)
356 {
357     // Check for overflow risk
358     if (size.width > 0 && size.height > INT_MAX / size.width) {
359         return false;
360     }
361     return size.width * size.height >= DMA_SIZE;
362 }
363 
IsFormatSupportDma(const PixelFormat &format)364 bool ImageUtils::IsFormatSupportDma(const PixelFormat &format)
365 {
366     return format == PixelFormat::UNKNOWN || format == PixelFormat::RGBA_8888;
367 }
368 
Is10Bit(const PixelFormat &format)369 bool ImageUtils::Is10Bit(const PixelFormat &format)
370 {
371     return format == PixelFormat::RGBA_1010102 ||
372         format == PixelFormat::YCRCB_P010 || format == PixelFormat::YCBCR_P010;
373 }
374 
CheckMulOverflow(int32_t width, int32_t bytesPerPixel)375 bool ImageUtils::CheckMulOverflow(int32_t width, int32_t bytesPerPixel)
376 {
377     if (width == 0 || bytesPerPixel == 0) {
378         IMAGE_LOGE("param is 0");
379         return true;
380     }
381     int64_t rowSize = static_cast<int64_t>(width) * bytesPerPixel;
382     if ((rowSize / width) != bytesPerPixel) {
383         IMAGE_LOGE("width * bytesPerPixel overflow!");
384         return true;
385     }
386     return false;
387 }
388 
CheckMulOverflow(int32_t width, int32_t height, int32_t bytesPerPixel)389 bool ImageUtils::CheckMulOverflow(int32_t width, int32_t height, int32_t bytesPerPixel)
390 {
391     if (width == 0 || height == 0 || bytesPerPixel == 0) {
392         IMAGE_LOGE("param is 0");
393         return true;
394     }
395     int64_t rectSize = static_cast<int64_t>(width) * height;
396     if ((rectSize / width) != height) {
397         IMAGE_LOGE("width * height overflow!");
398         return true;
399     }
400     int64_t bufferSize = rectSize * bytesPerPixel;
401     if ((bufferSize / bytesPerPixel) != rectSize) {
402         IMAGE_LOGE("bytesPerPixel overflow!");
403         return true;
404     }
405     return false;
406 }
407 
ReversePixels(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)408 static void ReversePixels(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)
409 {
410     if (byteCount % NUM_4 != NUM_0) {
411         IMAGE_LOGE("Pixel count must multiple of 4.");
412         return;
413     }
414     uint8_t *src = srcPixels;
415     uint8_t *dst = dstPixels;
416     for (uint32_t i = NUM_0 ; i < byteCount; i += NUM_4) {
417         // 0-B 1-G 2-R 3-A
418         dst[NUM_0] = src[NUM_3];
419         dst[NUM_1] = src[NUM_2];
420         dst[NUM_2] = src[NUM_1];
421         dst[NUM_3] = src[NUM_0];
422         src += NUM_4;
423         dst += NUM_4;
424     }
425 }
426 
BGRAToARGB(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)427 void ImageUtils::BGRAToARGB(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)
428 {
429     ImageTrace imageTrace("BGRAToARGB");
430     ReversePixels(srcPixels, dstPixels, byteCount);
431 }
432 
ARGBToBGRA(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)433 void ImageUtils::ARGBToBGRA(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)
434 {
435     ReversePixels(srcPixels, dstPixels, byteCount);
436 }
437 
SurfaceBuffer_Reference(void* buffer)438 int32_t ImageUtils::SurfaceBuffer_Reference(void* buffer)
439 {
440     if (buffer == nullptr) {
441         IMAGE_LOGE("parameter error, please check input parameter");
442         return ERR_SURFACEBUFFER_REFERENCE_FAILED;
443     }
444     OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(buffer);
445     ref->IncStrongRef(ref);
446     return SUCCESS;
447 }
448 
SurfaceBuffer_Unreference(void* buffer)449 int32_t ImageUtils::SurfaceBuffer_Unreference(void* buffer)
450 {
451     if (buffer == nullptr) {
452         IMAGE_LOGE("parameter error, please check input parameter");
453         return ERR_SURFACEBUFFER_UNREFERENCE_FAILED;
454     }
455     OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(buffer);
456     ref->DecStrongRef(ref);
457     return SUCCESS;
458 }
459 
DumpPixelMap(PixelMap* pixelMap, std::string customFileName, uint64_t imageId)460 void ImageUtils::DumpPixelMap(PixelMap* pixelMap, std::string customFileName, uint64_t imageId)
461 {
462     IMAGE_LOGI("ImageUtils::DumpPixelMap start");
463     std::string fileName = FILE_DIR_IN_THE_SANDBOX + GetLocalTime() + customFileName + std::to_string(imageId) +
464         GetPixelMapName(pixelMap) + ".dat";
465     int32_t totalSize = pixelMap->GetRowStride() * pixelMap->GetHeight();
466     if (pixelMap->GetPixelFormat() == PixelFormat::NV12 || pixelMap->GetPixelFormat() == PixelFormat::NV21) {
467 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
468         if (pixelMap->GetAllocatorType() == AllocatorType::DMA_ALLOC) {
469             auto sbBuffer = reinterpret_cast<SurfaceBuffer*>(pixelMap->GetFd());
470             totalSize = static_cast<int32_t>(sbBuffer->GetSize());
471         } else {
472             totalSize = static_cast<int32_t>(pixelMap->GetCapacity());
473         }
474 #else
475         totalSize = static_cast<int32_t>(pixelMap->GetCapacity());
476 #endif
477         IMAGE_LOGI("ImageUtils::DumpPixelMapIfDumpEnabled YUV420 totalSize is %{public}d", totalSize);
478     }
479     if (SUCCESS != SaveDataToFile(fileName, reinterpret_cast<const char*>(pixelMap->GetPixels()), totalSize)) {
480         IMAGE_LOGI("ImageUtils::DumpPixelMap failed");
481         return;
482     }
483     IMAGE_LOGI("ImageUtils::DumpPixelMap success, path = %{public}s", fileName.c_str());
484 }
485 
DumpPixelMapIfDumpEnabled(std::unique_ptr<PixelMap>& pixelMap, uint64_t imageId)486 void ImageUtils::DumpPixelMapIfDumpEnabled(std::unique_ptr<PixelMap>& pixelMap, uint64_t imageId)
487 {
488     if (!ImageSystemProperties::GetDumpImageEnabled()) {
489         return;
490     }
491     if (pixelMap == nullptr) {
492         IMAGE_LOGI("ImageUtils::DumpPixelMapIfDumpEnabled pixelMap is null");
493         return;
494     }
495     DumpPixelMap(pixelMap.get(), "_imageId", imageId);
496 }
497 
DumpPixelMapBeforeEncode(PixelMap& pixelMap)498 void ImageUtils::DumpPixelMapBeforeEncode(PixelMap& pixelMap)
499 {
500     if (!ImageSystemProperties::GetDumpImageEnabled()) {
501         return;
502     }
503     DumpPixelMap(&pixelMap, "_beforeEncode");
504 }
505 
DumpDataIfDumpEnabled(const char* data, const size_t& totalSize, const std::string& fileSuffix, uint64_t imageId)506 void ImageUtils::DumpDataIfDumpEnabled(const char* data, const size_t& totalSize,
507     const std::string& fileSuffix, uint64_t imageId)
508 {
509     if (!ImageSystemProperties::GetDumpImageEnabled()) {
510         return;
511     }
512     std::string fileName = FILE_DIR_IN_THE_SANDBOX + GetLocalTime() + "_imageId" + std::to_string(imageId) +
513         "_data_total" + std::to_string(totalSize) + "." + fileSuffix;
514     if (SUCCESS != SaveDataToFile(fileName, data, totalSize)) {
515         IMAGE_LOGI("ImageUtils::DumpDataIfDumpEnabled failed");
516         return;
517     }
518     IMAGE_LOGI("ImageUtils::DumpDataIfDumpEnabled success, path = %{public}s", fileName.c_str());
519 }
520 
GetNowTimeMilliSeconds()521 uint64_t ImageUtils::GetNowTimeMilliSeconds()
522 {
523     auto now = std::chrono::system_clock::now();
524     return std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
525 }
526 
GetNowTimeMicroSeconds()527 uint64_t ImageUtils::GetNowTimeMicroSeconds()
528 {
529     auto now = std::chrono::system_clock::now();
530     return std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
531 }
532 
GetCurrentProcessName()533 std::string ImageUtils::GetCurrentProcessName()
534 {
535     std::string processName;
536     std::ifstream cmdlineFile("/proc/self/cmdline");
537     if (cmdlineFile.is_open()) {
538         std::ostringstream oss;
539         oss << cmdlineFile.rdbuf();
540         cmdlineFile.close();
541 
542         //Extrace process name from the command line
543         std::string cmdline = oss.str();
544         size_t pos = cmdline.find_first_of('\0');
545         if (pos != std::string::npos) {
546             processName = cmdline.substr(0, pos);
547         }
548     }
549     return processName;
550 }
551 
SaveDataToFile(const std::string& fileName, const char* data, const size_t& totalSize)552 uint32_t ImageUtils::SaveDataToFile(const std::string& fileName, const char* data, const size_t& totalSize)
553 {
554     std::ofstream outFile(fileName, std::ofstream::out);
555     if (!outFile.is_open()) {
556         IMAGE_LOGI("ImageUtils::SaveDataToFile write error, path=%{public}s", fileName.c_str());
557         return IMAGE_RESULT_SAVE_DATA_TO_FILE_FAILED;
558     }
559     if (data == nullptr) {
560         IMAGE_LOGE("ImageUtils::SaveDataToFile data is nullptr");
561         return IMAGE_RESULT_SAVE_DATA_TO_FILE_FAILED;
562     }
563     outFile.write(data, totalSize);
564     return SUCCESS;
565 }
566 
GetLocalTime()567 std::string ImageUtils::GetLocalTime()
568 {
569     // time string : "year-month-day hour_minute_second.millisecond", ':' is not supported in windows file name
570     auto now = std::chrono::system_clock::now();
571     auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
572     std::time_t t = std::chrono::system_clock::to_time_t(now);
573     std::tm tm = *std::localtime(&t);
574 
575     std::stringstream ss;
576     int millSecondWidth = 3;
577     ss << std::put_time(&tm, "%Y-%m-%d %H_%M_%S.") << std::setfill('0') << std::setw(millSecondWidth) << ms.count();
578     return ss.str();
579 }
580 
GetPixelMapName(PixelMap* pixelMap)581 std::string ImageUtils::GetPixelMapName(PixelMap* pixelMap)
582 {
583     if (!pixelMap) {
584         IMAGE_LOGE("ImageUtils::GetPixelMapName error, pixelMap is null");
585         return "";
586     }
587 #ifdef IOS_PLATFORM
588     std::string pixelMapStr = "_pixelMap_w" + std::to_string(pixelMap->GetWidth()) +
589         "_h" + std::to_string(pixelMap->GetHeight()) +
590         "_rowStride" + std::to_string(pixelMap->GetRowStride()) +
591         "_pixelFormat" + std::to_string((int32_t)pixelMap->GetPixelFormat()) +
592         "_total" + std::to_string(pixelMap->GetRowStride() * pixelMap->GetHeight()) +
593         "_pid" + std::to_string(getpid()) +
594         "_tid" + std::to_string(syscall(SYS_thread_selfid)) +
595         "_uniqueId" + std::to_string(pixelMap->GetUniqueId());
596 #else
597     std::string yuvInfoStr = "";
598     if (pixelMap->GetPixelFormat() == PixelFormat::NV12 || pixelMap->GetPixelFormat() == PixelFormat::NV21) {
599         YUVDataInfo yuvInfo;
600         pixelMap->GetImageYUVInfo(yuvInfo);
601         yuvInfoStr += "_yWidth" + std::to_string(yuvInfo.yWidth) +
602             "_yHeight" + std::to_string(yuvInfo.yHeight) +
603             "_yStride" + std::to_string(yuvInfo.yStride) +
604             "_yOffset" + std::to_string(yuvInfo.yOffset) +
605             "_uvWidth" + std::to_string(yuvInfo.uvWidth) +
606             "_uvHeight" + std::to_string(yuvInfo.uvHeight) +
607             "_uvStride" + std::to_string(yuvInfo.uvStride) +
608             "_uvOffset" + std::to_string(yuvInfo.uvOffset);
609     }
610     std::string pixelMapStr = "_pixelMap_w" + std::to_string(pixelMap->GetWidth()) +
611         "_h" + std::to_string(pixelMap->GetHeight()) +
612         "_rowStride" + std::to_string(pixelMap->GetRowStride()) +
613         "_pixelFormat" + std::to_string((int32_t)pixelMap->GetPixelFormat()) +
614         "_total" + std::to_string(pixelMap->GetRowStride() * pixelMap->GetHeight()) +
615         "_pid" + std::to_string(getpid()) +
616         "_tid" + std::to_string(gettid()) +
617         "_uniqueId" + std::to_string(pixelMap->GetUniqueId());
618 #endif
619     return pixelMapStr;
620 }
621 
622  // BytesToUint16 function will modify the offset value.
BytesToUint16(uint8_t* bytes, uint32_t& offset, bool isBigEndian)623 uint16_t ImageUtils::BytesToUint16(uint8_t* bytes, uint32_t& offset, bool isBigEndian)
624 {
625     uint16_t data = 0;
626     if (bytes == nullptr) {
627         return data;
628     }
629     if (isBigEndian) {
630         data = (bytes[offset] << MOVE_BITS_8) | bytes[offset + NUM_1];
631     } else {
632         data = (bytes[offset + NUM_1] << MOVE_BITS_8) | bytes[offset];
633     }
634     offset += NUM_2;
635     return data;
636 }
637 
638 // BytesToUint32 function will modify the offset value.
BytesToUint32(uint8_t* bytes, uint32_t& offset, bool isBigEndian)639 uint32_t ImageUtils::BytesToUint32(uint8_t* bytes, uint32_t& offset, bool isBigEndian)
640 {
641     uint32_t data = 0;
642     if (bytes == nullptr) {
643         return data;
644     }
645     if (isBigEndian) {
646         data = (bytes[offset] << MOVE_BITS_24) | (bytes[offset + NUM_1] << MOVE_BITS_16) |
647                 (bytes[offset + NUM_2] << MOVE_BITS_8) | (bytes[offset + NUM_3]);
648     } else {
649         data = (bytes[offset + NUM_3] << MOVE_BITS_24) | (bytes[offset + NUM_2] << MOVE_BITS_16) |
650                 (bytes[offset + NUM_1] << MOVE_BITS_8) | bytes[offset];
651     }
652     offset += NUM_4;
653     return data;
654 }
655 
656 // BytesToInt32 function will modify the offset value.
BytesToInt32(uint8_t* bytes, uint32_t& offset, bool isBigEndian)657 int32_t ImageUtils::BytesToInt32(uint8_t* bytes, uint32_t& offset, bool isBigEndian)
658 {
659     int32_t data = 0;
660     if (bytes == nullptr) {
661         return data;
662     }
663     if (isBigEndian) {
664         data = (bytes[offset] << MOVE_BITS_24) | (bytes[offset + NUM_1] << MOVE_BITS_16) |
665                 (bytes[offset + NUM_2] << MOVE_BITS_8) | (bytes[offset + NUM_3]);
666     } else {
667         data = (bytes[offset + NUM_3] << MOVE_BITS_24) | (bytes[offset + NUM_2] << MOVE_BITS_16) |
668                 (bytes[offset + NUM_1] << MOVE_BITS_8) | bytes[offset];
669     }
670     offset += NUM_4;
671     return data;
672 }
673 
674 // BytesToFloat function will modify the offset value.
BytesToFloat(uint8_t* bytes, uint32_t& offset, bool isBigEndian)675 float ImageUtils::BytesToFloat(uint8_t* bytes, uint32_t& offset, bool isBigEndian)
676 {
677     uint32_t data = BytesToUint32(bytes, offset, isBigEndian);
678     union {
679         uint32_t i;
680         float f;
681     } u;
682     u.i = data;
683     return u.f;
684 }
685 
Uint16ToBytes(uint16_t data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)686 void ImageUtils::Uint16ToBytes(uint16_t data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)
687 {
688     uint8_t BYTE_ONE = (data >> MOVE_BITS_8) & 0xFF;
689     uint8_t BYTE_TWO = data & 0xFF;
690     if (isBigEndian) {
691         bytes[offset++] = BYTE_ONE;
692         bytes[offset++] = BYTE_TWO;
693     } else {
694         bytes[offset++] = BYTE_TWO;
695         bytes[offset++] = BYTE_ONE;
696     }
697 }
698 
Uint32ToBytes(uint32_t data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)699 void ImageUtils::Uint32ToBytes(uint32_t data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)
700 {
701     uint8_t BYTE_ONE = (data >> MOVE_BITS_24) & 0xFF;
702     uint8_t BYTE_TWO = (data >> MOVE_BITS_16) & 0xFF;
703     uint8_t BYTE_THREE = (data >> MOVE_BITS_8) & 0xFF;
704     uint8_t BYTE_FOUR = data & 0xFF;
705     if (isBigEndian) {
706         bytes[offset++] = BYTE_ONE;
707         bytes[offset++] = BYTE_TWO;
708         bytes[offset++] = BYTE_THREE;
709         bytes[offset++] = BYTE_FOUR;
710     } else {
711         bytes[offset++] = BYTE_FOUR;
712         bytes[offset++] = BYTE_THREE;
713         bytes[offset++] = BYTE_TWO;
714         bytes[offset++] = BYTE_ONE;
715     }
716 }
717 
FloatToBytes(float data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)718 void ImageUtils::FloatToBytes(float data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)
719 {
720     union {
721         uint32_t i;
722         float f;
723     } u;
724     u.f = data;
725     Uint32ToBytes(u.i, bytes, offset, isBigEndian);
726 }
727 
Int32ToBytes(int32_t data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)728 void ImageUtils::Int32ToBytes(int32_t data, vector<uint8_t>& bytes, uint32_t& offset, bool isBigEndian)
729 {
730     union {
731         uint32_t uit;
732         int32_t it;
733     } u;
734     u.it = data;
735     Uint32ToBytes(u.uit, bytes, offset, isBigEndian);
736 }
737 
ArrayToBytes(const uint8_t* data, uint32_t length, vector<uint8_t>& bytes, uint32_t& offset)738 void ImageUtils::ArrayToBytes(const uint8_t* data, uint32_t length, vector<uint8_t>& bytes, uint32_t& offset)
739 {
740     for (uint32_t i = 0; i < length; i++) {
741         bytes[offset++] = data[i] & 0xFF;
742     }
743 }
744 
GetNextArray(const uint8_t* pattern, uint32_t patternLen, std::vector<uint32_t>& next)745 static void GetNextArray(const uint8_t* pattern, uint32_t patternLen, std::vector<uint32_t>& next)
746 {
747     uint32_t prefixEnd = 0;
748     next[0] = prefixEnd;
749     for (uint32_t i = 1; i < patternLen; ++i) {
750         // if not match, move prefixEnd to next position
751         while (prefixEnd > 0 && pattern[prefixEnd] != pattern[i]) {
752             prefixEnd = next[prefixEnd - 1];
753         }
754         // if match, update prefixEnd
755         if (pattern[prefixEnd] == pattern[i]) {
756             prefixEnd++;
757         }
758         //update next array
759         next[i] = prefixEnd;
760     }
761 }
762 
KMPFind(const uint8_t* target, uint32_t targetLen, const uint8_t* pattern, uint32_t patternLen)763 int32_t ImageUtils::KMPFind(const uint8_t* target, uint32_t targetLen,
764     const uint8_t* pattern, uint32_t patternLen)
765 {
766     if (target == nullptr || pattern == nullptr || patternLen == 0) {
767         IMAGE_LOGE("ImageUtils FindFirstMatchingStringByKMP failed, patternLen is zero");
768         return ERR_MEDIA_INVALID_VALUE;
769     }
770 
771     std::vector<uint32_t> next(patternLen, 0);
772     GetNextArray(pattern, patternLen, next);
773     uint32_t targetIndex = 0;
774     uint32_t patternIndex = 0;
775     for (; targetIndex < targetLen; ++targetIndex) {
776         // if not match, move patternIndex to next position
777         while (patternIndex > 0 && target[targetIndex] != pattern[patternIndex]) {
778             patternIndex = next[patternIndex - 1];
779         }
780         // if match, update patternIndex
781         if (target[targetIndex] == pattern[patternIndex]) {
782             ++patternIndex;
783         }
784         // find the first matching string success
785         if (patternIndex == patternLen) {
786             return static_cast<int32_t>(targetIndex) - static_cast<int32_t>(patternLen) + static_cast<int32_t>(NUM_1);
787         }
788     }
789     return ERR_MEDIA_INVALID_VALUE;
790 }
791 
FlushSurfaceBuffer(PixelMap* pixelMap)792 void ImageUtils::FlushSurfaceBuffer(PixelMap* pixelMap)
793 {
794 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
795     if (!pixelMap || pixelMap->GetAllocatorType() != AllocatorType::DMA_ALLOC) {
796         return;
797     }
798     SurfaceBuffer* surfaceBuffer = static_cast<SurfaceBuffer*>(pixelMap->GetFd());
799     if (surfaceBuffer && (surfaceBuffer->GetUsage() & BUFFER_USAGE_MEM_MMZ_CACHE)) {
800         GSError err = surfaceBuffer->Map();
801         if (err != GSERROR_OK) {
802             IMAGE_LOGE("ImageUtils Map failed, GSError=%{public}d", err);
803             return;
804         }
805         err = surfaceBuffer->FlushCache();
806         if (err != GSERROR_OK) {
807             IMAGE_LOGE("ImageUtils FlushCache failed, GSError=%{public}d", err);
808         }
809     }
810 #else
811     return;
812 #endif
813 }
814 
FlushContextSurfaceBuffer(ImagePlugin::DecodeContext& context)815 void ImageUtils::FlushContextSurfaceBuffer(ImagePlugin::DecodeContext& context)
816 {
817 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
818     if (context.pixelsBuffer.context == nullptr || context.allocatorType != AllocatorType::DMA_ALLOC) {
819         return;
820     }
821     SurfaceBuffer* surfaceBuffer = static_cast<SurfaceBuffer*>(context.pixelsBuffer.context);
822     if (surfaceBuffer && (surfaceBuffer->GetUsage() & BUFFER_USAGE_MEM_MMZ_CACHE)) {
823         GSError err = surfaceBuffer->Map();
824         if (err != GSERROR_OK) {
825             IMAGE_LOGE("ImageUtils Map failed, GSError=%{public}d", err);
826             return;
827         }
828         err = surfaceBuffer->FlushCache();
829         if (err != GSERROR_OK) {
830             IMAGE_LOGE("ImageUtils FlushCache failed, GSError=%{public}d", err);
831         }
832     }
833 #else
834     return;
835 #endif
836 }
837 
InvalidateContextSurfaceBuffer(ImagePlugin::DecodeContext& context)838 void ImageUtils::InvalidateContextSurfaceBuffer(ImagePlugin::DecodeContext& context)
839 {
840 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
841     if (context.pixelsBuffer.context == nullptr || context.allocatorType != AllocatorType::DMA_ALLOC) {
842         return;
843     }
844     SurfaceBuffer* surfaceBuffer = static_cast<SurfaceBuffer*>(context.pixelsBuffer.context);
845     if (surfaceBuffer && (surfaceBuffer->GetUsage() & BUFFER_USAGE_MEM_MMZ_CACHE)) {
846         GSError err = surfaceBuffer->InvalidateCache();
847         if (err != GSERROR_OK) {
848             IMAGE_LOGE("ImageUtils FlushCache failed, GSError=%{public}d", err);
849         }
850     }
851 #else
852     return;
853 #endif
854 }
855 
IsAuxiliaryPictureTypeSupported(AuxiliaryPictureType type)856 bool ImageUtils::IsAuxiliaryPictureTypeSupported(AuxiliaryPictureType type)
857 {
858     auto auxTypes = GetAllAuxiliaryPictureType();
859     return (auxTypes.find(type) != auxTypes.end());
860 }
861 
IsAuxiliaryPictureEncoded(AuxiliaryPictureType type)862 bool ImageUtils::IsAuxiliaryPictureEncoded(AuxiliaryPictureType type)
863 {
864     return AuxiliaryPictureType::GAINMAP == type || AuxiliaryPictureType::UNREFOCUS_MAP == type ||
865         AuxiliaryPictureType::FRAGMENT_MAP == type;
866 }
867 
IsMetadataTypeSupported(MetadataType metadataType)868 bool ImageUtils::IsMetadataTypeSupported(MetadataType metadataType)
869 {
870     if (metadataType == MetadataType::EXIF || metadataType == MetadataType::FRAGMENT) {
871         return true;
872     } else {
873         return false;
874     }
875 }
876 
GetAllAuxiliaryPictureType()877 const std::set<AuxiliaryPictureType> ImageUtils::GetAllAuxiliaryPictureType()
878 {
879     static const std::set<AuxiliaryPictureType> auxTypes = {
880         AuxiliaryPictureType::GAINMAP,
881         AuxiliaryPictureType::DEPTH_MAP,
882         AuxiliaryPictureType::UNREFOCUS_MAP,
883         AuxiliaryPictureType::LINEAR_MAP,
884         AuxiliaryPictureType::FRAGMENT_MAP};
885     return auxTypes;
886 }
887 
GetAstcBytesCount(const ImageInfo& imageInfo)888 size_t ImageUtils::GetAstcBytesCount(const ImageInfo& imageInfo)
889 {
890     size_t astcBytesCount = 0;
891     uint32_t blockWidth = 0;
892     uint32_t blockHeight = 0;
893 
894     switch (imageInfo.pixelFormat) {
895         case PixelFormat::ASTC_4x4:
896             blockWidth = ASTC_4X4_BLOCK;
897             blockHeight = ASTC_4X4_BLOCK;
898             break;
899         case PixelFormat::ASTC_6x6:
900             blockWidth = ASTC_6X6_BLOCK;
901             blockHeight = ASTC_6X6_BLOCK;
902             break;
903         case PixelFormat::ASTC_8x8:
904             blockWidth = ASTC_8X8_BLOCK;
905             blockHeight = ASTC_8X8_BLOCK;
906             break;
907         default:
908             IMAGE_LOGE("ImageUtils GetAstcBytesCount failed, format is not supported %{public}d",
909                 imageInfo.pixelFormat);
910             return 0;
911     }
912     if ((blockWidth >= ASTC_4X4_BLOCK) && (blockHeight >= ASTC_4X4_BLOCK)) {
913         astcBytesCount = ((imageInfo.size.width + blockWidth - 1) / blockWidth) *
914             ((imageInfo.size.height + blockHeight - 1) / blockHeight) * ASTC_BLOCK_SIZE + ASTC_HEADER_SIZE;
915     }
916     return astcBytesCount;
917 }
918 
StrToUint32(const std::string& str, uint32_t& value)919 bool ImageUtils::StrToUint32(const std::string& str, uint32_t& value)
920 {
921     if (str.empty() || !isdigit(str.front())) {
922         return false;
923     }
924 
925     char* end = nullptr;
926     errno = 0;
927     auto addr = str.c_str();
928     auto result = strtoul(addr, &end, 10); /* 10 means decimal */
929     if ((end == addr) || (end[0] != '\0') || (errno == ERANGE) ||
930         (result > UINT32_MAX)) {
931         return false;
932     }
933     value = static_cast<uint32_t>(result);
934     return true;
935 }
936 
IsInRange(uint32_t value, uint32_t minValue, uint32_t maxValue)937 bool ImageUtils::IsInRange(uint32_t value, uint32_t minValue, uint32_t maxValue)
938 {
939     return (value >= minValue) && (value <= maxValue);
940 }
941 } // namespace Media
942 } // namespace OHOS
943