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
28 #include "__config"
29 #include "image_log.h"
30 #include "ios"
31 #include "istream"
32 #include "media_errors.h"
33 #include "new"
34 #include "plugin_server.h"
35 #include "singleton.h"
36 #include "string"
37 #include "type_traits"
38 #include "vector"
39 #include "image_trace.h"
40 #include "hitrace_meter.h"
41 #include "image_system_properties.h"
42 #include "pixel_map.h"
43 #ifdef IOS_PLATFORM
44 #include <sys/syscall.h>
45 #endif
46 #if !defined(IOS_PLATFORM) && !defined(A_PLATFORM)
47 #include "surface_buffer.h"
48 #else
49 #include "refbase.h"
50 #endif
51
52 #undef LOG_DOMAIN
53 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
54
55 #undef LOG_TAG
56 #define LOG_TAG "imageUtils"
57
58 namespace OHOS {
59 namespace Media {
60 using namespace std;
61 using namespace MultimediaPlugin;
62
63 constexpr int32_t ALPHA8_BYTES = 1;
64 constexpr int32_t RGB565_BYTES = 2;
65 constexpr int32_t RGB888_BYTES = 3;
66 constexpr int32_t ARGB8888_BYTES = 4;
67 constexpr int32_t RGBA_F16_BYTES = 8;
68 constexpr int32_t NV21_BYTES = 2; // Each pixel is sorted on 3/2 bytes.
69 constexpr int32_t ASTC_4X4_BYTES = 1;
70 constexpr float EPSILON = 1e-6;
71 constexpr int MAX_DIMENSION = INT32_MAX >> 2;
72 static bool g_pluginRegistered = false;
73 static const uint8_t NUM_0 = 0;
74 static const uint8_t NUM_1 = 1;
75 static const uint8_t NUM_2 = 2;
76 static const uint8_t NUM_3 = 3;
77 static const uint8_t NUM_4 = 4;
78 static const string FILE_DIR_IN_THE_SANDBOX = "/data/storage/el2/base/files/";
79
GetFileSize(const string & pathName,size_t & size)80 bool ImageUtils::GetFileSize(const string &pathName, size_t &size)
81 {
82 if (pathName.empty()) {
83 IMAGE_LOGE("[ImageUtil]input parameter exception.");
84 return false;
85 }
86 struct stat statbuf;
87 int ret = stat(pathName.c_str(), &statbuf);
88 if (ret != 0) {
89 IMAGE_LOGE("[ImageUtil]get the file size failed, ret:%{public}d, errno:%{public}d.", ret, errno);
90 return false;
91 }
92 size = statbuf.st_size;
93 return true;
94 }
95
GetFileSize(const int fd,size_t & size)96 bool ImageUtils::GetFileSize(const int fd, size_t &size)
97 {
98 struct stat statbuf;
99
100 if (fd < 0) {
101 return false;
102 }
103
104 int ret = fstat(fd, &statbuf);
105 if (ret != 0) {
106 IMAGE_LOGE("[ImageUtil]get the file size failed, ret:%{public}d, errno:%{public}d.", ret, errno);
107 return false;
108 }
109 size = statbuf.st_size;
110 return true;
111 }
112
GetInputStreamSize(istream & inputStream,size_t & size)113 bool ImageUtils::GetInputStreamSize(istream &inputStream, size_t &size)
114 {
115 if (inputStream.rdbuf() == nullptr) {
116 IMAGE_LOGE("[ImageUtil]input parameter exception.");
117 return false;
118 }
119 size_t original = inputStream.tellg();
120 inputStream.seekg(0, ios_base::end);
121 size = inputStream.tellg();
122 inputStream.seekg(original);
123 return true;
124 }
125
GetPixelBytes(const PixelFormat & pixelFormat)126 int32_t ImageUtils::GetPixelBytes(const PixelFormat &pixelFormat)
127 {
128 int pixelBytes = 0;
129 switch (pixelFormat) {
130 case PixelFormat::ARGB_8888:
131 case PixelFormat::BGRA_8888:
132 case PixelFormat::RGBA_8888:
133 case PixelFormat::CMYK:
134 pixelBytes = ARGB8888_BYTES;
135 break;
136 case PixelFormat::ALPHA_8:
137 pixelBytes = ALPHA8_BYTES;
138 break;
139 case PixelFormat::RGB_888:
140 pixelBytes = RGB888_BYTES;
141 break;
142 case PixelFormat::RGB_565:
143 pixelBytes = RGB565_BYTES;
144 break;
145 case PixelFormat::RGBA_F16:
146 pixelBytes = RGBA_F16_BYTES;
147 break;
148 case PixelFormat::NV21:
149 case PixelFormat::NV12:
150 pixelBytes = NV21_BYTES; // perl pixel 1.5 Bytes but return int so return 2
151 break;
152 case PixelFormat::ASTC_4x4:
153 case PixelFormat::ASTC_6x6:
154 case PixelFormat::ASTC_8x8:
155 pixelBytes = ASTC_4X4_BYTES;
156 break;
157 default:
158 IMAGE_LOGE("[ImageUtil]get pixel bytes failed, pixelFormat:%{public}d.",
159 static_cast<int32_t>(pixelFormat));
160 break;
161 }
162 return pixelBytes;
163 }
164
RegisterPluginServer()165 uint32_t ImageUtils::RegisterPluginServer()
166 {
167 #ifdef _WIN32
168 vector<string> pluginPaths = { "" };
169 #elif defined(_APPLE)
170 vector<string> pluginPaths = { "./" };
171 #elif defined(A_PLATFORM) || defined(IOS_PLATFORM)
172 vector<string> pluginPaths = {};
173 #else
174 vector<string> pluginPaths = { "/system/etc/multimediaplugin/image" };
175 #endif
176 PluginServer &pluginServer = DelayedRefSingleton<PluginServer>::GetInstance();
177 uint32_t result = pluginServer.Register(std::move(pluginPaths));
178 if (result != SUCCESS) {
179 IMAGE_LOGE("[ImageUtil]failed to register plugin server, ERRNO: %{public}u.", result);
180 } else {
181 g_pluginRegistered = true;
182 IMAGE_LOGD("[ImageUtil]success to register plugin server");
183 }
184 return result;
185 }
186
GetPluginServer()187 PluginServer& ImageUtils::GetPluginServer()
188 {
189 if (!g_pluginRegistered) {
190 uint32_t result = RegisterPluginServer();
191 if (result != SUCCESS) {
192 IMAGE_LOGI("[ImageUtil]failed to register plugin server, ERRNO: %{public}u.", result);
193 }
194 }
195 return DelayedRefSingleton<PluginServer>::GetInstance();
196 }
197
PathToRealPath(const string & path,string & realPath)198 bool ImageUtils::PathToRealPath(const string &path, string &realPath)
199 {
200 if (path.empty()) {
201 IMAGE_LOGE("path is empty!");
202 return false;
203 }
204
205 if ((path.length() >= PATH_MAX)) {
206 IMAGE_LOGE("path len is error, the len is: [%{public}lu]", static_cast<unsigned long>(path.length()));
207 return false;
208 }
209
210 char tmpPath[PATH_MAX] = { 0 };
211
212 #ifdef _WIN32
213 if (_fullpath(tmpPath, path.c_str(), path.length()) == nullptr) {
214 IMAGE_LOGW("path to _fullpath error");
215 }
216 #else
217 if (realpath(path.c_str(), tmpPath) == nullptr) {
218 IMAGE_LOGE("path to realpath is nullptr");
219 return false;
220 }
221 #endif
222
223 realPath = tmpPath;
224 return true;
225 }
226
FloatCompareZero(float src)227 bool ImageUtils::FloatCompareZero(float src)
228 {
229 return fabs(src - 0) < EPSILON;
230 }
231
GetValidAlphaTypeByFormat(const AlphaType & dstType,const PixelFormat & format)232 AlphaType ImageUtils::GetValidAlphaTypeByFormat(const AlphaType &dstType, const PixelFormat &format)
233 {
234 switch (format) {
235 case PixelFormat::RGBA_8888:
236 case PixelFormat::BGRA_8888:
237 case PixelFormat::ARGB_8888:
238 case PixelFormat::RGBA_F16: {
239 break;
240 }
241 case PixelFormat::ALPHA_8: {
242 if (dstType != AlphaType::IMAGE_ALPHA_TYPE_PREMUL) {
243 return AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
244 }
245 break;
246 }
247 case PixelFormat::RGB_888:
248 case PixelFormat::RGB_565: {
249 if (dstType != AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) {
250 return AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
251 }
252 break;
253 }
254 case PixelFormat::NV21:
255 case PixelFormat::NV12:
256 case PixelFormat::CMYK:
257 default: {
258 IMAGE_LOGE("GetValidAlphaTypeByFormat unsupport the format(%{public}d).", format);
259 return AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
260 }
261 }
262 return dstType;
263 }
264
IsValidImageInfo(const ImageInfo & info)265 bool ImageUtils::IsValidImageInfo(const ImageInfo &info)
266 {
267 if (info.size.width <= 0 || info.size.height <= 0 || info.size.width > MAX_DIMENSION ||
268 info.size.height > MAX_DIMENSION) {
269 IMAGE_LOGE("width(%{public}d) or height(%{public}d) is invalid.", info.size.width, info.size.height);
270 return false;
271 }
272 if (info.pixelFormat == PixelFormat::UNKNOWN || info.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) {
273 IMAGE_LOGE("check pixelformat and alphatype is invalid.");
274 return false;
275 }
276 return true;
277 }
278
CheckMulOverflow(int32_t width,int32_t bytesPerPixel)279 bool ImageUtils::CheckMulOverflow(int32_t width, int32_t bytesPerPixel)
280 {
281 if (width == 0 || bytesPerPixel == 0) {
282 IMAGE_LOGE("param is 0");
283 return true;
284 }
285 int64_t rowSize = static_cast<int64_t>(width) * bytesPerPixel;
286 if ((rowSize / width) != bytesPerPixel) {
287 IMAGE_LOGE("width * bytesPerPixel overflow!");
288 return true;
289 }
290 return false;
291 }
292
CheckMulOverflow(int32_t width,int32_t height,int32_t bytesPerPixel)293 bool ImageUtils::CheckMulOverflow(int32_t width, int32_t height, int32_t bytesPerPixel)
294 {
295 if (width == 0 || height == 0 || bytesPerPixel == 0) {
296 IMAGE_LOGE("param is 0");
297 return true;
298 }
299 int64_t rectSize = static_cast<int64_t>(width) * height;
300 if ((rectSize / width) != height) {
301 IMAGE_LOGE("width * height overflow!");
302 return true;
303 }
304 int64_t bufferSize = rectSize * bytesPerPixel;
305 if ((bufferSize / bytesPerPixel) != rectSize) {
306 IMAGE_LOGE("bytesPerPixel overflow!");
307 return true;
308 }
309 return false;
310 }
311
ReversePixels(uint8_t * srcPixels,uint8_t * dstPixels,uint32_t byteCount)312 static void ReversePixels(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)
313 {
314 if (byteCount % NUM_4 != NUM_0) {
315 IMAGE_LOGE("Pixel count must multiple of 4.");
316 return;
317 }
318 uint8_t *src = srcPixels;
319 uint8_t *dst = dstPixels;
320 for (uint32_t i = NUM_0 ; i < byteCount; i += NUM_4) {
321 // 0-B 1-G 2-R 3-A
322 dst[NUM_0] = src[NUM_3];
323 dst[NUM_1] = src[NUM_2];
324 dst[NUM_2] = src[NUM_1];
325 dst[NUM_3] = src[NUM_0];
326 src += NUM_4;
327 dst += NUM_4;
328 }
329 }
330
BGRAToARGB(uint8_t * srcPixels,uint8_t * dstPixels,uint32_t byteCount)331 void ImageUtils::BGRAToARGB(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)
332 {
333 ImageTrace imageTrace("BGRAToARGB");
334 ReversePixels(srcPixels, dstPixels, byteCount);
335 }
336
ARGBToBGRA(uint8_t * srcPixels,uint8_t * dstPixels,uint32_t byteCount)337 void ImageUtils::ARGBToBGRA(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount)
338 {
339 ReversePixels(srcPixels, dstPixels, byteCount);
340 }
341
SurfaceBuffer_Reference(void * buffer)342 int32_t ImageUtils::SurfaceBuffer_Reference(void* buffer)
343 {
344 if (buffer == nullptr) {
345 IMAGE_LOGE("parameter error, please check input parameter");
346 return ERR_SURFACEBUFFER_REFERENCE_FAILED;
347 }
348 OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(buffer);
349 ref->IncStrongRef(ref);
350 return SUCCESS;
351 }
352
SurfaceBuffer_Unreference(void * buffer)353 int32_t ImageUtils::SurfaceBuffer_Unreference(void* buffer)
354 {
355 if (buffer == nullptr) {
356 IMAGE_LOGE("parameter error, please check input parameter");
357 return ERR_SURFACEBUFFER_UNREFERENCE_FAILED;
358 }
359 OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(buffer);
360 ref->DecStrongRef(ref);
361 return SUCCESS;
362 }
363
DumpPixelMapIfDumpEnabled(std::unique_ptr<PixelMap> & pixelMap,uint64_t imageId)364 void ImageUtils::DumpPixelMapIfDumpEnabled(std::unique_ptr<PixelMap>& pixelMap, uint64_t imageId)
365 {
366 if (!ImageSystemProperties::GetDumpImageEnabled()) {
367 return;
368 }
369 if (pixelMap == nullptr) {
370 IMAGE_LOGI("ImageUtils::DumpPixelMapIfDumpEnabled pixelMap is null");
371 return;
372 }
373
374 IMAGE_LOGI("ImageUtils::DumpPixelMapIfDumpEnabled start");
375 std::string fileName = FILE_DIR_IN_THE_SANDBOX + GetLocalTime() + "_imageId" + std::to_string(imageId) +
376 GetPixelMapName(pixelMap.get()) + ".dat";
377 int32_t totalSize = pixelMap->GetRowStride() * pixelMap->GetHeight();
378 if (SUCCESS != SaveDataToFile(fileName, reinterpret_cast<const char*>(pixelMap->GetPixels()), totalSize)) {
379 IMAGE_LOGI("ImageUtils::DumpPixelMapIfDumpEnabled failed");
380 return;
381 }
382 IMAGE_LOGI("ImageUtils::DumpPixelMapIfDumpEnabled success, path = %{public}s", fileName.c_str());
383 }
384
DumpPixelMapBeforeEncode(PixelMap & pixelMap)385 void ImageUtils::DumpPixelMapBeforeEncode(PixelMap& pixelMap)
386 {
387 if (!ImageSystemProperties::GetDumpImageEnabled()) {
388 return;
389 }
390 IMAGE_LOGI("ImageUtils::DumpPixelMapBeforeEncode start");
391 std::string fileName = FILE_DIR_IN_THE_SANDBOX + GetLocalTime() + "_beforeEncode" + GetPixelMapName(&pixelMap) +
392 ".dat";
393 int32_t totalSize = pixelMap.GetRowStride() * pixelMap.GetHeight();
394 if (SUCCESS != SaveDataToFile(fileName, reinterpret_cast<const char*>(pixelMap.GetPixels()), totalSize)) {
395 IMAGE_LOGI("ImageUtils::DumpPixelMapBeforeEncode failed");
396 return;
397 }
398 IMAGE_LOGI("ImageUtils::DumpPixelMapBeforeEncode success, path = %{public}s", fileName.c_str());
399 }
400
DumpDataIfDumpEnabled(const char * data,const size_t & totalSize,const std::string & fileSuffix,uint64_t imageId)401 void ImageUtils::DumpDataIfDumpEnabled(const char* data, const size_t& totalSize,
402 const std::string& fileSuffix, uint64_t imageId)
403 {
404 if (!ImageSystemProperties::GetDumpImageEnabled()) {
405 return;
406 }
407 std::string fileName = FILE_DIR_IN_THE_SANDBOX + GetLocalTime() + "_imageId" + std::to_string(imageId) +
408 "_data_total" + std::to_string(totalSize) + "." + fileSuffix;
409 if (SUCCESS != SaveDataToFile(fileName, data, totalSize)) {
410 IMAGE_LOGI("ImageUtils::DumpDataIfDumpEnabled failed");
411 return;
412 }
413 IMAGE_LOGI("ImageUtils::DumpDataIfDumpEnabled success, path = %{public}s", fileName.c_str());
414 }
415
SaveDataToFile(const std::string & fileName,const char * data,const size_t & totalSize)416 uint32_t ImageUtils::SaveDataToFile(const std::string& fileName, const char* data, const size_t& totalSize)
417 {
418 std::ofstream outFile(fileName, std::ofstream::out);
419 if (!outFile.is_open()) {
420 IMAGE_LOGI("ImageUtils::SaveDataToFile write error, path=%{public}s", fileName.c_str());
421 return IMAGE_RESULT_SAVE_DATA_TO_FILE_FAILED;
422 }
423 outFile.write(data, totalSize);
424 return SUCCESS;
425 }
426
GetLocalTime()427 std::string ImageUtils::GetLocalTime()
428 {
429 // time string : "year-month-day hour_minute_second.millisecond", ':' is not supported in windows file name
430 auto now = std::chrono::system_clock::now();
431 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
432 std::time_t t = std::chrono::system_clock::to_time_t(now);
433 std::tm tm = *std::localtime(&t);
434
435 std::stringstream ss;
436 int millSecondWidth = 3;
437 ss << std::put_time(&tm, "%Y-%m-%d %H_%M_%S.") << std::setfill('0') << std::setw(millSecondWidth) << ms.count();
438 return ss.str();
439 }
440
GetPixelMapName(PixelMap * pixelMap)441 std::string ImageUtils::GetPixelMapName(PixelMap* pixelMap)
442 {
443 if (!pixelMap) {
444 IMAGE_LOGE("ImageUtils::GetPixelMapName error, pixelMap is null");
445 return "";
446 }
447 #ifdef IOS_PLATFORM
448 std::string pixelMapStr = "_pixelMap_w" + std::to_string(pixelMap->GetWidth()) +
449 "_h" + std::to_string(pixelMap->GetHeight()) +
450 "_rowStride" + std::to_string(pixelMap->GetRowStride()) +
451 "_total" + std::to_string(pixelMap->GetRowStride() * pixelMap->GetHeight()) +
452 "_pid" + std::to_string(getpid()) +
453 "_tid" + std::to_string(syscall(SYS_thread_selfid)) +
454 "_uniqueId" + std::to_string(pixelMap->GetUniqueId());
455 #else
456 std::string pixelMapStr = "_pixelMap_w" + std::to_string(pixelMap->GetWidth()) +
457 "_h" + std::to_string(pixelMap->GetHeight()) +
458 "_rowStride" + std::to_string(pixelMap->GetRowStride()) +
459 "_total" + std::to_string(pixelMap->GetRowStride() * pixelMap->GetHeight()) +
460 "_pid" + std::to_string(getpid()) +
461 "_tid" + std::to_string(gettid()) +
462 "_uniqueId" + std::to_string(pixelMap->GetUniqueId());
463 #endif
464 return pixelMapStr;
465 }
466 } // namespace Media
467 } // namespace OHOS
468