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