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