1 /*
2  * Copyright (C) 2022-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 #define MLOG_TAG "Thumbnail"
16 
17 #include "ithumbnail_helper.h"
18 
19 #include "ability_manager_client.h"
20 #include "background_task_mgr_helper.h"
21 #include "dfx_cloud_manager.h"
22 #include "dfx_utils.h"
23 #include "hitrace_meter.h"
24 #include "ipc_skeleton.h"
25 #include "media_column.h"
26 #include "medialibrary_errno.h"
27 #include "medialibrary_kvstore_manager.h"
28 #include "medialibrary_notify.h"
29 #include "medialibrary_photo_operations.h"
30 #include "medialibrary_type_const.h"
31 #include "media_file_utils.h"
32 #include "media_log.h"
33 #include "medialibrary_rdbstore.h"
34 #include "medialibrary_unistore_manager.h"
35 #include "post_event_utils.h"
36 #include "result_set_utils.h"
37 #include "rdb_predicates.h"
38 #include "rdb_helper.h"
39 #include "single_kvstore.h"
40 #include "thumbnail_const.h"
41 #include "thumbnail_generate_worker_manager.h"
42 #include "thumbnail_source_loading.h"
43 
44 using namespace std;
45 using namespace OHOS::DistributedKv;
46 using namespace OHOS::NativeRdb;
47 
48 namespace OHOS {
49 namespace Media {
50 
StoreThumbnailSize(const ThumbRdbOpt& opts, const ThumbnailData& data)51 void StoreThumbnailSize(const ThumbRdbOpt& opts, const ThumbnailData& data)
52 {
53     std::string photoId = opts.row.empty() ? data.id : opts.row;
54     std::string tmpPath = opts.path.empty() ? data.path : opts.path;
55     if (tmpPath.find(ROOT_MEDIA_DIR + PHOTO_BUCKET) != string::npos) {
56         MediaLibraryPhotoOperations::StoreThumbnailSize(photoId, tmpPath);
57     }
58 }
59 
CreateLcdAndThumbnail(std::shared_ptr<ThumbnailTaskData> &data)60 void IThumbnailHelper::CreateLcdAndThumbnail(std::shared_ptr<ThumbnailTaskData> &data)
61 {
62     if (data == nullptr) {
63         MEDIA_ERR_LOG("CreateLcdAndThumbnail failed, data is null");
64         return;
65     }
66     bool isSuccess = DoCreateLcdAndThumbnail(data->opts_, data->thumbnailData_);
67     if (isSuccess && !data->thumbnailData_.tracks.empty() && (data->thumbnailData_.trigger == "0")) {
68         UpdateHighlightDbState(data->opts_, data->thumbnailData_);
69     }
70     UpdateThumbnailState(data->opts_, data->thumbnailData_, isSuccess);
71     ThumbnailUtils::RecordCostTimeAndReport(data->thumbnailData_.stats);
72 }
73 
CreateLcd(std::shared_ptr<ThumbnailTaskData> &data)74 void IThumbnailHelper::CreateLcd(std::shared_ptr<ThumbnailTaskData> &data)
75 {
76     if (data == nullptr) {
77         MEDIA_ERR_LOG("CreateLcd failed, data is null");
78         return;
79     }
80     DoCreateLcd(data->opts_, data->thumbnailData_);
81 }
82 
CreateThumbnail(std::shared_ptr<ThumbnailTaskData> &data)83 void IThumbnailHelper::CreateThumbnail(std::shared_ptr<ThumbnailTaskData> &data)
84 {
85     if (data == nullptr) {
86         MEDIA_ERR_LOG("CreateThumbnail failed, data is null");
87         return;
88     }
89     bool isSuccess = DoCreateThumbnail(data->opts_, data->thumbnailData_);
90     UpdateThumbnailState(data->opts_, data->thumbnailData_, isSuccess);
91     ThumbnailUtils::RecordCostTimeAndReport(data->thumbnailData_.stats);
92 }
93 
CreateAstc(std::shared_ptr<ThumbnailTaskData> &data)94 void IThumbnailHelper::CreateAstc(std::shared_ptr<ThumbnailTaskData> &data)
95 {
96     if (data == nullptr) {
97         MEDIA_ERR_LOG("CreateAstc failed, data is null");
98         return;
99     }
100     bool isSuccess = DoCreateAstc(data->opts_, data->thumbnailData_);
101     UpdateThumbnailState(data->opts_, data->thumbnailData_, isSuccess);
102     ThumbnailUtils::RecordCostTimeAndReport(data->thumbnailData_.stats);
103 }
104 
CreateAstcEx(std::shared_ptr<ThumbnailTaskData> &data)105 void IThumbnailHelper::CreateAstcEx(std::shared_ptr<ThumbnailTaskData> &data)
106 {
107     if (data == nullptr) {
108         MEDIA_ERR_LOG("CreateAstcEx failed, data is null");
109         return;
110     }
111     bool isSuccess = DoCreateAstcEx(data->opts_, data->thumbnailData_);
112     UpdateThumbnailState(data->opts_, data->thumbnailData_, isSuccess);
113     ThumbnailUtils::RecordCostTimeAndReport(data->thumbnailData_.stats);
114 }
115 
DeleteMonthAndYearAstc(std::shared_ptr<ThumbnailTaskData> &data)116 void IThumbnailHelper::DeleteMonthAndYearAstc(std::shared_ptr<ThumbnailTaskData> &data)
117 {
118     if (data == nullptr) {
119         MEDIA_ERR_LOG("DeleteMonthAndYearAstc failed, data is null");
120         return;
121     }
122     if (!ThumbnailUtils::DoDeleteMonthAndYearAstc(data->opts_)) {
123         MEDIA_ERR_LOG("DeleteMonthAndYearAstc failed, key is %{public}s and %{public}s",
124             data->opts_.row.c_str(), data->opts_.dateTaken.c_str());
125     }
126 }
127 
UpdateAstcDateTaken(std::shared_ptr<ThumbnailTaskData> &data)128 void IThumbnailHelper::UpdateAstcDateTaken(std::shared_ptr<ThumbnailTaskData> &data)
129 {
130     if (data == nullptr) {
131         MEDIA_ERR_LOG("UpdateAstcDateTaken failed, data is null");
132         return;
133     }
134     if (!ThumbnailUtils::DoUpdateAstcDateTaken(data->opts_, data->thumbnailData_)) {
135         MEDIA_ERR_LOG("UpdateAstcDateTaken failed, key is %{public}s and %{public}s",
136             data->opts_.row.c_str(), data->thumbnailData_.dateTaken.c_str());
137     }
138 }
139 
AddThumbnailGenerateTask(ThumbnailGenerateExecute executor, ThumbRdbOpt &opts, ThumbnailData &thumbData, const ThumbnailTaskType &taskType, const ThumbnailTaskPriority &priority)140 void IThumbnailHelper::AddThumbnailGenerateTask(ThumbnailGenerateExecute executor, ThumbRdbOpt &opts,
141     ThumbnailData &thumbData, const ThumbnailTaskType &taskType, const ThumbnailTaskPriority &priority)
142 {
143     std::shared_ptr<ThumbnailGenerateWorker> thumbnailWorker =
144         ThumbnailGenerateWorkerManager::GetInstance().GetThumbnailWorker(taskType);
145     if (thumbnailWorker == nullptr) {
146         MEDIA_ERR_LOG("thumbnailWorker is null");
147         return;
148     }
149 
150     std::shared_ptr<ThumbnailTaskData> taskData = std::make_shared<ThumbnailTaskData>(opts, thumbData);
151     std::shared_ptr<ThumbnailGenerateTask> task = std::make_shared<ThumbnailGenerateTask>(executor, taskData);
152     thumbnailWorker->AddTask(task, priority);
153 }
154 
AddThumbnailGenBatchTask(ThumbnailGenerateExecute executor, ThumbRdbOpt &opts, ThumbnailData &thumbData, int32_t requestId)155 void IThumbnailHelper::AddThumbnailGenBatchTask(ThumbnailGenerateExecute executor,
156     ThumbRdbOpt &opts, ThumbnailData &thumbData, int32_t requestId)
157 {
158     std::shared_ptr<ThumbnailGenerateWorker> thumbnailWorker =
159         ThumbnailGenerateWorkerManager::GetInstance().GetThumbnailWorker(ThumbnailTaskType::FOREGROUND);
160     if (thumbnailWorker == nullptr) {
161         MEDIA_ERR_LOG("thumbnailWorker is null");
162         return;
163     }
164 
165     std::shared_ptr<ThumbnailTaskData> taskData = std::make_shared<ThumbnailTaskData>(opts, thumbData, requestId);
166     std::shared_ptr<ThumbnailGenerateTask> task = std::make_shared<ThumbnailGenerateTask>(executor, taskData);
167     thumbnailWorker->AddTask(task, ThumbnailTaskPriority::LOW);
168 }
169 
ThumbnailWait(bool release)170 ThumbnailWait::ThumbnailWait(bool release) : needRelease_(release)
171 {}
172 
~ThumbnailWait()173 ThumbnailWait::~ThumbnailWait()
174 {
175     if (needRelease_) {
176         Notify();
177     }
178 }
179 
180 ThumbnailMap ThumbnailWait::thumbnailMap_;
181 std::shared_mutex ThumbnailWait::mutex_;
182 
WaitFor(const shared_ptr<ThumbnailSyncStatus> &thumbnailWait, int waitMs, unique_lock<mutex> &lck)183 static bool WaitFor(const shared_ptr<ThumbnailSyncStatus> &thumbnailWait, int waitMs, unique_lock<mutex> &lck)
184 {
185     bool ret = thumbnailWait->cond_.wait_for(lck, chrono::milliseconds(waitMs),
186         [thumbnailWait]() { return thumbnailWait->isSyncComplete_; });
187     if (!ret) {
188         MEDIA_INFO_LOG("IThumbnailHelper::Wait wait for lock timeout");
189     }
190     return ret;
191 }
192 
InsertAndWait(const string &id, ThumbnailType type)193 WaitStatus ThumbnailWait::InsertAndWait(const string &id, ThumbnailType type)
194 {
195     id_ = id + ThumbnailUtils::GetThumbnailSuffix(type);
196     unique_lock<shared_mutex> writeLck(mutex_);
197     auto iter = thumbnailMap_.find(id_);
198     if (iter != thumbnailMap_.end()) {
199         auto thumbnailWait = iter->second;
200         unique_lock<mutex> lck(thumbnailWait->mtx_);
201         writeLck.unlock();
202         MEDIA_INFO_LOG("Waiting for thumbnail generation, id: %{public}s", id_.c_str());
203         thumbnailWait->cond_.wait(lck, [weakPtr = weak_ptr(thumbnailWait)]() {
204             if (auto sharedPtr = weakPtr.lock()) {
205                 return sharedPtr->isSyncComplete_;
206             } else {
207                 return true;
208             }
209         });
210         if (thumbnailWait->isCreateThumbnailSuccess_) {
211             MEDIA_INFO_LOG("Thumbnail generated successfully");
212             return WaitStatus::WAIT_SUCCESS;
213         } else {
214             MEDIA_ERR_LOG("Failed to generate thumbnail");
215             return WaitStatus::WAIT_FAILED;
216         }
217     } else {
218         shared_ptr<ThumbnailSyncStatus> thumbnailWait = make_shared<ThumbnailSyncStatus>();
219         thumbnailMap_.insert(ThumbnailMap::value_type(id_, thumbnailWait));
220         return WaitStatus::INSERT;
221     }
222 }
223 
CheckCloudReadResult(CloudLoadType cloudLoadType, CloudReadStatus status)224 WaitStatus CheckCloudReadResult(CloudLoadType cloudLoadType, CloudReadStatus status)
225 {
226     switch (status) {
227         case CloudReadStatus::FAIL:
228             MEDIA_INFO_LOG("Fail to cloud read thumbnail, type: %{public}d", cloudLoadType);
229             return WaitStatus::WAIT_FAILED;
230             break;
231         case CloudReadStatus::SUCCESS:
232             MEDIA_INFO_LOG("Success to cloud read thumbnail, type: %{public}d", cloudLoadType);
233             return WaitStatus::WAIT_SUCCESS;
234             break;
235         case CloudReadStatus::START:
236             MEDIA_INFO_LOG("Continue to cloud read thumbnail, type: %{public}d", cloudLoadType);
237             return WaitStatus::WAIT_CONTINUE;
238             break;
239         default:
240             break;
241     }
242     return WaitStatus::WAIT_FAILED;
243 }
244 
CloudInsertAndWait(const string &id, CloudLoadType cloudLoadType)245 WaitStatus ThumbnailWait::CloudInsertAndWait(const string &id, CloudLoadType cloudLoadType)
246 {
247     id_ = id + ".cloud";
248     unique_lock<shared_mutex> writeLck(mutex_);
249     auto iter = thumbnailMap_.find(id_);
250     if (iter != thumbnailMap_.end()) {
251         auto thumbnailWait = iter->second;
252         unique_lock<mutex> lck(thumbnailWait->mtx_);
253         writeLck.unlock();
254         MEDIA_INFO_LOG("Waiting for thumbnail generation, id: %{public}s", id_.c_str());
255         thumbnailWait->cond_.wait(lck, [weakPtr = weak_ptr(thumbnailWait)]() {
256             if (auto sharedPtr = weakPtr.lock()) {
257                 return sharedPtr->isSyncComplete_;
258             } else {
259                 return true;
260             }
261         });
262         thumbnailWait->isSyncComplete_ = false;
263         thumbnailWait->cloudLoadType_ = cloudLoadType;
264         unique_lock<shared_mutex> evokeLck(mutex_);
265         thumbnailMap_.emplace(ThumbnailMap::value_type(id_, thumbnailWait));
266         evokeLck.unlock();
267 
268         if (cloudLoadType == CLOUD_DOWNLOAD) {
269             MEDIA_INFO_LOG("Continue to generate thumbnail");
270             return WaitStatus::WAIT_CONTINUE;
271         }
272         if (cloudLoadType == CLOUD_READ_THUMB) {
273             return CheckCloudReadResult(cloudLoadType, thumbnailWait->CloudLoadThumbnailStatus_);
274         }
275         if (cloudLoadType == CLOUD_READ_LCD) {
276             return CheckCloudReadResult(cloudLoadType, thumbnailWait->CloudLoadLcdStatus_);
277         }
278         MEDIA_INFO_LOG("Cloud generate thumbnail successfully");
279         return WaitStatus::WAIT_SUCCESS;
280     } else {
281         shared_ptr<ThumbnailSyncStatus> thumbnailWait = make_shared<ThumbnailSyncStatus>();
282         thumbnailWait->cloudLoadType_ = cloudLoadType;
283         thumbnailMap_.insert(ThumbnailMap::value_type(id_, thumbnailWait));
284         return WaitStatus::INSERT;
285     }
286 }
287 
CheckAndWait(const string &id, bool isLcd)288 void ThumbnailWait::CheckAndWait(const string &id, bool isLcd)
289 {
290     id_ = id;
291 
292     if (isLcd) {
293         id_ += THUMBNAIL_LCD_SUFFIX;
294     } else {
295         id_ += THUMBNAIL_THUMB_SUFFIX;
296     }
297     shared_lock<shared_mutex> readLck(mutex_);
298     auto iter = thumbnailMap_.find(id_);
299     if (iter != thumbnailMap_.end()) {
300         auto thumbnailWait = iter->second;
301         unique_lock<mutex> lck(thumbnailWait->mtx_);
302         readLck.unlock();
303         WaitFor(thumbnailWait, WAIT_FOR_MS, lck);
304     }
305 }
306 
UpdateThumbnailMap()307 void ThumbnailWait::UpdateThumbnailMap()
308 {
309     unique_lock<shared_mutex> writeLck(mutex_);
310     auto iter = thumbnailMap_.find(id_);
311     if (iter != thumbnailMap_.end()) {
312         auto thumbnailWait = iter->second;
313         {
314             unique_lock<mutex> lck(thumbnailWait->mtx_);
315             writeLck.unlock();
316             thumbnailWait->isCreateThumbnailSuccess_ = true;
317         }
318     } else {
319         MEDIA_ERR_LOG("Update ThumbnailMap failed, id: %{public}s", id_.c_str());
320     }
321 }
322 
UpdateCloudLoadThumbnailMap(CloudLoadType cloudLoadType, bool isLoadSuccess)323 void ThumbnailWait::UpdateCloudLoadThumbnailMap(CloudLoadType cloudLoadType, bool isLoadSuccess)
324 {
325     unique_lock<shared_mutex> writeLck(mutex_);
326     auto iter = thumbnailMap_.find(id_);
327     if (iter != thumbnailMap_.end()) {
328         auto thumbnailWait = iter->second;
329         {
330             unique_lock<mutex> lck(thumbnailWait->mtx_);
331             writeLck.unlock();
332             switch (cloudLoadType) {
333                 case CLOUD_READ_THUMB:
334                     thumbnailWait->CloudLoadThumbnailStatus_ =
335                         isLoadSuccess ? CloudReadStatus::SUCCESS : CloudReadStatus::FAIL;
336                     break;
337                 case CLOUD_READ_LCD:
338                     thumbnailWait->CloudLoadLcdStatus_ =
339                         isLoadSuccess ? CloudReadStatus::SUCCESS : CloudReadStatus::FAIL;
340                     break;
341                 case CLOUD_DOWNLOAD:
342                     thumbnailWait->CloudLoadThumbnailStatus_ =
343                         isLoadSuccess ? CloudReadStatus::SUCCESS : CloudReadStatus::FAIL;
344                     thumbnailWait->CloudLoadLcdStatus_ =
345                         isLoadSuccess ? CloudReadStatus::SUCCESS : CloudReadStatus::FAIL;
346                     break;
347                 default:
348                     break;
349             }
350         }
351     } else {
352         MEDIA_ERR_LOG("Update CloudLoadThumbnailMap failed, id: %{public}s", id_.c_str());
353     }
354 }
355 
Notify()356 void ThumbnailWait::Notify()
357 {
358     unique_lock<shared_mutex> writeLck(mutex_);
359     auto iter = thumbnailMap_.find(id_);
360     if (iter != thumbnailMap_.end()) {
361         auto thumbnailWait = iter->second;
362         thumbnailMap_.erase(iter);
363         {
364             unique_lock<mutex> lck(thumbnailWait->mtx_);
365             writeLck.unlock();
366             thumbnailWait->isSyncComplete_ = true;
367         }
368         if (thumbnailWait->cloudLoadType_ == CloudLoadType::NONE) {
369             thumbnailWait->cond_.notify_all();
370         } else {
371             thumbnailWait->cond_.notify_one();
372         }
373     }
374 }
375 
TryLoadSource(ThumbRdbOpt &opts, ThumbnailData &data)376 bool IThumbnailHelper::TryLoadSource(ThumbRdbOpt &opts, ThumbnailData &data)
377 {
378     if (data.source != nullptr) {
379         return true;
380     }
381 
382     if (data.loaderOpts.loadingStates.empty()) {
383         MEDIA_ERR_LOG("try load source failed, the loading source states is empty.");
384         return false;
385     }
386 
387     if (!ThumbnailUtils::LoadSourceImage(data)) {
388         if (opts.path.empty()) {
389             MEDIA_ERR_LOG("LoadSourceImage faild, %{public}s", DfxUtils::GetSafePath(data.path).c_str());
390             VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN},
391                 {KEY_OPT_FILE, data.path}, {KEY_OPT_TYPE, OptType::THUMB}};
392             PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
393             return false;
394         } else {
395             opts.path = "";
396             ThumbnailUtils::GetThumbnailInfo(opts, data);
397             if (access(data.path.c_str(), F_OK) == 0) {
398                 return true;
399             }
400             if (!ThumbnailUtils::LoadSourceImage(data)) {
401                 VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__},
402                     {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN}, {KEY_OPT_FILE, data.path}, {KEY_OPT_TYPE, OptType::THUMB}};
403                 PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
404                 return false;
405             }
406         }
407     }
408     return true;
409 }
410 
DoCreateLcd(ThumbRdbOpt &opts, ThumbnailData &data)411 bool IThumbnailHelper::DoCreateLcd(ThumbRdbOpt &opts, ThumbnailData &data)
412 {
413     ThumbnailWait thumbnailWait(true);
414     auto ret = thumbnailWait.InsertAndWait(data.id, ThumbnailType::LCD);
415     if (ret != WaitStatus::INSERT) {
416         return ret == WaitStatus::WAIT_SUCCESS;
417     }
418 
419     if (!IsCreateLcdSuccess(opts, data)) {
420         MEDIA_ERR_LOG("Fail to create lcd, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
421         return false;
422     }
423 
424     if (data.orientation != 0 && !IsCreateLcdExSuccess(opts, data)) {
425         MEDIA_ERR_LOG("Fail to create lcdEx, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
426     }
427     thumbnailWait.UpdateThumbnailMap();
428     return true;
429 }
430 
UpdateLcdDbState(ThumbRdbOpt &opts, ThumbnailData &data)431 void UpdateLcdDbState(ThumbRdbOpt &opts, ThumbnailData &data)
432 {
433     if (opts.table != PhotoColumn::PHOTOS_TABLE) {
434         return;
435     }
436     if (data.isNeedStoreSize) {
437         StoreThumbnailSize(opts, data);
438     }
439     data.isNeedStoreSize = true;
440     int err = 0;
441     if (!ThumbnailUtils::UpdateLcdInfo(opts, data, err)) {
442         MEDIA_INFO_LOG("UpdateLcdInfo faild err : %{public}d", err);
443     }
444 }
445 
UpdateHighlightDbState(ThumbRdbOpt &opts, ThumbnailData &data)446 void IThumbnailHelper::UpdateHighlightDbState(ThumbRdbOpt &opts, ThumbnailData &data)
447 {
448     if (opts.table != PhotoColumn::HIGHLIGHT_TABLE) {
449         return;
450     }
451     int err = 0;
452     if (!ThumbnailUtils::UpdateHighlightInfo(opts, data, err)) {
453         MEDIA_ERR_LOG("UpdateHighlightInfo faild err : %{public}d", err);
454     }
455 }
456 
IsCreateLcdSuccess(ThumbRdbOpt &opts, ThumbnailData &data)457 bool IThumbnailHelper::IsCreateLcdSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
458 {
459     data.loaderOpts.decodeInThumbSize = false;
460     data.loaderOpts.isHdr = true;
461     if (!TryLoadSource(opts, data)) {
462         MEDIA_ERR_LOG("load source is nullptr path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
463         return false;
464     }
465 
466     if (data.source == nullptr) {
467         MEDIA_ERR_LOG("Fail to create lcd, source is nullptr");
468         return false;
469     }
470 
471     shared_ptr<PixelMap> lcdSource = data.source;
472     int lcdDesiredWidth = data.orientation % FLAT_ANGLE == 0 ? data.lcdDesiredSize.width : data.lcdDesiredSize.height;
473     int lcdDesiredHeight = data.orientation % FLAT_ANGLE == 0 ? data.lcdDesiredSize.height : data.lcdDesiredSize.width;
474     if (lcdDesiredWidth != data.source->GetWidth()) {
475         MEDIA_INFO_LOG("Copy and resize data source for lcd desiredSize: %{public}s",
476             DfxUtils::GetSafePath(opts.path).c_str());
477         Media::InitializationOptions initOpts;
478         auto copySource = PixelMap::Create(*data.source, initOpts);
479         lcdSource = std::move(copySource);
480         float widthScale = (1.0f * lcdDesiredWidth) / data.source->GetWidth();
481         float heightScale = (1.0f * lcdDesiredHeight) / data.source->GetHeight();
482         lcdSource->scale(widthScale, heightScale);
483     }
484     if (!ThumbnailUtils::CompressImage(lcdSource, data.lcd, data.mediaType == MEDIA_TYPE_AUDIO, false, false)) {
485         MEDIA_ERR_LOG("CompressImage faild");
486         return false;
487     }
488 
489     int err = ThumbnailUtils::TrySaveFile(data, ThumbnailType::LCD);
490     if (err < 0) {
491         MEDIA_ERR_LOG("SaveLcd faild %{public}d", err);
492         return false;
493     }
494 
495     data.lcd.clear();
496     UpdateLcdDbState(opts, data);
497     return true;
498 }
499 
IsCreateLcdExSuccess(ThumbRdbOpt &opts, ThumbnailData &data)500 bool IThumbnailHelper::IsCreateLcdExSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
501 {
502     if (!data.isLocalFile) {
503         MEDIA_INFO_LOG("Create lcd when cloud loading, no need to create THM_EX, path: %{public}s, id: %{public}s",
504             DfxUtils::GetSafePath(opts.path).c_str(), data.id.c_str());
505         return false;
506     }
507 
508     string fileName = GetThumbnailPath(data.path, THUMBNAIL_LCD_EX_SUFFIX);
509     string dirName = MediaFileUtils::GetParentPath(fileName);
510     if (!MediaFileUtils::CreateDirectory(dirName)) {
511         MEDIA_ERR_LOG("Fail to create directory, fileName: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
512         return false;
513     }
514 
515     if (data.sourceEx == nullptr) {
516         MEDIA_ERR_LOG("Fail to create lcdEx, source is nullptr");
517         return false;
518     }
519     shared_ptr<PixelMap> lcdSourceEx = data.sourceEx;
520     if (data.lcdDesiredSize.width != data.sourceEx->GetWidth()) {
521         MEDIA_INFO_LOG("Copy and resize data source for lcdEx desiredSize: %{public}s",
522             DfxUtils::GetSafePath(opts.path).c_str());
523         Media::InitializationOptions initOpts;
524         auto copySource = PixelMap::Create(*data.sourceEx, initOpts);
525         lcdSourceEx = std::move(copySource);
526         float widthScale = (1.0f * data.lcdDesiredSize.width) / data.sourceEx->GetWidth();
527         float heightScale = (1.0f * data.lcdDesiredSize.height) / data.sourceEx->GetHeight();
528         lcdSourceEx->scale(widthScale, heightScale);
529     }
530     if (!ThumbnailUtils::CompressImage(lcdSourceEx, data.lcd, data.mediaType == MEDIA_TYPE_AUDIO)) {
531         MEDIA_ERR_LOG("CompressImage faild");
532         return false;
533     }
534 
535     int err = ThumbnailUtils::TrySaveFile(data, ThumbnailType::LCD_EX);
536     if (err < 0) {
537         MEDIA_ERR_LOG("SaveLcdEx faild %{public}d", err);
538         return false;
539     }
540     data.lcd.clear();
541     return true;
542 }
543 
GenThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, const ThumbnailType type)544 bool IThumbnailHelper::GenThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, const ThumbnailType type)
545 {
546     if (data.source == nullptr) {
547         MEDIA_ERR_LOG("source is nullptr when generate type: %{public}s", TYPE_NAME_MAP.at(type).c_str());
548         return false;
549     }
550 
551     if (type == ThumbnailType::THUMB || type == ThumbnailType::THUMB_ASTC) {
552         if (!ThumbnailUtils::CompressImage(data.source, type == ThumbnailType::THUMB ? data.thumbnail : data.thumbAstc,
553             false, type == ThumbnailType::THUMB_ASTC)) {
554             MEDIA_ERR_LOG("CompressImage faild id %{public}s", opts.row.c_str());
555             VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN},
556                 {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
557             PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
558             return false;
559         }
560     } else if (type == ThumbnailType::MTH_ASTC || type == ThumbnailType::YEAR_ASTC) {
561         if (!ThumbnailUtils::CheckDateTaken(opts, data)) {
562             MEDIA_ERR_LOG("CheckDateTaken failed in GenThumbnail");
563             return false;
564         }
565         if (!GenMonthAndYearAstcData(data, type)) {
566             MEDIA_ERR_LOG("GenMonthAndYearAstcData failed in GenThumbnail");
567             return false;
568         }
569     } else {
570         MEDIA_ERR_LOG("invalid thumbnail type: %{public}d", type);
571         return false;
572     }
573 
574     int err = ThumbnailUtils::TrySaveFile(data, type);
575     if (err < 0) {
576         MEDIA_ERR_LOG("SaveThumbnailData faild %{public}d", err);
577         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, err},
578             {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
579         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
580         return false;
581     }
582     data.thumbnail.clear();
583     return true;
584 }
585 
GenThumbnailEx(ThumbRdbOpt &opts, ThumbnailData &data)586 bool IThumbnailHelper::GenThumbnailEx(ThumbRdbOpt &opts, ThumbnailData &data)
587 {
588     if (!data.isLocalFile) {
589         MEDIA_INFO_LOG("Create thumb when cloud loading, no need to create THM_EX, path: %{public}s, id: %{public}s",
590             DfxUtils::GetSafePath(opts.path).c_str(), data.id.c_str());
591         return false;
592     }
593 
594     string fileName = GetThumbnailPath(data.path, THUMBNAIL_THUMB_EX_SUFFIX);
595     string dirName = MediaFileUtils::GetParentPath(fileName);
596     if (!MediaFileUtils::CreateDirectory(dirName)) {
597         MEDIA_ERR_LOG("Fail to create directory, fileName: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
598         return false;
599     }
600 
601     if (data.sourceEx == nullptr) {
602         MEDIA_ERR_LOG("sourceEx is nullptr when generate thumbnailEx, path: %{public}s",
603             DfxUtils::GetSafePath(opts.path).c_str());
604         return false;
605     }
606 
607     if (!ThumbnailUtils::CompressImage(data.sourceEx, data.thumbnail, false, false)) {
608         MEDIA_ERR_LOG("CompressImage failed id %{public}s", opts.row.c_str());
609         return false;
610     }
611 
612     int err = ThumbnailUtils::TrySaveFile(data, ThumbnailType::THUMB_EX);
613     if (err < 0) {
614         MEDIA_ERR_LOG("SaveThumbnailEx failed %{public}d", err);
615         return false;
616     }
617     data.thumbnail.clear();
618     return true;
619 }
620 
GenMonthAndYearAstcData(ThumbnailData &data, const ThumbnailType type)621 bool IThumbnailHelper::GenMonthAndYearAstcData(ThumbnailData &data, const ThumbnailType type)
622 {
623     Size size;
624     if (type == ThumbnailType::MTH_ASTC) {
625         size = {DEFAULT_MTH_SIZE, DEFAULT_MTH_SIZE };
626     } else if (type == ThumbnailType::YEAR_ASTC) {
627         size = {DEFAULT_YEAR_SIZE, DEFAULT_YEAR_SIZE };
628     } else {
629         MEDIA_ERR_LOG("invalid thumbnail type");
630         return false;
631     }
632 
633     ThumbnailUtils::GenTargetPixelmap(data, size);
634 
635 #ifdef IMAGE_COLORSPACE_FLAG
636     if (data.source->ApplyColorSpace(ColorManager::ColorSpaceName::DISPLAY_P3) != E_OK) {
637         MEDIA_ERR_LOG("ApplyColorSpace to p3 failed");
638     }
639 #endif
640 
641     if (!ThumbnailUtils::CompressImage(data.source,
642         (type == ThumbnailType::MTH_ASTC) ? data.monthAstc : data.yearAstc, false, true)) {
643         MEDIA_ERR_LOG("CompressImage to astc failed");
644         return false;
645     }
646     return true;
647 }
648 
649 // After all thumbnails are generated, the value of column "thumbnail_ready" in rdb needs to be updated,
650 // And if generate successfully, application should receive a notification at the same time.
UpdateThumbnailState(const ThumbRdbOpt &opts, ThumbnailData &data, const bool isSuccess)651 bool IThumbnailHelper::UpdateThumbnailState(const ThumbRdbOpt &opts, ThumbnailData &data, const bool isSuccess)
652 {
653     if (data.fileUri.empty()) {
654         data.fileUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::DEFAULT_PHOTO_URI + "/", data.id,
655             MediaFileUtils::GetExtraUri(data.displayName, data.path));
656     }
657     return isSuccess ? UpdateSuccessState(opts, data) : UpdateFailState(opts, data);
658 }
659 
UpdateSuccessState(const ThumbRdbOpt &opts, const ThumbnailData &data)660 bool IThumbnailHelper::UpdateSuccessState(const ThumbRdbOpt &opts, const ThumbnailData &data)
661 {
662     int32_t err = UpdateThumbDbState(opts, data);
663     if (err != E_OK) {
664         MEDIA_ERR_LOG("update thumbnail_ready failed, err = %{public}d", err);
665         return false;
666     }
667 
668     auto watch = MediaLibraryNotify::GetInstance();
669     if (watch == nullptr) {
670         MEDIA_ERR_LOG("watch is nullptr");
671         return false;
672     }
673     watch->Notify(data.fileUri, NotifyType::NOTIFY_THUMB_ADD);
674     return true;
675 }
676 
UpdateFailState(const ThumbRdbOpt &opts, const ThumbnailData &data)677 bool IThumbnailHelper::UpdateFailState(const ThumbRdbOpt &opts, const ThumbnailData &data)
678 {
679     if (opts.store == nullptr) {
680         MEDIA_ERR_LOG("opts.store is nullptr");
681         return false;
682     }
683     ValuesBucket values;
684     int changedRows;
685     values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_READY, static_cast<int64_t>(ThumbnailReady::GENERATE_THUMB_RETRY));
686     int32_t err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
687         vector<string> { data.id });
688     if (err != NativeRdb::E_OK) {
689         MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
690         return false;
691     }
692     return true;
693 }
694 
UpdateThumbDbState(const ThumbRdbOpt &opts, const ThumbnailData &data)695 int32_t IThumbnailHelper::UpdateThumbDbState(const ThumbRdbOpt &opts, const ThumbnailData &data)
696 {
697     ValuesBucket values;
698     int changedRows;
699     values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_READY, MediaFileUtils::UTCTimeMilliSeconds());
700     values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, 1);
701     Size lcdSize;
702     if (ThumbnailUtils::GetLocalThumbSize(data, ThumbnailType::LCD, lcdSize)) {
703         ThumbnailUtils::SetThumbnailSizeValue(values, lcdSize, PhotoColumn::PHOTO_LCD_SIZE);
704         values.PutLong(PhotoColumn::PHOTO_LCD_VISIT_TIME, static_cast<int64_t>(LcdReady::GENERATE_LCD_COMPLETED));
705     }
706     Size thumbSize;
707     if (ThumbnailUtils::GetLocalThumbSize(data, ThumbnailType::THUMB, thumbSize)) {
708         ThumbnailUtils::SetThumbnailSizeValue(values, thumbSize, PhotoColumn::PHOTO_THUMB_SIZE);
709     }
710     int32_t err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
711         vector<string> { data.id });
712     StoreThumbnailSize(opts, data);
713     if (err != NativeRdb::E_OK) {
714         MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
715         return E_ERR;
716     }
717     return E_OK;
718 }
719 
DoCreateThumbnail(ThumbRdbOpt &opts, ThumbnailData &data)720 bool IThumbnailHelper::DoCreateThumbnail(ThumbRdbOpt &opts, ThumbnailData &data)
721 {
722     ThumbnailWait thumbnailWait(true);
723     auto ret = thumbnailWait.InsertAndWait(data.id, ThumbnailType::THUMB);
724     if (ret != WaitStatus::INSERT) {
725         return ret == WaitStatus::WAIT_SUCCESS;
726     }
727 
728     if (!IsCreateThumbnailSuccess(opts, data)) {
729         MEDIA_ERR_LOG("Fail to create thumbnail, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
730         return false;
731     }
732 
733     if (data.orientation != 0 && !IsCreateThumbnailExSuccess(opts, data)) {
734         MEDIA_ERR_LOG("Fail to create thumbnailEx, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
735     }
736     thumbnailWait.UpdateThumbnailMap();
737     return true;
738 }
739 
IsCreateThumbnailSuccess(ThumbRdbOpt &opts, ThumbnailData &data)740 bool IThumbnailHelper::IsCreateThumbnailSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
741 {
742     data.loaderOpts.decodeInThumbSize = true;
743     if (!TryLoadSource(opts, data)) {
744         MEDIA_ERR_LOG("DoCreateThumbnail failed, try to load source failed, id: %{public}s", data.id.c_str());
745         return false;
746     }
747     if (data.source != nullptr && data.source->IsHdr()) {
748         data.source->ToSdr();
749     }
750     if (!GenThumbnail(opts, data, ThumbnailType::THUMB)) {
751         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN},
752             {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
753         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
754         return false;
755     }
756     if (opts.table == AudioColumn::AUDIOS_TABLE) {
757         MEDIA_DEBUG_LOG("AUDIOS_TABLE, no need to create all thumbnail");
758         return true;
759     }
760 
761     if (ThumbnailUtils::IsSupportGenAstc() && !GenThumbnail(opts, data, ThumbnailType::THUMB_ASTC)) {
762         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__},
763             {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN}, {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
764         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
765         return false;
766     }
767 
768     if (!data.tracks.empty()) {
769         MEDIA_INFO_LOG("generate highlight frame, no need to create month and year astc");
770         return true;
771     }
772 
773     // for some device that do not support KvStore, no need to generate the month and year astc.
774     if (MediaLibraryKvStoreManager::GetInstance()
775         .GetKvStore(KvStoreRoleType::OWNER, KvStoreValueType::MONTH_ASTC) == nullptr) {
776         MEDIA_DEBUG_LOG("kvStore is nullptr, no need to create month and year astc");
777         return true;
778     }
779     if (!GenThumbnail(opts, data, ThumbnailType::MTH_ASTC)) {
780         return false;
781     }
782     if (!GenThumbnail(opts, data, ThumbnailType::YEAR_ASTC)) {
783         return false;
784     }
785     return true;
786 }
787 
IsCreateThumbnailExSuccess(ThumbRdbOpt &opts, ThumbnailData &data)788 bool IThumbnailHelper::IsCreateThumbnailExSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
789 {
790     if (!GenThumbnailEx(opts, data)) {
791         MEDIA_ERR_LOG("Fail to create thumbnailEx, fileName: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
792         return false;
793     }
794     return true;
795 }
796 
DoRotateThumbnail(ThumbRdbOpt &opts, ThumbnailData &data)797 bool IThumbnailHelper::DoRotateThumbnail(ThumbRdbOpt &opts, ThumbnailData &data)
798 {
799     if (data.source == nullptr) {
800         MEDIA_ERR_LOG("source is nullptr when rotate thumbnail path: %{public}s",
801             DfxUtils::GetSafePath(data.path).c_str());
802         return false;
803     }
804 
805     if (!ThumbnailUtils::CompressImage(data.source, data.thumbnail, false, false)) {
806         MEDIA_ERR_LOG("CompressImage faild id %{public}s", data.id.c_str());
807         return false;
808     }
809 
810     int err = ThumbnailUtils::TrySaveFile(data, ThumbnailType::THUMB);
811     if (err < 0) {
812         MEDIA_ERR_LOG("SaveThumbnailData faild %{public}d", err);
813         return false;
814     }
815     data.thumbnail.clear();
816     return true;
817 }
818 
DoCreateLcdAndThumbnail(ThumbRdbOpt &opts, ThumbnailData &data)819 bool IThumbnailHelper::DoCreateLcdAndThumbnail(ThumbRdbOpt &opts, ThumbnailData &data)
820 {
821     MEDIA_INFO_LOG("Start DoCreateLcdAndThumbnail, id: %{public}s, path: %{public}s",
822         data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
823     data.isNeedStoreSize = false;
824     if (!DoCreateLcd(opts, data)) {
825         MEDIA_ERR_LOG("Fail to create lcd, err path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
826         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN},
827             {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
828         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
829         return false;
830     }
831 
832     data.loaderOpts.decodeInThumbSize = true;
833     if (data.source != nullptr && data.source->IsHdr()) {
834         data.source->ToSdr();
835     }
836     if (!ThumbnailUtils::ScaleThumbnailFromSource(data, false)) {
837         MEDIA_ERR_LOG("Fail to scale from LCD to THM, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
838         return false;
839     }
840 
841     if (data.orientation != 0 && data.sourceEx != nullptr && data.sourceEx->IsHdr()) {
842         data.sourceEx->ToSdr();
843     }
844     if (data.orientation != 0 && !ThumbnailUtils::ScaleThumbnailFromSource(data, true)) {
845         MEDIA_ERR_LOG("Fail to scale from LCD_EX to THM_EX, path: %{public}s",
846             DfxUtils::GetSafePath(data.path).c_str());
847         data.sourceEx = nullptr;
848     }
849 
850     if (!DoCreateThumbnail(opts, data)) {
851         MEDIA_ERR_LOG("Fail to create thumbnail, err path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
852         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN},
853             {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
854         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
855         return false;
856     }
857     return true;
858 }
859 
GetAvailableThumbnailSuffix(ThumbnailData &data)860 std::string GetAvailableThumbnailSuffix(ThumbnailData &data)
861 {
862     // Check whether the thumbnail data exist, firstly thumb then lcd, and return the corresponding suffix.
863     // When there is no thumbnail data, return empty string.
864     if (access(GetThumbnailPath(data.path, THUMBNAIL_THUMB_SUFFIX).c_str(), F_OK) == 0) {
865         return THUMBNAIL_THUMB_SUFFIX;
866     }
867     if (access(GetThumbnailPath(data.path, THUMBNAIL_LCD_SUFFIX).c_str(), F_OK) == 0) {
868         return THUMBNAIL_LCD_SUFFIX;
869     }
870     return "";
871 }
872 
DoCreateAstc(ThumbRdbOpt &opts, ThumbnailData &data)873 bool IThumbnailHelper::DoCreateAstc(ThumbRdbOpt &opts, ThumbnailData &data)
874 {
875     MEDIA_INFO_LOG("Start DoCreateAstc, id: %{public}s, path: %{public}s",
876         data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
877     data.loaderOpts.decodeInThumbSize = true;
878     if (!TryLoadSource(opts, data)) {
879         MEDIA_ERR_LOG("DoCreateAstc failed, try to load exist thumbnail failed, id: %{public}s", data.id.c_str());
880         return false;
881     }
882     if (data.source != nullptr && data.source->IsHdr()) {
883         data.source->ToSdr();
884     }
885     if (!GenThumbnail(opts, data, ThumbnailType::THUMB)) {
886         MEDIA_ERR_LOG("DoCreateAstc GenThumbnail THUMB failed, id: %{public}s", data.id.c_str());
887         return false;
888     }
889     if (!GenThumbnail(opts, data, ThumbnailType::THUMB_ASTC)) {
890         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__},
891             {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN}, {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
892         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
893         return false;
894     }
895     if (!GenThumbnail(opts, data, ThumbnailType::MTH_ASTC) || !GenThumbnail(opts, data, ThumbnailType::YEAR_ASTC)) {
896         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__},
897             {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN}, {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
898         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
899         return false;
900     }
901     CloudSyncDfxManager::GetInstance().RunDfx();
902     return true;
903 }
904 
GenerateRotatedThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, ThumbnailType thumbType)905 bool GenerateRotatedThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, ThumbnailType thumbType)
906 {
907     if (thumbType == ThumbnailType::LCD && !IThumbnailHelper::DoCreateLcd(opts, data)) {
908         MEDIA_ERR_LOG("Get lcd thumbnail pixelmap, rotate lcd failed: %{public}s",
909             DfxUtils::GetSafePath(data.path).c_str());
910         return false;
911     }
912     if (thumbType != ThumbnailType::LCD && !IThumbnailHelper::DoRotateThumbnail(opts, data)) {
913         MEDIA_ERR_LOG("Get default thumbnail pixelmap, rotate thumbnail failed: %{public}s",
914             DfxUtils::GetSafePath(data.path).c_str());
915         return false;
916     }
917     return true;
918 }
919 
DecodeThumbnailFromFd(int32_t fd)920 unique_ptr<PixelMap> DecodeThumbnailFromFd(int32_t fd)
921 {
922     SourceOptions opts;
923     uint32_t err = 0;
924     unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(fd, opts, err);
925     if (imageSource == nullptr) {
926         MEDIA_ERR_LOG("Decode thumbnail from fd failed, CreateImageSource err: %{public}d", err);
927         return nullptr;
928     }
929 
930     ImageInfo imageInfo;
931     err = imageSource->GetImageInfo(0, imageInfo);
932     if (err != E_OK) {
933         MEDIA_ERR_LOG("Decode thumbnail from fd failed, GetImageInfo err: %{public}d", err);
934         return nullptr;
935     }
936 
937     DecodeOptions decodeOpts;
938     decodeOpts.desiredDynamicRange = DecodeDynamicRange::SDR;
939     decodeOpts.desiredPixelFormat = PixelFormat::RGBA_8888;
940     unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, err);
941     if (pixelMap == nullptr) {
942         MEDIA_ERR_LOG("Decode thumbnail from fd failed, CreatePixelMap err: %{public}d", err);
943         return nullptr;
944     }
945     return pixelMap;
946 }
947 
DoCreateAstcEx(ThumbRdbOpt &opts, ThumbnailData &data)948 bool IThumbnailHelper::DoCreateAstcEx(ThumbRdbOpt &opts, ThumbnailData &data)
949 {
950     ThumbnailWait thumbnailWait(true);
951     auto ret = thumbnailWait.CloudInsertAndWait(data.id, CloudLoadType::CLOUD_DOWNLOAD);
952     if (ret != WaitStatus::INSERT && ret != WaitStatus::WAIT_CONTINUE) {
953         return ret == WaitStatus::WAIT_SUCCESS;
954     }
955 
956     MEDIA_INFO_LOG("Start DoCreateAstcEx, id: %{public}s, path: %{public}s",
957         data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
958     string fileName = GetThumbnailPath(data.path, THUMBNAIL_LCD_EX_SUFFIX);
959     if (access(fileName.c_str(), F_OK) != 0) {
960         MEDIA_ERR_LOG("No available file in THM_EX, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
961         return false;
962     }
963 
964     if (!DoCreateLcd(opts, data)) {
965         MEDIA_ERR_LOG("Fail to create lcd, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
966         return false;
967     }
968 
969     data.loaderOpts.decodeInThumbSize = true;
970     if (data.source != nullptr && data.source->IsHdr()) {
971         data.source->ToSdr();
972     }
973     if (!ThumbnailUtils::ScaleThumbnailFromSource(data, false)) {
974         MEDIA_ERR_LOG("Fail to scale from LCD to THM, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
975         return false;
976     }
977 
978     if (!DoCreateThumbnail(opts, data)) {
979         MEDIA_ERR_LOG("Fail to create thumbnail, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
980         return false;
981     }
982 
983     if (!ThumbnailUtils::DeleteThumbExDir(data)) {
984         MEDIA_ERR_LOG("Fail to delete THM_EX directory, path: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
985     }
986 
987     thumbnailWait.UpdateCloudLoadThumbnailMap(CloudLoadType::CLOUD_DOWNLOAD, true);
988     CloudSyncDfxManager::GetInstance().RunDfx();
989     return true;
990 }
991 
DoRotateThumbnailEx(ThumbRdbOpt &opts, ThumbnailData &data, int32_t fd, ThumbnailType thumbType)992 bool IThumbnailHelper::DoRotateThumbnailEx(ThumbRdbOpt &opts, ThumbnailData &data, int32_t fd, ThumbnailType thumbType)
993 {
994     ThumbnailWait thumbnailWait(true);
995     auto ret = thumbnailWait.CloudInsertAndWait(data.id, thumbType == ThumbnailType::LCD ?
996         CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB);
997     if (ret != WaitStatus::INSERT && ret != WaitStatus::WAIT_CONTINUE) {
998         close(fd);
999         return ret == WaitStatus::WAIT_SUCCESS;
1000     }
1001 
1002     auto dataSource = DecodeThumbnailFromFd(fd);
1003     if (dataSource == nullptr) {
1004         MEDIA_ERR_LOG("GetThumbnailPixelMap failed, dataSource is nullptr, path: %{public}s",
1005             DfxUtils::GetSafePath(data.path).c_str());
1006         close(fd);
1007         thumbnailWait.UpdateCloudLoadThumbnailMap(thumbType == ThumbnailType::LCD ?
1008             CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB, false);
1009         return false;
1010     }
1011     close(fd);
1012 
1013     data.source = std::move(dataSource);
1014     data.source->rotate(static_cast<float>(data.orientation));
1015     if (!GenerateRotatedThumbnail(opts, data, thumbType)) {
1016         MEDIA_ERR_LOG("GenerateRotatedThumbnail failed, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1017         thumbnailWait.UpdateCloudLoadThumbnailMap(thumbType == ThumbnailType::LCD ?
1018             CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB, false);
1019         return false;
1020     }
1021 
1022     thumbnailWait.UpdateCloudLoadThumbnailMap(thumbType == ThumbnailType::LCD ?
1023         CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB, true);
1024     return true;
1025 }
1026 
IsPureCloudImage(ThumbRdbOpt &opts)1027 bool IThumbnailHelper::IsPureCloudImage(ThumbRdbOpt &opts)
1028 {
1029     vector<string> columns = {
1030         MEDIA_DATA_DB_ID,
1031         PhotoColumn::PHOTO_POSITION
1032     };
1033     if (opts.row.empty() || opts.table.empty()) {
1034         MEDIA_ERR_LOG("IsPureCloudImage opts.row is empty");
1035         return false;
1036     }
1037     string strQueryCondition = MEDIA_DATA_DB_ID + " = " + opts.row;
1038     RdbPredicates rdbPredicates(opts.table);
1039     rdbPredicates.SetWhereClause(strQueryCondition);
1040     if (opts.store == nullptr) {
1041         MEDIA_ERR_LOG("IsPureCloudImage opts.store is nullptr");
1042         return false;
1043     }
1044     auto resultSet = opts.store->QueryByStep(rdbPredicates, columns);
1045     if (resultSet == nullptr) {
1046         MEDIA_ERR_LOG("IsPureCloudImage result set is null");
1047         return false;
1048     }
1049     auto ret = resultSet->GoToFirstRow();
1050     if (ret != NativeRdb::E_OK) {
1051         MEDIA_ERR_LOG("IsPureCloudImage go to first row failed");
1052         return false;
1053     }
1054     int photoPosition = GetInt32Val(PhotoColumn::PHOTO_POSITION, resultSet);
1055 
1056     // if current image is a pure cloud image, it's photo position column in database will be 2
1057     return photoPosition == 2;
1058 }
1059 } // namespace Media
1060 } // namespace OHOS