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