1 /*
2 * Copyright (C) 2024 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 "thumbnail_source_loading.h"
17
18 #include <fcntl.h>
19
20 #include "dfx_manager.h"
21 #include "dfx_utils.h"
22 #include "directory_ex.h"
23 #include "image_source.h"
24 #include "media_exif.h"
25 #include "media_file_utils.h"
26 #include "medialibrary_tracer.h"
27 #include "post_proc.h"
28 #include "thumbnail_image_framework_utils.h"
29 #include "thumbnail_utils.h"
30 #include "thumbnail_const.h"
31
32 using namespace std;
33
34 namespace OHOS {
35 namespace Media {
36
37 const std::string LOCAL_MEDIA_PATH = "/storage/media/local/files/";
38
39 const std::unordered_map<SourceState, SourceState> SourceLoader::LOCAL_SOURCE_LOADING_STATES = {
40 { SourceState::BEGIN, SourceState::LOCAL_ORIGIN },
41 { SourceState::LOCAL_ORIGIN, SourceState::FINISH },
42 };
43
44 const std::unordered_map<SourceState, SourceState> SourceLoader::LOCAL_THUMB_SOURCE_LOADING_STATES = {
45 { SourceState::BEGIN, SourceState::LOCAL_THUMB },
46 { SourceState::LOCAL_THUMB, SourceState::LOCAL_LCD },
47 { SourceState::LOCAL_LCD, SourceState::LOCAL_ORIGIN },
48 { SourceState::LOCAL_ORIGIN, SourceState::FINISH },
49 };
50
51 const std::unordered_map<SourceState, SourceState> SourceLoader::CLOUD_SOURCE_LOADING_STATES = {
52 { SourceState::BEGIN, SourceState::CLOUD_THUMB },
53 { SourceState::CLOUD_THUMB, SourceState::CLOUD_LCD },
54 { SourceState::CLOUD_LCD, SourceState::CLOUD_ORIGIN },
55 { SourceState::CLOUD_ORIGIN, SourceState::FINISH },
56 };
57
58 const std::unordered_map<SourceState, SourceState> SourceLoader::ALL_SOURCE_LOADING_STATES = {
59 { SourceState::BEGIN, SourceState::LOCAL_THUMB },
60 { SourceState::LOCAL_THUMB, SourceState::LOCAL_LCD },
61 { SourceState::LOCAL_LCD, SourceState::LOCAL_ORIGIN },
62 { SourceState::LOCAL_ORIGIN, SourceState::CLOUD_LCD },
63 { SourceState::CLOUD_LCD, SourceState::CLOUD_ORIGIN },
64 { SourceState::CLOUD_ORIGIN, SourceState::FINISH },
65 };
66
67 // For cloud video, generating thumbnail foreground in LOCAL_ORIGIN state may download its source video.
68 const std::unordered_map<SourceState, SourceState> SourceLoader::ALL_SOURCE_LOADING_CLOUD_VIDEO_STATES = {
69 { SourceState::BEGIN, SourceState::LOCAL_THUMB },
70 { SourceState::LOCAL_THUMB, SourceState::LOCAL_LCD },
71 { SourceState::LOCAL_LCD, SourceState::CLOUD_LCD },
72 { SourceState::CLOUD_LCD, SourceState::CLOUD_ORIGIN },
73 { SourceState::CLOUD_ORIGIN, SourceState::FINISH },
74 };
75
76 const std::unordered_map<SourceState, SourceState> SourceLoader::CLOUD_LCD_SOURCE_LOADING_STATES = {
77 { SourceState::BEGIN, SourceState::CLOUD_LCD },
78 { SourceState::CLOUD_LCD, SourceState::CLOUD_ORIGIN },
79 { SourceState::CLOUD_ORIGIN, SourceState::FINISH },
80 };
81
82 const std::unordered_map<SourceState, SourceState> SourceLoader::LOCAL_LCD_SOURCE_LOADING_STATES = {
83 { SourceState::BEGIN, SourceState::LOCAL_LCD },
84 { SourceState::LOCAL_LCD, SourceState::LOCAL_ORIGIN },
85 { SourceState::LOCAL_ORIGIN, SourceState::FINISH },
86 };
87
88 const std::unordered_map<SourceState, SourceState> SourceLoader::UPGRADE_SOURCE_LOADING_STATES = {
89 { SourceState::BEGIN, SourceState::LOCAL_ORIGIN },
90 { SourceState::LOCAL_ORIGIN, SourceState::CLOUD_ORIGIN },
91 { SourceState::CLOUD_ORIGIN, SourceState::FINISH },
92 };
93
94 const std::unordered_map<SourceState, SourceState> SourceLoader::UPGRADE_VIDEO_SOURCE_LOADING_STATES = {
95 { SourceState::BEGIN, SourceState::LOCAL_ORIGIN },
96 { SourceState::LOCAL_ORIGIN, SourceState::CLOUD_LCD },
97 { SourceState::CLOUD_LCD, SourceState::FINISH },
98 };
99
GetLocalThumbnailPath(const std::string & path,const std::string & key)100 std::string GetLocalThumbnailPath(const std::string &path, const std::string &key)
101 {
102 if (path.length() < ROOT_MEDIA_DIR.length()) {
103 return "";
104 }
105 std::string suffix = (key == "") ? "" : "/" + key + ".jpg";
106 return LOCAL_MEDIA_PATH + ((key == "") ? "" : ".thumbs/") + path.substr(ROOT_MEDIA_DIR.length()) + suffix;
107 }
108
GetLocalKeyFrameThumbnailPath(const std::string & path,const std::string & key,const std::string & timeStamp)109 std::string GetLocalKeyFrameThumbnailPath(const std::string &path, const std::string &key, const std::string &timeStamp)
110 {
111 if (path.length() < ROOT_MEDIA_DIR.length()) {
112 return "";
113 }
114 std::string suffix = (key == "") ? "" : "/" + key + ".jpg";
115 return LOCAL_MEDIA_PATH + ((key == "") ? "" : ".thumbs/") + path.substr(ROOT_MEDIA_DIR.length()) +
116 "/beginTimeStamp" + timeStamp + "/" + suffix;
117 }
118
GetLcdExPath(const std::string & path)119 std::string GetLcdExPath(const std::string &path)
120 {
121 if (path.length() < ROOT_MEDIA_DIR.length()) {
122 return "";
123 }
124 std::string suffix = "/THM_EX/" + THUMBNAIL_LCD_SUFFIX + ".jpg";
125 return ROOT_MEDIA_DIR + ".thumbs/" + path.substr(ROOT_MEDIA_DIR.length()) + suffix;
126 }
127
IsLocalSourceAvailable(const std::string & path)128 bool IsLocalSourceAvailable(const std::string& path)
129 {
130 char tmpPath[PATH_MAX] = { 0 };
131 if (realpath(path.c_str(), tmpPath) == nullptr) {
132 // it's alright if source loading fails here, just move on to next source
133 MEDIA_ERR_LOG("SourceLoader path to realPath is nullptr: errno: %{public}d, %{public}s",
134 errno, DfxUtils::GetSafePath(path).c_str());
135 return false;
136 }
137
138 FILE* filePtr = fopen(tmpPath, "rb");
139 if (filePtr == nullptr) {
140 MEDIA_ERR_LOG("SourceLoader open local file fail: errno: %{public}d, %{public}s",
141 errno, DfxUtils::GetSafePath(path).c_str());
142 return false;
143 }
144 if (fclose(filePtr) != E_OK) {
145 MEDIA_ERR_LOG("SourceLoader close filePtr fail: errno: %{public}d, %{public}s",
146 errno, DfxUtils::GetSafePath(path).c_str());
147 return false;
148 }
149 return true;
150 }
151
IsCloudSourceAvailable(const std::string & path)152 bool IsCloudSourceAvailable(const std::string& path)
153 {
154 string absFilePath;
155 if (!PathToRealPath(path, absFilePath)) {
156 MEDIA_ERR_LOG("Not real file path: errno: %{public}d, %{public}s", errno, DfxUtils::GetSafePath(path).c_str());
157 return false;
158 }
159
160 int fd = open(absFilePath.c_str(), O_RDONLY);
161 if (fd < 0) {
162 MEDIA_ERR_LOG("open cloud file fail: errno: %{public}d, %{public}s",
163 errno, DfxUtils::GetSafePath(path).c_str());
164 return false;
165 }
166 close(fd);
167 return true;
168 }
169
NeedAutoResize(const Size & size)170 bool NeedAutoResize(const Size &size)
171 {
172 // Only small thumbnails need to be scaled after decoding, others should resized while decoding.
173 return size.width > SHORT_SIDE_THRESHOLD && size.height > SHORT_SIDE_THRESHOLD;
174 }
175
GenDecodeOpts(const Size & sourceSize,const Size & targetSize,DecodeOptions & decodeOpts)176 bool GenDecodeOpts(const Size &sourceSize, const Size &targetSize, DecodeOptions &decodeOpts)
177 {
178 if (targetSize.width == 0) {
179 MEDIA_ERR_LOG("Failed to generate decodeOpts, scale size contains zero");
180 return false;
181 }
182 decodeOpts.desiredPixelFormat = PixelFormat::RGBA_8888;
183 if (NeedAutoResize(targetSize)) {
184 decodeOpts.desiredSize = targetSize;
185 return true;
186 }
187
188 int32_t decodeScale = 1;
189 int32_t scaleFactor = sourceSize.width / targetSize.width;
190 while (scaleFactor /= DECODE_SCALE_BASE) {
191 decodeScale *= DECODE_SCALE_BASE;
192 }
193 decodeOpts.desiredSize = {
194 std::ceil(sourceSize.width / decodeScale),
195 std::ceil(sourceSize.height / decodeScale),
196 };
197 return true;
198 }
199
ConvertDecodeSize(ThumbnailData & data,const Size & sourceSize,Size & desiredSize)200 Size ConvertDecodeSize(ThumbnailData &data, const Size &sourceSize, Size &desiredSize)
201 {
202 int width = sourceSize.width;
203 int height = sourceSize.height;
204 if (!ThumbnailUtils::ResizeThumb(width, height)) {
205 MEDIA_ERR_LOG("ResizeThumb failed");
206 return {0, 0};
207 }
208 Size thumbDesiredSize = {width, height};
209 data.thumbDesiredSize = thumbDesiredSize;
210 float desiredScale = static_cast<float>(thumbDesiredSize.height) / static_cast<float>(thumbDesiredSize.width);
211 float sourceScale = static_cast<float>(sourceSize.height) / static_cast<float>(sourceSize.width);
212 float scale = 1.0f;
213 if (sourceScale - desiredScale <= EPSILON) {
214 scale = (float)thumbDesiredSize.height / sourceSize.height;
215 } else {
216 scale = (float)thumbDesiredSize.width / sourceSize.width;
217 }
218 scale = scale < 1.0f ? scale : 1.0f;
219 Size thumbDecodeSize = {
220 static_cast<int32_t> (scale * sourceSize.width),
221 static_cast<int32_t> (scale * sourceSize.height),
222 };
223
224 width = sourceSize.width;
225 height = sourceSize.height;
226 if (!ThumbnailUtils::ResizeLcd(width, height)) {
227 MEDIA_ERR_LOG("ResizeLcd failed");
228 return {0, 0};
229 }
230 Size lcdDesiredSize = {width, height};
231 data.lcdDesiredSize = lcdDesiredSize;
232
233 int lcdMinSide = std::min(lcdDesiredSize.width, lcdDesiredSize.height);
234 int thumbMinSide = std::min(thumbDesiredSize.width, thumbDesiredSize.height);
235 Size lcdDecodeSize = lcdMinSide < thumbMinSide ? thumbDecodeSize : lcdDesiredSize;
236
237 if (data.loaderOpts.decodeInThumbSize) {
238 desiredSize = thumbDesiredSize;
239 return thumbDecodeSize;
240 } else if (data.needResizeLcd) {
241 desiredSize = lcdDesiredSize;
242 return lcdDecodeSize;
243 } else {
244 desiredSize = lcdDesiredSize;
245 return lcdDesiredSize;
246 }
247 }
248
ParseDesiredMinSide(const ThumbnailType & type)249 int32_t ParseDesiredMinSide(const ThumbnailType &type)
250 {
251 switch (type) {
252 case ThumbnailType::THUMB:
253 return SHORT_SIDE_THRESHOLD;
254 break;
255 case ThumbnailType::MTH_ASTC:
256 return MONTH_SHORT_SIDE_THRESHOLD;
257 break;
258 default:
259 break;
260 }
261 return INT32_MAX_VALUE_LENGTH;
262 }
263
SwitchToNextState(ThumbnailData & data,SourceState & state)264 void SwitchToNextState(ThumbnailData &data, SourceState &state)
265 {
266 if (state == SourceState::FINISH) {
267 MEDIA_INFO_LOG("SwitchToNextState current state is FINISH.");
268 return;
269 }
270 auto iter = data.loaderOpts.loadingStates.find(state);
271 if (iter == data.loaderOpts.loadingStates.end()) {
272 MEDIA_WARN_LOG("SwitchToNextState find next state error, current state:%{public}d",
273 static_cast<int32_t>(state));
274 return;
275 }
276 state = iter->second;
277 }
278
LoadImageSource(const std::string & path,uint32_t & err)279 unique_ptr<ImageSource> LoadImageSource(const std::string &path, uint32_t &err)
280 {
281 MediaLibraryTracer tracer;
282 tracer.Start("LoadImageSource");
283
284 SourceOptions opts;
285 unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(path, opts, err);
286 if (err != E_OK || !imageSource) {
287 MEDIA_ERR_LOG("Failed to LoadImageSource, pixelmap path: %{public}s exists: %{public}d",
288 path.c_str(), MediaFileUtils::IsFileExists(path));
289 DfxManager::GetInstance()->HandleThumbnailError(path, DfxType::IMAGE_SOURCE_CREATE, err);
290 return imageSource;
291 }
292 return imageSource;
293 }
294
CreateVideoFramePixelMap()295 bool SourceLoader::CreateVideoFramePixelMap()
296 {
297 MediaLibraryTracer tracer;
298 tracer.Start("CreateVideoFramePixelMap");
299 return ThumbnailUtils::LoadVideoFile(data_, desiredSize_);
300 }
301
SetCurrentStateFunction()302 void SourceLoader::SetCurrentStateFunction()
303 {
304 StateFunc stateFunc = STATE_FUNC_MAP.at(state_);
305 GetSourcePath = stateFunc.GetSourcePath;
306 IsSizeLargeEnough = stateFunc.IsSizeLargeEnough;
307 }
308
GeneratePictureSource(std::unique_ptr<ImageSource> & imageSource,const Size & targetSize)309 bool SourceLoader::GeneratePictureSource(std::unique_ptr<ImageSource> &imageSource, const Size &targetSize)
310 {
311 DecodingOptionsForPicture pictureOpts;
312 pictureOpts.desireAuxiliaryPictures = {AuxiliaryPictureType::GAINMAP};
313 uint32_t errorCode = ERR_OK;
314 auto picturePtr = imageSource->CreatePicture(pictureOpts, errorCode);
315 if (errorCode != E_OK || picturePtr == nullptr) {
316 MEDIA_ERR_LOG("Failed to GeneratePictureSource, CreatePicture failed, err: %{public}d, path %{public}s",
317 errorCode, DfxUtils::GetSafePath(data_.path).c_str());
318 return false;
319 }
320 std::shared_ptr<Picture> picture = std::move(picturePtr);
321 auto pixelMap = picture->GetMainPixel();
322 auto gainMap = picture->GetGainmapPixelMap();
323 if (pixelMap == nullptr) {
324 MEDIA_ERR_LOG("Failed to GeneratePictureSource, main pixelMap is nullptr, path %{public}s",
325 DfxUtils::GetSafePath(data_.path).c_str());
326 return false;
327 }
328 if (gainMap == nullptr) {
329 MEDIA_ERR_LOG("Failed to GeneratePictureSource, gainmap is nullptr, path %{public}s",
330 DfxUtils::GetSafePath(data_.path).c_str());
331 return false;
332 }
333 if (pixelMap->GetWidth() * pixelMap->GetHeight() == 0) {
334 MEDIA_ERR_LOG("Failed to GeneratePictureSource, pixelMap size invalid, width: %{public}d, height: %{public}d,"
335 "path %{public}s", pixelMap->GetWidth(), pixelMap->GetHeight(), DfxUtils::GetSafePath(data_.path).c_str());
336 return false;
337 }
338 float widthScale = (1.0f * targetSize.width) / pixelMap->GetWidth();
339 float heightScale = (1.0f * targetSize.height) / pixelMap->GetHeight();
340 pixelMap->resize(widthScale, heightScale);
341 gainMap->resize(widthScale, heightScale);
342 data_.source.SetPicture(picture);
343 return true;
344 }
345
GeneratePixelMapSource(std::unique_ptr<ImageSource> & imageSource,const Size & sourceSize,const Size & targetSize)346 bool SourceLoader::GeneratePixelMapSource(std::unique_ptr<ImageSource> &imageSource, const Size &sourceSize,
347 const Size &targetSize)
348 {
349 DecodeOptions decodeOpts;
350 uint32_t err = ERR_OK;
351 if (!GenDecodeOpts(sourceSize, targetSize, decodeOpts)) {
352 MEDIA_ERR_LOG("SourceLoader failed to generate decodeOpts, pixelmap path %{public}s",
353 DfxUtils::GetSafePath(data_.path).c_str());
354 return false;
355 }
356 std::shared_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, err);
357 if (err != E_OK || pixelMap == nullptr) {
358 MEDIA_ERR_LOG("SourceLoader failed to CreatePixelMap, err: %{public}d, pixelmap path %{public}s",
359 err, DfxUtils::GetSafePath(data_.path).c_str());
360 DfxManager::GetInstance()->HandleThumbnailError(data_.path, DfxType::IMAGE_SOURCE_CREATE_PIXELMAP, err);
361 return false;
362 }
363 if (!NeedAutoResize(targetSize) && !ThumbnailUtils::ScaleTargetPixelMap(pixelMap, targetSize,
364 Media::AntiAliasingOption::HIGH)) {
365 MEDIA_ERR_LOG("SourceLoader fail to scaleTarget, path %{public}s", DfxUtils::GetSafePath(data_.path).c_str());
366 return false;
367 }
368 data_.source.SetPixelMap(pixelMap);
369 return true;
370 }
371
CreateImagePixelMap(const std::string & sourcePath)372 bool SourceLoader::CreateImagePixelMap(const std::string &sourcePath)
373 {
374 MediaLibraryTracer tracer;
375 tracer.Start("SourceLoader CreateImagePixelMap");
376 uint32_t err = 0;
377 std::unique_ptr<ImageSource> imageSource = LoadImageSource(sourcePath, err);
378 if (err != E_OK || imageSource == nullptr) {
379 MEDIA_ERR_LOG("SourceLoader LoadImageSource error:%{public}d, errorno:%{public}d", err, errno);
380 return false;
381 }
382
383 ImageInfo imageInfo;
384 if (!IsSizeAcceptable(imageSource, imageInfo)) {
385 MEDIA_ERR_LOG("SourceLoader CreateImagePixelMap size not acceptable, status:%{public}s, path:%{public}s",
386 STATE_NAME_MAP.at(state_).c_str(), DfxUtils::GetSafePath(data_.path).c_str());
387 return false;
388 }
389
390 Size targetSize = ConvertDecodeSize(data_, imageInfo.size, desiredSize_);
391 Size sourceSize = imageInfo.size;
392
393 // When encode picture, if mainPixel width or height is odd, hardware encode would fail.
394 // For the safety of encode process, only those of even desiredSize are allowed to generate througth picture.
395 bool shouldGeneratePicture = data_.loaderOpts.isHdr && imageSource->IsHdrImage() &&
396 data_.lcdDesiredSize.width % 2 == 0 && data_.lcdDesiredSize.height % 2 == 0;
397 bool isGenerateSucceed = shouldGeneratePicture ?
398 GeneratePictureSource(imageSource, targetSize) : GeneratePixelMapSource(imageSource, sourceSize, targetSize);
399 if (!isGenerateSucceed && shouldGeneratePicture) {
400 MEDIA_ERR_LOG("SourceLoader generate picture source failed, generate pixelmap instead, path:%{public}s",
401 DfxUtils::GetSafePath(data_.path).c_str());
402 std::unique_ptr<ImageSource> retryImageSource = LoadImageSource(sourcePath, err);
403 if (err != E_OK || retryImageSource == nullptr) {
404 MEDIA_ERR_LOG("LoadImageSource retryImageSource error:%{public}d, errorno:%{public}d", err, errno);
405 return false;
406 }
407 isGenerateSucceed = GeneratePixelMapSource(retryImageSource, sourceSize, targetSize);
408 }
409 if (!isGenerateSucceed) {
410 MEDIA_ERR_LOG("ImagePixelMap generate failed, path:%{public}s", DfxUtils::GetSafePath(data_.path).c_str());
411 return false;
412 }
413 tracer.Finish();
414
415 if (data_.orientation == 0) {
416 err = imageSource->GetImagePropertyInt(0, PHOTO_DATA_IMAGE_ORIENTATION, data_.orientation);
417 if (err != E_OK) {
418 MEDIA_ERR_LOG("SourceLoader Failed to get ImageProperty, path: %{public}s",
419 DfxUtils::GetSafePath(data_.path).c_str());
420 }
421 }
422
423 if (data_.mediaType == MEDIA_TYPE_VIDEO) {
424 data_.orientation = 0;
425 }
426 DfxManager::GetInstance()->HandleHighMemoryThumbnail(data_.path, MEDIA_TYPE_IMAGE, imageInfo.size.width,
427 imageInfo.size.height);
428 return true;
429 }
430
CreateSourcePixelMap()431 bool SourceLoader::CreateSourcePixelMap()
432 {
433 if (state_ == SourceState::LOCAL_ORIGIN && data_.mediaType == MEDIA_TYPE_VIDEO) {
434 return CreateVideoFramePixelMap();
435 }
436
437 if (GetSourcePath == nullptr) {
438 MEDIA_ERR_LOG("GetSourcePath is nullptr.");
439 return false;
440 }
441
442 std::string sourcePath = GetSourcePath(data_, error_);
443 if (sourcePath.empty()) {
444 MEDIA_ERR_LOG("SourceLoader source path unavailable, status:%{public}s, path:%{public}s",
445 STATE_NAME_MAP.at(state_).c_str(), DfxUtils::GetSafePath(data_.path).c_str());
446 return false;
447 }
448 if (!CreateImagePixelMap(sourcePath)) {
449 MEDIA_ERR_LOG("SourceLoader fail to create image pixel map, status:%{public}s, path:%{public}s",
450 STATE_NAME_MAP.at(state_).c_str(), DfxUtils::GetSafePath(data_.path).c_str());
451 return false;
452 }
453 return true;
454 }
455
CreateSourceFromOriginalPhotoPicture()456 bool SourceLoader::CreateSourceFromOriginalPhotoPicture()
457 {
458 CHECK_AND_RETURN_RET_LOG(data_.originalPhotoPicture != nullptr, false, "OriginalPhotoPicture is nullptr");
459 if (data_.loaderOpts.decodeInThumbSize ||
460 !ThumbnailImageFrameWorkUtils::IsSupportCopyPixelMap(data_.originalPhotoPicture->GetMainPixel())) {
461 data_.originalPhotoPicture = nullptr;
462 return false;
463 }
464
465 int32_t orientation = 0;
466 int32_t err = ThumbnailImageFrameWorkUtils::GetPictureOrientation(
467 data_.originalPhotoPicture, orientation);
468 CHECK_AND_WARN_LOG(err == E_OK, "SourceLoader Failed to get picture orientation, path: %{public}s",
469 DfxUtils::GetSafePath(data_.path).c_str());
470
471 bool isCreateSource = false;
472 if (data_.originalPhotoPicture->GetGainmapPixelMap() == nullptr) {
473 isCreateSource = CreateSourceWithOriginalPictureMainPixel();
474 } else {
475 isCreateSource = CreateSourceWithWholeOriginalPicture();
476 }
477 CHECK_AND_RETURN_RET_LOG(isCreateSource, false, "Create source failed");
478 if (data_.orientation == 0 && orientation > 0) {
479 data_.orientation = orientation;
480 }
481 if (data_.mediaType == MEDIA_TYPE_VIDEO) {
482 data_.orientation = 0;
483 }
484 return true;
485 }
486
CreateSourceWithWholeOriginalPicture()487 bool SourceLoader::CreateSourceWithWholeOriginalPicture()
488 {
489 CHECK_AND_RETURN_RET_LOG(data_.originalPhotoPicture != nullptr, false, "OriginalPhotoPicture is nullptr");
490 MediaLibraryTracer tracer;
491 tracer.Start("CreateSourceWithWholeOriginalPicture");
492
493 std::shared_ptr<Picture> picture = ThumbnailImageFrameWorkUtils::CopyPictureSource(data_.originalPhotoPicture);
494 data_.originalPhotoPicture = nullptr;
495 CHECK_AND_RETURN_RET_LOG(picture != nullptr, false, "CopyPictureSource failed");
496 auto pixelMap = picture->GetMainPixel();
497 auto gainMap = picture->GetGainmapPixelMap();
498 CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr && gainMap != nullptr, false,
499 "PixelMap or gainMap is nullptr");
500 CHECK_AND_RETURN_RET_LOG(pixelMap->GetWidth() * pixelMap->GetHeight() != 0, false,
501 "Picture is invalid");
502
503 Size originSize = { .width = pixelMap->GetWidth(),
504 .height = pixelMap->GetHeight() };
505 Size targetSize = ConvertDecodeSize(data_, originSize, desiredSize_);
506
507 float widthScale = (1.0f * targetSize.width) / pixelMap->GetWidth();
508 float heightScale = (1.0f * targetSize.height) / pixelMap->GetHeight();
509 pixelMap->resize(widthScale, heightScale);
510 gainMap->resize(widthScale, heightScale);
511 data_.source.SetPicture(picture);
512
513 DfxManager::GetInstance()->HandleHighMemoryThumbnail(data_.path, data_.mediaType, originSize.width,
514 originSize.height);
515 return true;
516 }
517
CreateSourceWithOriginalPictureMainPixel()518 bool SourceLoader::CreateSourceWithOriginalPictureMainPixel()
519 {
520 CHECK_AND_RETURN_RET_LOG(data_.originalPhotoPicture != nullptr, false, "OriginalPhotoPicture is nullptr");
521 MediaLibraryTracer tracer;
522 tracer.Start("CreateSourceWithOriginalPictureMainPixel");
523 auto mainPixel = data_.originalPhotoPicture->GetMainPixel();
524 CHECK_AND_RETURN_RET_LOG(mainPixel != nullptr, false, "Main pixel is nullptr");
525 MEDIA_INFO_LOG("Main pixelMap format:%{public}d isHdr:%{public}d allocatorType:%{public}d, "
526 "size: %{public}d * %{public}d", mainPixel->GetPixelFormat(), mainPixel->IsHdr(),
527 mainPixel->GetAllocatorType(), mainPixel->GetWidth(), mainPixel->GetHeight());
528
529 std::shared_ptr<PixelMap> pixelMap = ThumbnailImageFrameWorkUtils::CopyPixelMapSource(mainPixel);
530 mainPixel = nullptr;
531 data_.originalPhotoPicture = nullptr;
532 CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, false, "Copy main pixel failed");
533 CHECK_AND_RETURN_RET_LOG(pixelMap->GetWidth() * pixelMap->GetHeight() != 0, false,
534 "PixelMap is invalid");
535
536 Size originSize = { .width = pixelMap->GetWidth(),
537 .height = pixelMap->GetHeight() };
538 Size targetSize = ConvertDecodeSize(data_, originSize, desiredSize_);
539
540 float widthScale = (1.0f * targetSize.width) / pixelMap->GetWidth();
541 float heightScale = (1.0f * targetSize.height) / pixelMap->GetHeight();
542 pixelMap->resize(widthScale, heightScale);
543 data_.source.SetPixelMap(pixelMap);
544
545 DfxManager::GetInstance()->HandleHighMemoryThumbnail(data_.path, data_.mediaType, originSize.width,
546 originSize.height);
547 return true;
548 }
549
RunLoading()550 bool SourceLoader::RunLoading()
551 {
552 if (data_.originalPhotoPicture != nullptr && CreateSourceFromOriginalPhotoPicture()) {
553 return true;
554 }
555
556 if (data_.loaderOpts.loadingStates.empty()) {
557 MEDIA_ERR_LOG("source loading run loading failed, the given states is empty");
558 return false;
559 }
560 state_ = SourceState::BEGIN;
561 data_.source.ClearAllSource();
562 SetCurrentStateFunction();
563
564 // always check state not final after every state switch
565 while (!IsFinal()) {
566 SwitchToNextState(data_, state_);
567 MEDIA_DEBUG_LOG("SourceLoader new cycle status:%{public}s", STATE_NAME_MAP.at(state_).c_str());
568 if (IsFinal()) {
569 break;
570 }
571 SetCurrentStateFunction();
572 do {
573 if (state_ < SourceState::CLOUD_THUMB) {
574 data_.stats.sourceType = LoadSourceType::LOCAL_PHOTO;
575 } else if (state_ >= SourceState::CLOUD_THUMB && state_ <= SourceState::CLOUD_ORIGIN) {
576 data_.stats.sourceType = static_cast<LoadSourceType>(state_);
577 }
578
579 if (!CreateSourcePixelMap()) {
580 MEDIA_ERR_LOG("SourceLoader fail to create source pixel map, status:%{public}s, path:%{public}s",
581 STATE_NAME_MAP.at(state_).c_str(), DfxUtils::GetSafePath(data_.path).c_str());
582 break;
583 }
584 state_ = SourceState::FINISH;
585 DfxManager::GetInstance()->HandleThumbnailGeneration(data_.stats);
586 } while (0);
587 };
588 if (state_ == SourceState::ERROR) {
589 data_.source.ClearAllSource();
590 }
591 if (data_.source.IsEmptySource()) {
592 MEDIA_ERR_LOG("SourceLoader source is nullptr, status:%{public}s, path:%{public}s",
593 STATE_NAME_MAP.at(state_).c_str(), DfxUtils::GetSafePath(data_.path).c_str());
594 return false;
595 }
596 return true;
597 }
598
IsSizeAcceptable(std::unique_ptr<ImageSource> & imageSource,ImageInfo & imageInfo)599 bool SourceLoader::IsSizeAcceptable(std::unique_ptr<ImageSource>& imageSource, ImageInfo& imageInfo)
600 {
601 uint32_t err = imageSource->GetImageInfo(0, imageInfo);
602 if (err != E_OK) {
603 DfxManager::GetInstance()->HandleThumbnailError(data_.path, DfxType::IMAGE_SOURCE_GET_INFO, err);
604 error_ = E_ERR;
605 return false;
606 }
607
608 if (IsSizeLargeEnough == nullptr) {
609 MEDIA_ERR_LOG("IsSizeLargeEnough is nullptr.");
610 return false;
611 }
612
613 int32_t minSize = imageInfo.size.width < imageInfo.size.height ? imageInfo.size.width : imageInfo.size.height;
614 if (!IsSizeLargeEnough(data_, minSize)) {
615 MEDIA_DEBUG_LOG("SourceLoader size not acceptable, width:%{public}d, height:%{public}d", imageInfo.size.width,
616 imageInfo.size.height);
617 return false;
618 }
619
620 data_.stats.sourceWidth = imageInfo.size.width;
621 data_.stats.sourceHeight = imageInfo.size.height;
622 return true;
623 }
624
IsFinal()625 bool SourceLoader::IsFinal()
626 {
627 if (error_ != E_OK) {
628 state_ = SourceState::ERROR;
629 data_.stats.errorCode = error_;
630 return true;
631 }
632 if (state_ == SourceState::FINISH) {
633 return true;
634 }
635 return false;
636 }
637
GetSourcePath(ThumbnailData & data,int32_t & error)638 std::string LocalThumbSource::GetSourcePath(ThumbnailData &data, int32_t &error)
639 {
640 std::string tmpPath = GetLocalThumbnailPath(data.path, THUMBNAIL_THUMB_SUFFIX);
641 if (!IsLocalSourceAvailable(tmpPath)) {
642 return "";
643 }
644 return tmpPath;
645 }
646
IsSizeLargeEnough(ThumbnailData & data,int32_t & minSize)647 bool LocalThumbSource::IsSizeLargeEnough(ThumbnailData &data, int32_t &minSize)
648 {
649 if (minSize < SHORT_SIDE_THRESHOLD) {
650 return false;
651 }
652 return true;
653 }
654
GetSourcePath(ThumbnailData & data,int32_t & error)655 std::string LocalLcdSource::GetSourcePath(ThumbnailData &data, int32_t &error)
656 {
657 std::string tmpPath = GetLocalThumbnailPath(data.path, THUMBNAIL_LCD_SUFFIX);
658 if (!IsLocalSourceAvailable(tmpPath)) {
659 return "";
660 }
661 return tmpPath;
662 }
663
IsSizeLargeEnough(ThumbnailData & data,int32_t & minSize)664 bool LocalLcdSource::IsSizeLargeEnough(ThumbnailData &data, int32_t &minSize)
665 {
666 if (minSize < SHORT_SIDE_THRESHOLD) {
667 return false;
668 }
669 return true;
670 }
671
GetSourcePath(ThumbnailData & data,int32_t & error)672 std::string LocalOriginSource::GetSourcePath(ThumbnailData &data, int32_t &error)
673 {
674 std::string tmpPath = GetLocalThumbnailPath(data.path, "");
675 if (!IsLocalSourceAvailable(tmpPath)) {
676 return "";
677 }
678 return tmpPath;
679 }
680
IsSizeLargeEnough(ThumbnailData & data,int32_t & minSize)681 bool LocalOriginSource::IsSizeLargeEnough(ThumbnailData &data, int32_t &minSize)
682 {
683 return true;
684 }
685
GetSourcePath(ThumbnailData & data,int32_t & error)686 std::string CloudThumbSource::GetSourcePath(ThumbnailData &data, int32_t &error)
687 {
688 std::string tmpPath = data.orientation != 0 ?
689 GetThumbnailPath(data.path, THUMBNAIL_THUMB_EX_SUFFIX) : GetThumbnailPath(data.path, THUMBNAIL_THUMB_SUFFIX);
690 int64_t startTime = MediaFileUtils::UTCTimeMilliSeconds();
691 if (!IsCloudSourceAvailable(tmpPath)) {
692 return "";
693 }
694 int32_t totalCost = static_cast<int32_t>(MediaFileUtils::UTCTimeMilliSeconds() - startTime);
695 data.stats.openThumbCost = totalCost;
696 return tmpPath;
697 }
698
IsSizeLargeEnough(ThumbnailData & data,int32_t & minSize)699 bool CloudThumbSource::IsSizeLargeEnough(ThumbnailData &data, int32_t &minSize)
700 {
701 int minDesiredSide = ParseDesiredMinSide(data.loaderOpts.desiredType);
702 if (minSize < minDesiredSide) {
703 return false;
704 }
705 return true;
706 }
707
GetSourcePath(ThumbnailData & data,int32_t & error)708 std::string CloudLcdSource::GetSourcePath(ThumbnailData &data, int32_t &error)
709 {
710 std::string tmpPath;
711 if (data.orientation != 0) {
712 tmpPath = GetLcdExPath(data.path);
713 } else {
714 tmpPath = GetThumbnailPath(data.path, THUMBNAIL_LCD_SUFFIX);
715 }
716 int64_t startTime = MediaFileUtils::UTCTimeMilliSeconds();
717 if (!IsCloudSourceAvailable(tmpPath)) {
718 return "";
719 }
720 int32_t totalCost = static_cast<int32_t>(MediaFileUtils::UTCTimeMilliSeconds() - startTime);
721 data.stats.openLcdCost = totalCost;
722 return tmpPath;
723 }
724
IsSizeLargeEnough(ThumbnailData & data,int32_t & minSize)725 bool CloudLcdSource::IsSizeLargeEnough(ThumbnailData &data, int32_t &minSize)
726 {
727 if (data.mediaType == MEDIA_TYPE_VIDEO) {
728 return true;
729 }
730 int photoShorterSide = data.photoWidth < data.photoHeight ? data.photoWidth : data.photoHeight;
731 if (photoShorterSide != 0 && photoShorterSide < SHORT_SIDE_THRESHOLD) {
732 return true;
733 }
734 if (minSize < SHORT_SIDE_THRESHOLD) {
735 return false;
736 }
737 return true;
738 }
739
GetSourcePath(ThumbnailData & data,int32_t & error)740 std::string CloudOriginSource::GetSourcePath(ThumbnailData &data, int32_t &error)
741 {
742 if (data.mediaType == MEDIA_TYPE_VIDEO) {
743 // avoid opening cloud origin video file.
744 MEDIA_ERR_LOG("avoid opening cloud origin video file path:%{public}s",
745 DfxUtils::GetSafePath(data.path).c_str());
746 return "";
747 }
748 int64_t startTime = MediaFileUtils::UTCTimeMilliSeconds();
749 if (!IsCloudSourceAvailable(data.path)) {
750 return "";
751 }
752 int32_t totalCost = static_cast<int32_t>(MediaFileUtils::UTCTimeMilliSeconds() - startTime);
753 data.stats.openOriginCost = totalCost;
754 return data.path;
755 }
756
IsSizeLargeEnough(ThumbnailData & data,int32_t & minSize)757 bool CloudOriginSource::IsSizeLargeEnough(ThumbnailData &data, int32_t &minSize)
758 {
759 return true;
760 }
761
762 } // namespace Media
763 } // namespace OHOS