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