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