• 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     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     MEDIA_INFO_LOG("Start DoCreateLcd, id: %{public}s, path: %{public}s",
421         data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
422     ThumbnailWait thumbnailWait(true);
423     ret = thumbnailWait.InsertAndWait(data.id, ThumbnailType::LCD);
424     if (ret != WaitStatus::INSERT) {
425         return ret == WaitStatus::WAIT_SUCCESS;
426     }
427 
428     if (!IsCreateLcdSuccess(opts, data)) {
429         MEDIA_ERR_LOG("Fail to create lcd, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
430         return false;
431     }
432 
433     if (data.orientation != 0 && !IsCreateLcdExSuccess(opts, data)) {
434         MEDIA_ERR_LOG("Fail to create lcdEx, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
435     }
436     thumbnailWait.UpdateThumbnailMap();
437     return true;
438 }
439 
UpdateLcdDbState(ThumbRdbOpt & opts,ThumbnailData & data)440 void UpdateLcdDbState(ThumbRdbOpt &opts, ThumbnailData &data)
441 {
442     if (opts.table != PhotoColumn::PHOTOS_TABLE) {
443         return;
444     }
445     StoreThumbnailSize(opts, data);
446     int err = 0;
447     if (!ThumbnailUtils::UpdateLcdInfo(opts, data, err)) {
448         MEDIA_INFO_LOG("UpdateLcdInfo faild err : %{public}d", err);
449     }
450 }
451 
SaveLcdPictureSource(ThumbRdbOpt & opts,ThumbnailData & data,bool isSourceEx)452 bool SaveLcdPictureSource(ThumbRdbOpt &opts, ThumbnailData &data, bool isSourceEx)
453 {
454     shared_ptr<Picture> lcdSource = isSourceEx ? data.source.GetPictureEx() : data.source.GetPicture();
455     if (lcdSource == nullptr || lcdSource->GetMainPixel() == nullptr) {
456         MEDIA_ERR_LOG("SaveLcdPictureSource failed, lcdSource is null");
457         return false;
458     }
459     int lcdDesiredWidth;
460     int lcdDesiredHeight;
461     if (isSourceEx) {
462         lcdDesiredWidth = data.lcdDesiredSize.width;
463         lcdDesiredHeight = data.lcdDesiredSize.height;
464     } else {
465         lcdDesiredWidth = data.orientation % FLAT_ANGLE == 0 ? data.lcdDesiredSize.width : data.lcdDesiredSize.height;
466         lcdDesiredHeight = data.orientation % FLAT_ANGLE == 0 ? data.lcdDesiredSize.height : data.lcdDesiredSize.width;
467     }
468     std::shared_ptr<Picture> copySource;
469     if (lcdDesiredWidth != lcdSource->GetMainPixel()->GetWidth()) {
470         MEDIA_INFO_LOG("Copy and resize picture source for lcd desiredSize: %{public}s",
471             DfxUtils::GetSafePath(data.path).c_str());
472         if (!ThumbnailUtils::CopyPictureSource(lcdSource, copySource)) {
473             MEDIA_ERR_LOG("CompressPicture failed, CopyPictureSource failed");
474             return false;
475         }
476         if (lcdSource->GetMainPixel()->GetWidth() * lcdSource->GetMainPixel()->GetHeight() == 0) {
477             MEDIA_ERR_LOG("CompressPicture failed, invalid mainpixel size");
478             return false;
479         }
480         float widthScale = (1.0f * lcdDesiredWidth) / lcdSource->GetMainPixel()->GetWidth();
481         float heightScale = (1.0f * lcdDesiredHeight) / lcdSource->GetMainPixel()->GetHeight();
482         lcdSource->GetMainPixel()->scale(widthScale, heightScale);
483         lcdSource->GetGainmapPixelMap()->scale(widthScale, heightScale);
484     }
485     if (!ThumbnailUtils::CompressPicture(data, isSourceEx)) {
486         MEDIA_ERR_LOG("CompressPicture failed");
487         return false;
488     }
489     if (copySource != nullptr) {
490         lcdSource = copySource;
491     }
492     if (!isSourceEx) {
493         UpdateLcdDbState(opts, data);
494     }
495     return true;
496 }
497 
SaveLcdPixelMapSource(ThumbRdbOpt & opts,ThumbnailData & data,bool isSourceEx)498 bool SaveLcdPixelMapSource(ThumbRdbOpt &opts, ThumbnailData &data, bool isSourceEx)
499 {
500     shared_ptr<PixelMap> lcdSource = isSourceEx ? data.source.GetPixelMapEx() : data.source.GetPixelMap();
501     if (lcdSource == nullptr) {
502         MEDIA_ERR_LOG("SaveLcdPixelMapSource failed, lcdSource is null");
503         return false;
504     }
505     int lcdDesiredWidth;
506     int lcdDesiredHeight;
507     if (isSourceEx) {
508         lcdDesiredWidth = data.lcdDesiredSize.width;
509         lcdDesiredHeight = data.lcdDesiredSize.height;
510     } else {
511         lcdDesiredWidth = data.orientation % FLAT_ANGLE == 0 ? data.lcdDesiredSize.width : data.lcdDesiredSize.height;
512         lcdDesiredHeight = data.orientation % FLAT_ANGLE == 0 ? data.lcdDesiredSize.height : data.lcdDesiredSize.width;
513     }
514     if (lcdDesiredWidth != lcdSource->GetWidth()) {
515         MEDIA_INFO_LOG("Copy and resize data source for lcd desiredSize: %{public}s",
516             DfxUtils::GetSafePath(data.path).c_str());
517         Media::InitializationOptions initOpts;
518         auto copySource = PixelMap::Create(*lcdSource, initOpts);
519         lcdSource = std::move(copySource);
520         if (lcdSource->GetWidth() * lcdSource->GetHeight() == 0) {
521             MEDIA_ERR_LOG("CompressImage failed, invalid lcdSource");
522             return false;
523         }
524         float widthScale = (1.0f * lcdDesiredWidth) / lcdSource->GetWidth();
525         float heightScale = (1.0f * lcdDesiredHeight) / lcdSource->GetHeight();
526         lcdSource->scale(widthScale, heightScale);
527     }
528     if (!ThumbnailUtils::CompressImage(lcdSource, data.lcd, false, false, data.thumbnailQuality)) {
529         MEDIA_ERR_LOG("CompressImage failed");
530         return false;
531     }
532 
533     int err = ThumbnailUtils::TrySaveFile(data, isSourceEx ? ThumbnailType::LCD_EX : ThumbnailType::LCD);
534     if (err < 0) {
535         MEDIA_ERR_LOG("SaveLcd PixelMap failed %{public}d", err);
536         return false;
537     }
538 
539     data.lcd.clear();
540     if (!isSourceEx) {
541         UpdateLcdDbState(opts, data);
542     }
543     return true;
544 }
545 
IsCreateLcdSuccess(ThumbRdbOpt & opts,ThumbnailData & data)546 bool IThumbnailHelper::IsCreateLcdSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
547 {
548     data.loaderOpts.decodeInThumbSize = false;
549     data.loaderOpts.isHdr = true;
550     if (!TryLoadSource(opts, data)) {
551         MEDIA_ERR_LOG("load source is nullptr path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
552         return false;
553     }
554 
555     if (data.source.IsEmptySource()) {
556         MEDIA_ERR_LOG("Fail to create lcd, source is nullptr");
557         return false;
558     }
559 
560     if (data.source.HasPictureSource()) {
561         return SaveLcdPictureSource(opts, data, false);
562     } else {
563         return SaveLcdPixelMapSource(opts, data, false);
564     }
565 }
566 
IsCreateLcdExSuccess(ThumbRdbOpt & opts,ThumbnailData & data)567 bool IThumbnailHelper::IsCreateLcdExSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
568 {
569     if (!data.isLocalFile) {
570         MEDIA_INFO_LOG("Create lcd when cloud loading, no need to create THM_EX, path: %{public}s, id: %{public}s",
571             DfxUtils::GetSafePath(opts.path).c_str(), data.id.c_str());
572         return false;
573     }
574 
575     string fileName = GetThumbnailPath(data.path, THUMBNAIL_LCD_EX_SUFFIX);
576     string dirName = MediaFileUtils::GetParentPath(fileName);
577     if (!MediaFileUtils::CreateDirectory(dirName)) {
578         MEDIA_ERR_LOG("Fail to create directory, fileName: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
579         return false;
580     }
581 
582     if (data.source.IsEmptySource()) {
583         MEDIA_ERR_LOG("Fail to create lcdEx, source is nullptr");
584         return false;
585     }
586 
587     if (data.source.HasPictureSource()) {
588         return SaveLcdPictureSource(opts, data, true);
589     } else {
590         return SaveLcdPixelMapSource(opts, data, true);
591     }
592 }
593 
GenThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,const ThumbnailType type)594 bool IThumbnailHelper::GenThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, const ThumbnailType type)
595 {
596     auto pixelMap = data.source.GetPixelMap();
597     if (pixelMap == nullptr) {
598         MEDIA_ERR_LOG("source is nullptr when generate type: %{public}s", TYPE_NAME_MAP.at(type).c_str());
599         return false;
600     }
601 
602     if (type == ThumbnailType::THUMB || type == ThumbnailType::THUMB_ASTC) {
603         if (!ThumbnailUtils::CompressImage(pixelMap, type == ThumbnailType::THUMB ? data.thumbnail : data.thumbAstc,
604             type == ThumbnailType::THUMB_ASTC)) {
605             MEDIA_ERR_LOG("CompressImage faild id %{public}s", opts.row.c_str());
606             VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN},
607                 {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
608             PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
609             return false;
610         }
611     } else if (type == ThumbnailType::MTH_ASTC || type == ThumbnailType::YEAR_ASTC) {
612         if (!ThumbnailUtils::CheckDateTaken(opts, data)) {
613             MEDIA_ERR_LOG("CheckDateTaken failed in GenThumbnail");
614             return false;
615         }
616         if (!GenMonthAndYearAstcData(data, type)) {
617             MEDIA_ERR_LOG("GenMonthAndYearAstcData failed in GenThumbnail");
618             return false;
619         }
620     } else {
621         MEDIA_ERR_LOG("invalid thumbnail type: %{public}d", type);
622         return false;
623     }
624 
625     int err = ThumbnailUtils::TrySaveFile(data, type);
626     if (err < 0) {
627         MEDIA_ERR_LOG("SaveThumbnailData faild %{public}d", err);
628         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, err},
629             {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
630         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
631         return false;
632     }
633     data.thumbnail.clear();
634     return true;
635 }
636 
GenThumbnailEx(ThumbRdbOpt & opts,ThumbnailData & data)637 bool IThumbnailHelper::GenThumbnailEx(ThumbRdbOpt &opts, ThumbnailData &data)
638 {
639     if (!data.isLocalFile) {
640         MEDIA_INFO_LOG("Create thumb when cloud loading, no need to create THM_EX, path: %{public}s, id: %{public}s",
641             DfxUtils::GetSafePath(opts.path).c_str(), data.id.c_str());
642         return false;
643     }
644 
645     string fileName = GetThumbnailPath(data.path, THUMBNAIL_THUMB_EX_SUFFIX);
646     string dirName = MediaFileUtils::GetParentPath(fileName);
647     if (!MediaFileUtils::CreateDirectory(dirName)) {
648         MEDIA_ERR_LOG("Fail to create directory, fileName: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
649         return false;
650     }
651 
652     auto pixelMapEx = data.source.GetPixelMapEx();
653     if (pixelMapEx == nullptr) {
654         MEDIA_ERR_LOG("sourceEx is nullptr when generate thumbnailEx, path: %{public}s",
655             DfxUtils::GetSafePath(opts.path).c_str());
656         return false;
657     }
658 
659     if (!ThumbnailUtils::CompressImage(pixelMapEx, data.thumbnail, false)) {
660         MEDIA_ERR_LOG("CompressImage failed id %{public}s", opts.row.c_str());
661         return false;
662     }
663 
664     int err = ThumbnailUtils::TrySaveFile(data, ThumbnailType::THUMB_EX);
665     if (err < 0) {
666         MEDIA_ERR_LOG("SaveThumbnailEx failed %{public}d", err);
667         return false;
668     }
669     data.thumbnail.clear();
670     return true;
671 }
672 
GenMonthAndYearAstcData(ThumbnailData & data,const ThumbnailType type)673 bool IThumbnailHelper::GenMonthAndYearAstcData(ThumbnailData &data, const ThumbnailType type)
674 {
675     Size size;
676     if (type == ThumbnailType::MTH_ASTC) {
677         size = {DEFAULT_MTH_SIZE, DEFAULT_MTH_SIZE };
678     } else if (type == ThumbnailType::YEAR_ASTC) {
679         size = {DEFAULT_YEAR_SIZE, DEFAULT_YEAR_SIZE };
680     } else {
681         MEDIA_ERR_LOG("invalid thumbnail type");
682         return false;
683     }
684     ThumbnailUtils::GenTargetPixelmap(data, size);
685     auto pixelMap = data.source.GetPixelMap();
686 #ifdef IMAGE_COLORSPACE_FLAG
687     if (pixelMap->ApplyColorSpace(ColorManager::ColorSpaceName::DISPLAY_P3) != E_OK) {
688         MEDIA_ERR_LOG("ApplyColorSpace to p3 failed");
689     }
690 #endif
691     if (!ThumbnailUtils::CompressImage(pixelMap,
692         (type == ThumbnailType::MTH_ASTC) ? data.monthAstc : data.yearAstc, true)) {
693         MEDIA_ERR_LOG("CompressImage to astc failed");
694         return false;
695     }
696     return true;
697 }
698 
699 // After all thumbnails are generated, the value of column "thumbnail_ready" in rdb needs to be updated,
700 // And if generate successfully, application should receive a notification at the same time.
UpdateThumbnailState(const ThumbRdbOpt & opts,ThumbnailData & data,const bool isSuccess)701 bool IThumbnailHelper::UpdateThumbnailState(const ThumbRdbOpt &opts, ThumbnailData &data, const bool isSuccess)
702 {
703     if (data.fileUri.empty()) {
704         data.fileUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::DEFAULT_PHOTO_URI + "/", data.id,
705             MediaFileUtils::GetExtraUri(data.displayName, data.path));
706     }
707     return isSuccess ? UpdateSuccessState(opts, data) : UpdateFailState(opts, data);
708 }
709 
UpdateSuccessState(const ThumbRdbOpt & opts,const ThumbnailData & data)710 bool IThumbnailHelper::UpdateSuccessState(const ThumbRdbOpt &opts, const ThumbnailData &data)
711 {
712     int32_t err = UpdateThumbDbState(opts, data);
713     if (err != E_OK) {
714         MEDIA_ERR_LOG("update thumbnail_ready failed, err = %{public}d", err);
715         return false;
716     }
717 
718     auto watch = MediaLibraryNotify::GetInstance();
719     if (watch == nullptr) {
720         MEDIA_ERR_LOG("watch is nullptr");
721         return false;
722     }
723     watch->Notify(data.fileUri, NotifyType::NOTIFY_THUMB_ADD);
724     if (data.isThumbExisted) {
725         watch->Notify(data.fileUri, NotifyType::NOTIFY_THUMB_UPDATE);
726     } else {
727         watch->Notify(data.fileUri, NotifyType::NOTIFY_THUMB_ADD);
728     }
729     return true;
730 }
731 
UpdateFailState(const ThumbRdbOpt & opts,const ThumbnailData & data)732 bool IThumbnailHelper::UpdateFailState(const ThumbRdbOpt &opts, const ThumbnailData &data)
733 {
734     if (opts.store == nullptr) {
735         MEDIA_ERR_LOG("opts.store is nullptr");
736         return false;
737     }
738     ValuesBucket values;
739     int changedRows;
740     values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_READY, static_cast<int64_t>(ThumbnailReady::GENERATE_THUMB_RETRY));
741     values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, 1);
742     int32_t err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
743         vector<string> { data.id });
744     if (err != NativeRdb::E_OK) {
745         MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
746         return false;
747     }
748     return true;
749 }
750 
UpdateThumbDbState(const ThumbRdbOpt & opts,const ThumbnailData & data)751 int32_t IThumbnailHelper::UpdateThumbDbState(const ThumbRdbOpt &opts, const ThumbnailData &data)
752 {
753     ValuesBucket values;
754     int changedRows;
755     values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_READY, MediaFileUtils::UTCTimeMilliSeconds());
756     values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, 1);
757     Size lcdSize;
758     if (ThumbnailUtils::GetLocalThumbSize(data, ThumbnailType::LCD, lcdSize)) {
759         ThumbnailUtils::SetThumbnailSizeValue(values, lcdSize, PhotoColumn::PHOTO_LCD_SIZE);
760         values.PutLong(PhotoColumn::PHOTO_LCD_VISIT_TIME, static_cast<int64_t>(LcdReady::GENERATE_LCD_COMPLETED));
761     }
762     Size thumbSize;
763     if (ThumbnailUtils::GetLocalThumbSize(data, ThumbnailType::THUMB, thumbSize)) {
764         ThumbnailUtils::SetThumbnailSizeValue(values, thumbSize, PhotoColumn::PHOTO_THUMB_SIZE);
765     }
766     int32_t err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
767         vector<string> { data.id });
768     StoreThumbnailSize(opts, data);
769     if (err != NativeRdb::E_OK) {
770         MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
771         return E_ERR;
772     }
773     return E_OK;
774 }
775 
DoCreateThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,WaitStatus & ret)776 bool IThumbnailHelper::DoCreateThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, WaitStatus &ret)
777 {
778     MEDIA_INFO_LOG("Start DoCreateThumbnail, id: %{public}s, path: %{public}s",
779         data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
780     ThumbnailWait thumbnailWait(true);
781     ret = thumbnailWait.InsertAndWait(data.id, ThumbnailType::THUMB);
782     if (ret != WaitStatus::INSERT) {
783         return ret == WaitStatus::WAIT_SUCCESS;
784     }
785 
786     if (!IsCreateThumbnailSuccess(opts, data)) {
787         MEDIA_ERR_LOG("Fail to create thumbnail, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
788         return false;
789     }
790 
791     if (data.orientation != 0 && !IsCreateThumbnailExSuccess(opts, data)) {
792         MEDIA_ERR_LOG("Fail to create thumbnailEx, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
793     }
794     thumbnailWait.UpdateThumbnailMap();
795     return true;
796 }
797 
IsCreateThumbnailSuccess(ThumbRdbOpt & opts,ThumbnailData & data)798 bool IThumbnailHelper::IsCreateThumbnailSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
799 {
800     data.loaderOpts.decodeInThumbSize = true;
801     if (!TryLoadSource(opts, data)) {
802         MEDIA_ERR_LOG("DoCreateThumbnail failed, try to load source failed, id: %{public}s", data.id.c_str());
803         return false;
804     }
805     auto pixelMap = data.source.GetPixelMap();
806     if (pixelMap != nullptr && pixelMap->IsHdr()) {
807         uint32_t ret = pixelMap->ToSdr();
808         if (ret != E_OK) {
809             MEDIA_ERR_LOG("DoCreateThumbnail failed to transform to sdr, id: %{public}s.", data.id.c_str());
810             return false;
811         }
812     }
813     if (!GenThumbnail(opts, data, ThumbnailType::THUMB)) {
814         return false;
815     }
816     if (opts.table == AudioColumn::AUDIOS_TABLE) {
817         MEDIA_DEBUG_LOG("AUDIOS_TABLE, no need to create all thumbnail");
818         return true;
819     }
820 
821     if (ThumbnailUtils::IsSupportGenAstc() && !GenThumbnail(opts, data, ThumbnailType::THUMB_ASTC)) {
822         return false;
823     }
824 
825     // for some device that do not support KvStore, no need to generate the month and year astc.
826     if (MediaLibraryKvStoreManager::GetInstance()
827         .GetKvStore(KvStoreRoleType::OWNER, KvStoreValueType::MONTH_ASTC) == nullptr) {
828         MEDIA_DEBUG_LOG("kvStore is nullptr, no need to create month and year astc");
829         return true;
830     }
831     if (!GenThumbnail(opts, data, ThumbnailType::MTH_ASTC)) {
832         return false;
833     }
834     if (!GenThumbnail(opts, data, ThumbnailType::YEAR_ASTC)) {
835         return false;
836     }
837     return true;
838 }
839 
IsCreateThumbnailExSuccess(ThumbRdbOpt & opts,ThumbnailData & data)840 bool IThumbnailHelper::IsCreateThumbnailExSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
841 {
842     if (!GenThumbnailEx(opts, data)) {
843         MEDIA_ERR_LOG("Fail to create thumbnailEx, fileName: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
844         return false;
845     }
846     return true;
847 }
848 
DoRotateThumbnail(ThumbRdbOpt & opts,ThumbnailData & data)849 bool IThumbnailHelper::DoRotateThumbnail(ThumbRdbOpt &opts, ThumbnailData &data)
850 {
851     auto pixelMap = data.source.GetPixelMap();
852     if (pixelMap == nullptr) {
853         MEDIA_ERR_LOG("source is nullptr when rotate thumbnail path: %{public}s",
854             DfxUtils::GetSafePath(data.path).c_str());
855         return false;
856     }
857 
858     if (!ThumbnailUtils::CompressImage(pixelMap, data.thumbnail, false)) {
859         MEDIA_ERR_LOG("CompressImage faild id %{public}s", data.id.c_str());
860         return false;
861     }
862 
863     int err = ThumbnailUtils::TrySaveFile(data, ThumbnailType::THUMB);
864     if (err < 0) {
865         MEDIA_ERR_LOG("SaveThumbnailData faild %{public}d", err);
866         return false;
867     }
868     data.thumbnail.clear();
869     return true;
870 }
871 
DoCreateLcdAndThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,WaitStatus & ret)872 bool IThumbnailHelper::DoCreateLcdAndThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, WaitStatus &ret)
873 {
874     MEDIA_INFO_LOG("Start DoCreateLcdAndThumbnail, id: %{public}s, path: %{public}s",
875         data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
876     if (!DoCreateLcd(opts, data, ret)) {
877         MEDIA_ERR_LOG("Fail to create lcd, err path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
878         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN},
879             {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
880         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
881         return false;
882     }
883 
884     data.loaderOpts.decodeInThumbSize = true;
885     if (data.source.HasPictureSource()) {
886         MEDIA_INFO_LOG("Scale from picture source, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
887         auto mainPixelMap = data.source.GetPicture()->GetMainPixel();
888         data.source.SetPixelMap(mainPixelMap);
889     }
890     if (!ThumbnailUtils::ScaleThumbnailFromSource(data, false)) {
891         MEDIA_ERR_LOG("Fail to scale from LCD to THM, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
892         return false;
893     }
894 
895     if (data.orientation != 0 && data.source.HasPictureSource()) {
896         MEDIA_INFO_LOG("Scale from picture source, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
897         auto mainPixelMapEx = data.source.GetPictureEx()->GetMainPixel();
898         data.source.SetPixelMapEx(mainPixelMapEx);
899     }
900     if (data.orientation != 0 && !ThumbnailUtils::ScaleThumbnailFromSource(data, true)) {
901         MEDIA_ERR_LOG("Fail to scale from LCD_EX to THM_EX, path: %{public}s",
902             DfxUtils::GetSafePath(data.path).c_str());
903     }
904 
905     if (!DoCreateThumbnail(opts, data, ret)) {
906         MEDIA_ERR_LOG("Fail to create thumbnail, err path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
907         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN},
908             {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
909         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
910         return false;
911     }
912     return true;
913 }
914 
GetAvailableThumbnailSuffix(ThumbnailData & data)915 std::string GetAvailableThumbnailSuffix(ThumbnailData &data)
916 {
917     // Check whether the thumbnail data exist, firstly thumb then lcd, and return the corresponding suffix.
918     // When there is no thumbnail data, return empty string.
919     if (access(GetThumbnailPath(data.path, THUMBNAIL_THUMB_SUFFIX).c_str(), F_OK) == 0) {
920         return THUMBNAIL_THUMB_SUFFIX;
921     }
922     if (access(GetThumbnailPath(data.path, THUMBNAIL_LCD_SUFFIX).c_str(), F_OK) == 0) {
923         return THUMBNAIL_LCD_SUFFIX;
924     }
925     return "";
926 }
927 
DoCreateAstc(ThumbRdbOpt & opts,ThumbnailData & data)928 bool IThumbnailHelper::DoCreateAstc(ThumbRdbOpt &opts, ThumbnailData &data)
929 {
930     MEDIA_INFO_LOG("Start DoCreateAstc, id: %{public}s, path: %{public}s",
931         data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
932     data.loaderOpts.decodeInThumbSize = true;
933     if (!TryLoadSource(opts, data)) {
934         MEDIA_ERR_LOG("DoCreateAstc failed, try to load exist thumbnail failed, id: %{public}s", data.id.c_str());
935         return false;
936     }
937     auto pixelMap = data.source.GetPixelMap();
938     if (pixelMap != nullptr && pixelMap->IsHdr()) {
939         uint32_t ret = pixelMap->ToSdr();
940         if (ret != E_OK) {
941             MEDIA_ERR_LOG("DoCreateAstc failed to transform to sdr, id: %{public}s.", data.id.c_str());
942             return false;
943         }
944     }
945     if (!GenThumbnail(opts, data, ThumbnailType::THUMB)) {
946         MEDIA_ERR_LOG("DoCreateAstc GenThumbnail THUMB failed, id: %{public}s", data.id.c_str());
947         return false;
948     }
949     if (!GenThumbnail(opts, data, ThumbnailType::THUMB_ASTC)) {
950         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__},
951             {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN}, {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
952         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
953         return false;
954     }
955     if (!GenThumbnail(opts, data, ThumbnailType::MTH_ASTC) || !GenThumbnail(opts, data, ThumbnailType::YEAR_ASTC)) {
956         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__},
957             {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN}, {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
958         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
959         return false;
960     }
961     CloudSyncDfxManager::GetInstance().RunDfx();
962     return true;
963 }
964 
GenerateRotatedThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,ThumbnailType thumbType)965 bool GenerateRotatedThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, ThumbnailType thumbType)
966 {
967     WaitStatus status;
968     if (thumbType == ThumbnailType::LCD && !IThumbnailHelper::DoCreateLcd(opts, data, status)) {
969         MEDIA_ERR_LOG("Get lcd thumbnail pixelmap, rotate lcd failed: %{public}s",
970             DfxUtils::GetSafePath(data.path).c_str());
971         return false;
972     }
973     if (thumbType != ThumbnailType::LCD && !IThumbnailHelper::DoRotateThumbnail(opts, data)) {
974         MEDIA_ERR_LOG("Get default thumbnail pixelmap, rotate thumbnail failed: %{public}s",
975             DfxUtils::GetSafePath(data.path).c_str());
976         return false;
977     }
978     return true;
979 }
980 
DecodeThumbnailFromFd(int32_t fd)981 unique_ptr<PixelMap> DecodeThumbnailFromFd(int32_t fd)
982 {
983     SourceOptions opts;
984     uint32_t err = 0;
985     unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(fd, opts, err);
986     if (imageSource == nullptr) {
987         MEDIA_ERR_LOG("Decode thumbnail from fd failed, CreateImageSource err: %{public}d", err);
988         return nullptr;
989     }
990 
991     ImageInfo imageInfo;
992     err = imageSource->GetImageInfo(0, imageInfo);
993     if (err != E_OK) {
994         MEDIA_ERR_LOG("Decode thumbnail from fd failed, GetImageInfo err: %{public}d", err);
995         return nullptr;
996     }
997 
998     DecodeOptions decodeOpts;
999     decodeOpts.desiredDynamicRange = DecodeDynamicRange::SDR;
1000     decodeOpts.desiredPixelFormat = PixelFormat::RGBA_8888;
1001     unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, err);
1002     if (pixelMap == nullptr) {
1003         MEDIA_ERR_LOG("Decode thumbnail from fd failed, CreatePixelMap err: %{public}d", err);
1004         return nullptr;
1005     }
1006     return pixelMap;
1007 }
1008 
DoCreateAstcEx(ThumbRdbOpt & opts,ThumbnailData & data,WaitStatus & ret)1009 bool IThumbnailHelper::DoCreateAstcEx(ThumbRdbOpt &opts, ThumbnailData &data, WaitStatus &ret)
1010 {
1011     ThumbnailWait thumbnailWait(true);
1012     ret = thumbnailWait.CloudInsertAndWait(data.id, CloudLoadType::CLOUD_DOWNLOAD);
1013     if (ret != WaitStatus::INSERT && ret != WaitStatus::WAIT_CONTINUE) {
1014         return ret == WaitStatus::WAIT_SUCCESS;
1015     }
1016 
1017     MEDIA_INFO_LOG("Start DoCreateAstcEx, id: %{public}s, path: %{public}s",
1018         data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
1019     string fileName = GetThumbnailPath(data.path, THUMBNAIL_LCD_EX_SUFFIX);
1020     if (access(fileName.c_str(), F_OK) != 0) {
1021         MEDIA_ERR_LOG("No available file in THM_EX, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1022         return false;
1023     }
1024 
1025     if (!DoCreateLcd(opts, data, ret)) {
1026         MEDIA_ERR_LOG("Fail to create lcd, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1027         return false;
1028     }
1029 
1030     data.loaderOpts.decodeInThumbSize = true;
1031     if (data.source.HasPictureSource()) {
1032         MEDIA_INFO_LOG("Scale from picture source, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1033         auto mainPixelMap = data.source.GetPicture()->GetMainPixel();
1034         data.source.SetPixelMap(mainPixelMap);
1035     }
1036     if (!ThumbnailUtils::ScaleThumbnailFromSource(data, false)) {
1037         MEDIA_ERR_LOG("Fail to scale from LCD to THM, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1038         return false;
1039     }
1040 
1041     if (!DoCreateThumbnail(opts, data, ret)) {
1042         MEDIA_ERR_LOG("Fail to create thumbnail, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1043         return false;
1044     }
1045 
1046     thumbnailWait.UpdateCloudLoadThumbnailMap(CloudLoadType::CLOUD_DOWNLOAD, true);
1047     CloudSyncDfxManager::GetInstance().RunDfx();
1048     return true;
1049 }
1050 
DoRotateThumbnailEx(ThumbRdbOpt & opts,ThumbnailData & data,int32_t fd,ThumbnailType thumbType)1051 bool IThumbnailHelper::DoRotateThumbnailEx(ThumbRdbOpt &opts, ThumbnailData &data, int32_t fd, ThumbnailType thumbType)
1052 {
1053     ThumbnailWait thumbnailWait(true);
1054     auto ret = thumbnailWait.CloudInsertAndWait(data.id, thumbType == ThumbnailType::LCD ?
1055         CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB);
1056     if (ret != WaitStatus::INSERT && ret != WaitStatus::WAIT_CONTINUE) {
1057         close(fd);
1058         return ret == WaitStatus::WAIT_SUCCESS;
1059     }
1060 
1061     auto dataSourcePtr = DecodeThumbnailFromFd(fd);
1062     std::shared_ptr<PixelMap> dataSource = std::move(dataSourcePtr);
1063     if (dataSource == nullptr) {
1064         MEDIA_ERR_LOG("GetThumbnailPixelMap failed, dataSource is nullptr, path: %{public}s",
1065             DfxUtils::GetSafePath(data.path).c_str());
1066         close(fd);
1067         thumbnailWait.UpdateCloudLoadThumbnailMap(thumbType == ThumbnailType::LCD ?
1068             CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB, false);
1069         return false;
1070     }
1071     close(fd);
1072 
1073     dataSource->rotate(static_cast<float>(data.orientation));
1074     data.source.SetPixelMap(dataSource);
1075     if (!GenerateRotatedThumbnail(opts, data, thumbType)) {
1076         MEDIA_ERR_LOG("GenerateRotatedThumbnail failed, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1077         thumbnailWait.UpdateCloudLoadThumbnailMap(thumbType == ThumbnailType::LCD ?
1078             CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB, false);
1079         return false;
1080     }
1081 
1082     thumbnailWait.UpdateCloudLoadThumbnailMap(thumbType == ThumbnailType::LCD ?
1083         CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB, true);
1084     return true;
1085 }
1086 
IsPureCloudImage(ThumbRdbOpt & opts)1087 bool IThumbnailHelper::IsPureCloudImage(ThumbRdbOpt &opts)
1088 {
1089     vector<string> columns = {
1090         MEDIA_DATA_DB_ID,
1091         PhotoColumn::PHOTO_POSITION
1092     };
1093     if (opts.row.empty() || opts.table.empty()) {
1094         MEDIA_ERR_LOG("IsPureCloudImage opts.row is empty");
1095         return false;
1096     }
1097     string strQueryCondition = MEDIA_DATA_DB_ID + " = " + opts.row;
1098     RdbPredicates rdbPredicates(opts.table);
1099     rdbPredicates.SetWhereClause(strQueryCondition);
1100     if (opts.store == nullptr) {
1101         MEDIA_ERR_LOG("IsPureCloudImage opts.store is nullptr");
1102         return false;
1103     }
1104     auto resultSet = opts.store->QueryByStep(rdbPredicates, columns);
1105     if (resultSet == nullptr) {
1106         MEDIA_ERR_LOG("IsPureCloudImage result set is null");
1107         return false;
1108     }
1109     auto ret = resultSet->GoToFirstRow();
1110     if (ret != NativeRdb::E_OK) {
1111         MEDIA_ERR_LOG("IsPureCloudImage go to first row failed");
1112         return false;
1113     }
1114     int photoPosition = GetInt32Val(PhotoColumn::PHOTO_POSITION, resultSet);
1115 
1116     // if current image is a pure cloud image, it's photo position column in database will be 2
1117     return photoPosition == 2;
1118 }
1119 } // namespace Media
1120 } // namespace OHOS