• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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