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