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