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