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 "cloud_sync_helper.h"
22 #include "dfx_cloud_manager.h"
23 #include "dfx_utils.h"
24 #include "hitrace_meter.h"
25 #include "ipc_skeleton.h"
26 #include "media_column.h"
27 #include "medialibrary_errno.h"
28 #include "medialibrary_kvstore_manager.h"
29 #include "medialibrary_notify.h"
30 #include "medialibrary_photo_operations.h"
31 #include "medialibrary_type_const.h"
32 #include "media_file_utils.h"
33 #include "media_log.h"
34 #include "medialibrary_rdbstore.h"
35 #include "medialibrary_unistore_manager.h"
36 #include "post_event_utils.h"
37 #include "post_proc.h"
38 #include "result_set_utils.h"
39 #include "rdb_predicates.h"
40 #include "rdb_helper.h"
41 #include "single_kvstore.h"
42 #include "thumbnail_const.h"
43 #include "thumbnail_generate_worker_manager.h"
44 #include "thumbnail_image_framework_utils.h"
45 #include "thumbnail_source_loading.h"
46 #include "medialibrary_astc_stat.h"
47 using namespace std;
48 using namespace OHOS::DistributedKv;
49 using namespace OHOS::NativeRdb;
50
51 namespace OHOS {
52 namespace Media {
53
StoreThumbnailSize(const ThumbRdbOpt & opts,const ThumbnailData & data)54 void StoreThumbnailSize(const ThumbRdbOpt& opts, const ThumbnailData& data)
55 {
56 std::string photoId = opts.row.empty() ? data.id : opts.row;
57 std::string tmpPath = opts.path.empty() ? data.path : opts.path;
58 if (tmpPath.find(ROOT_MEDIA_DIR + PHOTO_BUCKET) != string::npos) {
59 MediaLibraryPhotoOperations::StoreThumbnailSize(photoId, tmpPath);
60 }
61 }
62
CloudSyncOnGenerationComplete(std::shared_ptr<ThumbnailTaskData> & data)63 void IThumbnailHelper::CloudSyncOnGenerationComplete(std::shared_ptr<ThumbnailTaskData> &data)
64 {
65 CloudSyncHelper::GetInstance()->isThumbnailGenerationCompleted_ = true;
66 CloudSyncHelper::GetInstance()->StartSync();
67 MEDIA_INFO_LOG("CloudSyncOnGenerationComplete complete");
68 }
69
CreateLcdAndThumbnail(std::shared_ptr<ThumbnailTaskData> & data)70 void IThumbnailHelper::CreateLcdAndThumbnail(std::shared_ptr<ThumbnailTaskData> &data)
71 {
72 if (data == nullptr) {
73 MEDIA_ERR_LOG("CreateLcdAndThumbnail failed, data is null");
74 return;
75 }
76 WaitStatus status;
77 bool isSuccess = DoCreateLcdAndThumbnail(data->opts_, data->thumbnailData_, status);
78 if (status == WaitStatus::INSERT) {
79 if (isSuccess && !data->thumbnailData_.tracks.empty() && (data->thumbnailData_.trigger == "0")) {
80 UpdateHighlightDbState(data->opts_, data->thumbnailData_);
81 }
82 if (data->thumbnailData_.tracks.empty()) {
83 UpdateThumbnailState(data->opts_, data->thumbnailData_, isSuccess);
84 }
85 }
86
87 ThumbnailUtils::RecordCostTimeAndReport(data->thumbnailData_.stats);
88 }
89
CreateLcd(std::shared_ptr<ThumbnailTaskData> & data)90 void IThumbnailHelper::CreateLcd(std::shared_ptr<ThumbnailTaskData> &data)
91 {
92 if (data == nullptr) {
93 MEDIA_ERR_LOG("CreateLcd failed, data is null");
94 return;
95 }
96 WaitStatus status;
97 DoCreateLcd(data->opts_, data->thumbnailData_, status);
98 }
99
CreateThumbnail(std::shared_ptr<ThumbnailTaskData> & data)100 void IThumbnailHelper::CreateThumbnail(std::shared_ptr<ThumbnailTaskData> &data)
101 {
102 if (data == nullptr) {
103 MEDIA_ERR_LOG("CreateThumbnail failed, data is null");
104 return;
105 }
106 WaitStatus status;
107 bool isSuccess = DoCreateThumbnail(data->opts_, data->thumbnailData_, status);
108 if (status == WaitStatus::INSERT) {
109 UpdateThumbnailState(data->opts_, data->thumbnailData_, isSuccess);
110 }
111
112 ThumbnailUtils::RecordCostTimeAndReport(data->thumbnailData_.stats);
113 }
114
CreateAstc(std::shared_ptr<ThumbnailTaskData> & data)115 void IThumbnailHelper::CreateAstc(std::shared_ptr<ThumbnailTaskData> &data)
116 {
117 if (data == nullptr) {
118 MEDIA_ERR_LOG("CreateAstc failed, data is null");
119 return;
120 }
121 int64_t startTime = MediaFileUtils::UTCTimeMilliSeconds();
122 bool isSuccess = DoCreateAstc(data->opts_, data->thumbnailData_);
123 UpdateThumbnailState(data->opts_, data->thumbnailData_, isSuccess);
124 MediaLibraryAstcStat::GetInstance().AddAstcInfo(startTime,
125 data->thumbnailData_.stats.scene, AstcGenScene::NOCHARGING_SCREENOFF, data->thumbnailData_.id);
126 ThumbnailUtils::RecordCostTimeAndReport(data->thumbnailData_.stats);
127 }
128
CreateAstcEx(std::shared_ptr<ThumbnailTaskData> & data)129 void IThumbnailHelper::CreateAstcEx(std::shared_ptr<ThumbnailTaskData> &data)
130 {
131 if (data == nullptr) {
132 MEDIA_ERR_LOG("CreateAstcEx failed, data is null");
133 return;
134 }
135 WaitStatus status;
136 bool isSuccess = DoCreateAstcEx(data->opts_, data->thumbnailData_, status);
137 if (status == WaitStatus::INSERT || status == WaitStatus::WAIT_CONTINUE) {
138 UpdateThumbnailState(data->opts_, data->thumbnailData_, isSuccess);
139 }
140 ThumbnailUtils::RecordCostTimeAndReport(data->thumbnailData_.stats);
141 }
142
DeleteMonthAndYearAstc(std::shared_ptr<ThumbnailTaskData> & data)143 void IThumbnailHelper::DeleteMonthAndYearAstc(std::shared_ptr<ThumbnailTaskData> &data)
144 {
145 if (data == nullptr) {
146 MEDIA_ERR_LOG("DeleteMonthAndYearAstc failed, data is null");
147 return;
148 }
149 if (!ThumbnailUtils::DoDeleteMonthAndYearAstc(data->opts_)) {
150 MEDIA_ERR_LOG("DeleteMonthAndYearAstc failed, key is %{public}s and %{public}s",
151 data->opts_.row.c_str(), data->opts_.dateTaken.c_str());
152 }
153 }
154
UpdateAstcDateTaken(std::shared_ptr<ThumbnailTaskData> & data)155 void IThumbnailHelper::UpdateAstcDateTaken(std::shared_ptr<ThumbnailTaskData> &data)
156 {
157 if (data == nullptr) {
158 MEDIA_ERR_LOG("UpdateAstcDateTaken failed, data is null");
159 return;
160 }
161 if (!ThumbnailUtils::DoUpdateAstcDateTaken(data->opts_, data->thumbnailData_)) {
162 MEDIA_ERR_LOG("UpdateAstcDateTaken failed, key is %{public}s and %{public}s",
163 data->opts_.row.c_str(), data->thumbnailData_.dateTaken.c_str());
164 }
165 }
166
AddThumbnailGenerateTask(ThumbnailGenerateExecute executor,const ThumbnailTaskType & taskType,const ThumbnailTaskPriority & priority)167 void IThumbnailHelper::AddThumbnailGenerateTask(ThumbnailGenerateExecute executor, const ThumbnailTaskType &taskType,
168 const ThumbnailTaskPriority &priority)
169 {
170 std::shared_ptr<ThumbnailGenerateWorker> thumbnailWorker =
171 ThumbnailGenerateWorkerManager::GetInstance().GetThumbnailWorker(taskType);
172 if (thumbnailWorker == nullptr) {
173 MEDIA_ERR_LOG("thumbnailWorker is null");
174 return;
175 }
176
177 std::shared_ptr<ThumbnailTaskData> taskData = std::make_shared<ThumbnailTaskData>();
178 std::shared_ptr<ThumbnailGenerateTask> task = std::make_shared<ThumbnailGenerateTask>(executor, taskData);
179 thumbnailWorker->AddTask(task, priority);
180 }
181
AddThumbnailGenerateTask(ThumbnailGenerateExecute executor,ThumbRdbOpt & opts,ThumbnailData & thumbData,const ThumbnailTaskType & taskType,const ThumbnailTaskPriority & priority,std::shared_ptr<ExecuteParamBuilder> param)182 void IThumbnailHelper::AddThumbnailGenerateTask(ThumbnailGenerateExecute executor, ThumbRdbOpt &opts,
183 ThumbnailData &thumbData, const ThumbnailTaskType &taskType, const ThumbnailTaskPriority &priority,
184 std::shared_ptr<ExecuteParamBuilder> param)
185 {
186 std::shared_ptr<ThumbnailGenerateWorker> thumbnailWorker =
187 ThumbnailGenerateWorkerManager::GetInstance().GetThumbnailWorker(taskType);
188 if (thumbnailWorker == nullptr) {
189 MEDIA_ERR_LOG("thumbnailWorker is null");
190 return;
191 }
192
193 std::shared_ptr<ThumbnailTaskData> taskData = std::make_shared<ThumbnailTaskData>(opts, thumbData);
194 std::shared_ptr<ThumbnailGenerateTask> task = std::make_shared<ThumbnailGenerateTask>(executor, taskData, param);
195 thumbnailWorker->AddTask(task, priority);
196 }
197
AddThumbnailGenBatchTask(ThumbnailGenerateExecute executor,ThumbRdbOpt & opts,ThumbnailData & thumbData,int32_t requestId)198 void IThumbnailHelper::AddThumbnailGenBatchTask(ThumbnailGenerateExecute executor,
199 ThumbRdbOpt &opts, ThumbnailData &thumbData, int32_t requestId)
200 {
201 std::shared_ptr<ThumbnailGenerateWorker> thumbnailWorker =
202 ThumbnailGenerateWorkerManager::GetInstance().GetThumbnailWorker(ThumbnailTaskType::FOREGROUND);
203 if (thumbnailWorker == nullptr) {
204 MEDIA_ERR_LOG("thumbnailWorker is null");
205 return;
206 }
207
208 std::shared_ptr<ThumbnailTaskData> taskData = std::make_shared<ThumbnailTaskData>(opts, thumbData, requestId);
209 std::shared_ptr<ThumbnailGenerateTask> task = std::make_shared<ThumbnailGenerateTask>(executor, taskData);
210 thumbnailWorker->AddTask(task, ThumbnailTaskPriority::LOW);
211 }
212
ThumbnailWait(bool release)213 ThumbnailWait::ThumbnailWait(bool release) : needRelease_(release)
214 {}
215
~ThumbnailWait()216 ThumbnailWait::~ThumbnailWait()
217 {
218 if (needRelease_) {
219 Notify();
220 }
221 }
222
223 ThumbnailMap ThumbnailWait::thumbnailMap_;
224 std::shared_mutex ThumbnailWait::mutex_;
225
WaitFor(const shared_ptr<ThumbnailSyncStatus> & thumbnailWait,int waitMs,unique_lock<mutex> & lck)226 static bool WaitFor(const shared_ptr<ThumbnailSyncStatus> &thumbnailWait, int waitMs, unique_lock<mutex> &lck)
227 {
228 bool ret = thumbnailWait->cond_.wait_for(lck, chrono::milliseconds(waitMs),
229 [thumbnailWait]() { return thumbnailWait->isSyncComplete_; });
230 if (!ret) {
231 MEDIA_INFO_LOG("IThumbnailHelper::Wait wait for lock timeout");
232 }
233 return ret;
234 }
235
InsertAndWait(const string & id,ThumbnailType type,const string & dateModified)236 WaitStatus ThumbnailWait::InsertAndWait(const string &id, ThumbnailType type, const string &dateModified)
237 {
238 id_ = id + ThumbnailUtils::GetThumbnailSuffix(type);
239 dateModified_ = dateModified;
240 unique_lock<shared_mutex> writeLck(mutex_);
241 auto iter = thumbnailMap_.find(id_);
242 if (iter != thumbnailMap_.end()) {
243 auto thumbnailWait = iter->second;
244 unique_lock<mutex> lck(thumbnailWait->mtx_);
245
246 // As data Source has changed, allowing this insertion to proceed and update dateModified
247 if (thumbnailWait->latestDateModified_ < dateModified) {
248 MEDIA_INFO_LOG("DateModified changed, continue to generate thumbnail, id: %{public}s, last: %{public}s,"
249 "new: %{public}s", id_.c_str(), thumbnailWait->latestDateModified_.c_str(), dateModified.c_str());
250 thumbnailWait->latestDateModified_ = dateModified;
251 return WaitStatus::WAIT_CONTINUE;
252 }
253
254 writeLck.unlock();
255 MEDIA_INFO_LOG("Waiting for thumbnail generation, id: %{public}s", id_.c_str());
256 thumbnailWait->cond_.wait(lck, [weakPtr = weak_ptr(thumbnailWait)]() {
257 if (auto sharedPtr = weakPtr.lock()) {
258 return sharedPtr->isSyncComplete_;
259 } else {
260 return true;
261 }
262 });
263 if (thumbnailWait->isCreateThumbnailSuccess_) {
264 MEDIA_INFO_LOG("Thumbnail generated successfully");
265 return WaitStatus::WAIT_SUCCESS;
266 } else {
267 MEDIA_ERR_LOG("Failed to generate thumbnail");
268 return WaitStatus::WAIT_FAILED;
269 }
270 } else {
271 shared_ptr<ThumbnailSyncStatus> thumbnailWait = make_shared<ThumbnailSyncStatus>();
272 thumbnailWait->latestDateModified_ = dateModified;
273 thumbnailMap_.insert(ThumbnailMap::value_type(id_, thumbnailWait));
274 return WaitStatus::INSERT;
275 }
276 }
277
CheckCloudReadResult(CloudLoadType cloudLoadType,CloudReadStatus status)278 WaitStatus CheckCloudReadResult(CloudLoadType cloudLoadType, CloudReadStatus status)
279 {
280 switch (status) {
281 case CloudReadStatus::FAIL:
282 MEDIA_INFO_LOG("Fail to cloud read thumbnail, type: %{public}d", cloudLoadType);
283 return WaitStatus::WAIT_FAILED;
284 break;
285 case CloudReadStatus::SUCCESS:
286 MEDIA_INFO_LOG("Success to cloud read thumbnail, type: %{public}d", cloudLoadType);
287 return WaitStatus::WAIT_SUCCESS;
288 break;
289 case CloudReadStatus::START:
290 MEDIA_INFO_LOG("Continue to cloud read thumbnail, type: %{public}d", cloudLoadType);
291 return WaitStatus::WAIT_CONTINUE;
292 break;
293 default:
294 break;
295 }
296 return WaitStatus::WAIT_FAILED;
297 }
298
CloudInsertAndWait(const string & id,CloudLoadType cloudLoadType)299 WaitStatus ThumbnailWait::CloudInsertAndWait(const string &id, CloudLoadType cloudLoadType)
300 {
301 id_ = id + ".cloud";
302 unique_lock<shared_mutex> writeLck(mutex_);
303 auto iter = thumbnailMap_.find(id_);
304 if (iter != thumbnailMap_.end()) {
305 auto thumbnailWait = iter->second;
306 unique_lock<mutex> lck(thumbnailWait->mtx_);
307 writeLck.unlock();
308 MEDIA_INFO_LOG("Waiting for thumbnail generation, id: %{public}s", id_.c_str());
309 thumbnailWait->cond_.wait(lck, [weakPtr = weak_ptr(thumbnailWait)]() {
310 if (auto sharedPtr = weakPtr.lock()) {
311 return sharedPtr->isSyncComplete_;
312 } else {
313 return true;
314 }
315 });
316 thumbnailWait->isSyncComplete_ = false;
317 thumbnailWait->cloudLoadType_ = cloudLoadType;
318 unique_lock<shared_mutex> evokeLck(mutex_);
319 thumbnailMap_.emplace(ThumbnailMap::value_type(id_, thumbnailWait));
320 evokeLck.unlock();
321
322 if (cloudLoadType == CLOUD_DOWNLOAD) {
323 MEDIA_INFO_LOG("Continue to generate thumbnail");
324 return WaitStatus::WAIT_CONTINUE;
325 }
326 if (cloudLoadType == CLOUD_READ_THUMB) {
327 return CheckCloudReadResult(cloudLoadType, thumbnailWait->CloudLoadThumbnailStatus_);
328 }
329 if (cloudLoadType == CLOUD_READ_LCD) {
330 return CheckCloudReadResult(cloudLoadType, thumbnailWait->CloudLoadLcdStatus_);
331 }
332 MEDIA_INFO_LOG("Cloud generate thumbnail successfully");
333 return WaitStatus::WAIT_SUCCESS;
334 } else {
335 shared_ptr<ThumbnailSyncStatus> thumbnailWait = make_shared<ThumbnailSyncStatus>();
336 thumbnailWait->cloudLoadType_ = cloudLoadType;
337 thumbnailMap_.insert(ThumbnailMap::value_type(id_, thumbnailWait));
338 return WaitStatus::INSERT;
339 }
340 }
341
TrySaveCurrentPixelMap(ThumbnailData & data,ThumbnailType type)342 bool ThumbnailWait::TrySaveCurrentPixelMap(ThumbnailData &data, ThumbnailType type)
343 {
344 ThumbnailType idType = (type == ThumbnailType::LCD || type == ThumbnailType::LCD_EX) ?
345 ThumbnailType::LCD : ThumbnailType::THUMB;
346 id_ = data.id + ThumbnailUtils::GetThumbnailSuffix(idType);
347 MEDIA_INFO_LOG("Save current pixelMap, path: %{public}s, type: %{public}d",
348 DfxUtils::GetSafePath(data.path).c_str(), type);
349 unique_lock<shared_mutex> writeLck(mutex_);
350 auto iter = thumbnailMap_.find(id_);
351 if (iter != thumbnailMap_.end()) {
352 auto thumbnailWait = iter->second;
353 unique_lock<mutex> lck(thumbnailWait->mtx_);
354 writeLck.unlock();
355 if (!thumbnailWait->CheckSavedFileMap(data.id, type, data.dateModified)) {
356 MEDIA_ERR_LOG("TrySaveCurrentPixelMap cancelled, latest file exists, path: %{public}s",
357 DfxUtils::GetSafePath(data.path).c_str());
358 return false;
359 }
360
361 int err = ThumbnailUtils::TrySaveFile(data, type);
362 if (err < 0) {
363 MEDIA_ERR_LOG("TrySaveCurrentPixelMap failed: %{public}d, path: %{public}s", err,
364 DfxUtils::GetSafePath(data.path).c_str());
365 return false;
366 }
367
368 if (!thumbnailWait->UpdateSavedFileMap(data.id, type, data.dateModified)) {
369 MEDIA_ERR_LOG("UpdateSavedFileMap failed while save pixelMap, path: %{public}s",
370 DfxUtils::GetSafePath(data.path).c_str());
371 return false;
372 }
373 } else {
374 MEDIA_ERR_LOG("TrySaveCurrentPixelMap cancelled, corresponding task has finished, path: %{public}s",
375 DfxUtils::GetSafePath(data.path).c_str());
376 return false;
377 }
378 return true;
379 }
380
TrySaveCurrentPicture(ThumbnailData & data,bool isSourceEx,const string & tempOutputPath)381 bool ThumbnailWait::TrySaveCurrentPicture(ThumbnailData &data, bool isSourceEx, const string &tempOutputPath)
382 {
383 id_ = data.id + ThumbnailUtils::GetThumbnailSuffix(ThumbnailType::LCD);
384 MEDIA_INFO_LOG("Save current picture, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
385 unique_lock<shared_mutex> writeLck(mutex_);
386 auto iter = thumbnailMap_.find(id_);
387 if (iter != thumbnailMap_.end()) {
388 auto thumbnailWait = iter->second;
389 unique_lock<mutex> lck(thumbnailWait->mtx_);
390 writeLck.unlock();
391 ThumbnailType lcdType = isSourceEx ? ThumbnailType::LCD_EX : ThumbnailType::LCD;
392 if (!thumbnailWait->CheckSavedFileMap(data.id, lcdType, data.dateModified)) {
393 MEDIA_ERR_LOG("TrySaveCurrentPicture cancelled, latest file exists, path: %{public}s",
394 DfxUtils::GetSafePath(data.path).c_str());
395 ThumbnailUtils::CancelAfterPacking(tempOutputPath);
396 return false;
397 }
398
399 if (!ThumbnailUtils::SaveAfterPacking(data, isSourceEx, tempOutputPath)) {
400 MEDIA_ERR_LOG("TrySaveCurrentPicture failed, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
401 return false;
402 }
403
404 if (!thumbnailWait->UpdateSavedFileMap(data.id, lcdType, data.dateModified)) {
405 MEDIA_ERR_LOG("UpdateSavedFileMap failed while save picture, path: %{public}s",
406 DfxUtils::GetSafePath(data.path).c_str());
407 return false;
408 }
409 } else {
410 MEDIA_ERR_LOG("TrySaveCurrentPicture cancelled, corresponding task has finished, path: %{public}s",
411 DfxUtils::GetSafePath(data.path).c_str());
412 ThumbnailUtils::CancelAfterPacking(tempOutputPath);
413 return false;
414 }
415 return true;
416 }
417
CheckAndWait(const string & id,bool isLcd)418 void ThumbnailWait::CheckAndWait(const string &id, bool isLcd)
419 {
420 id_ = id;
421
422 if (isLcd) {
423 id_ += THUMBNAIL_LCD_SUFFIX;
424 } else {
425 id_ += THUMBNAIL_THUMB_SUFFIX;
426 }
427 shared_lock<shared_mutex> readLck(mutex_);
428 auto iter = thumbnailMap_.find(id_);
429 if (iter != thumbnailMap_.end()) {
430 auto thumbnailWait = iter->second;
431 unique_lock<mutex> lck(thumbnailWait->mtx_);
432 readLck.unlock();
433 WaitFor(thumbnailWait, WAIT_FOR_MS, lck);
434 }
435 }
436
UpdateThumbnailMap()437 void ThumbnailWait::UpdateThumbnailMap()
438 {
439 unique_lock<shared_mutex> writeLck(mutex_);
440 auto iter = thumbnailMap_.find(id_);
441 if (iter != thumbnailMap_.end()) {
442 auto thumbnailWait = iter->second;
443 {
444 unique_lock<mutex> lck(thumbnailWait->mtx_);
445 writeLck.unlock();
446 thumbnailWait->isCreateThumbnailSuccess_ = true;
447 needRelease_ = thumbnailWait->latestDateModified_ == dateModified_;
448 }
449 if (!needRelease_) {
450 MEDIA_INFO_LOG("Latest task has come, id: %{public}s", id_.c_str());
451 }
452 } else {
453 MEDIA_ERR_LOG("Update ThumbnailMap failed, id: %{public}s", id_.c_str());
454 }
455 }
456
UpdateCloudLoadThumbnailMap(CloudLoadType cloudLoadType,bool isLoadSuccess)457 void ThumbnailWait::UpdateCloudLoadThumbnailMap(CloudLoadType cloudLoadType, bool isLoadSuccess)
458 {
459 unique_lock<shared_mutex> writeLck(mutex_);
460 auto iter = thumbnailMap_.find(id_);
461 if (iter != thumbnailMap_.end()) {
462 auto thumbnailWait = iter->second;
463 {
464 unique_lock<mutex> lck(thumbnailWait->mtx_);
465 writeLck.unlock();
466 switch (cloudLoadType) {
467 case CLOUD_READ_THUMB:
468 thumbnailWait->CloudLoadThumbnailStatus_ =
469 isLoadSuccess ? CloudReadStatus::SUCCESS : CloudReadStatus::FAIL;
470 break;
471 case CLOUD_READ_LCD:
472 thumbnailWait->CloudLoadLcdStatus_ =
473 isLoadSuccess ? CloudReadStatus::SUCCESS : CloudReadStatus::FAIL;
474 break;
475 case CLOUD_DOWNLOAD:
476 thumbnailWait->CloudLoadThumbnailStatus_ =
477 isLoadSuccess ? CloudReadStatus::SUCCESS : CloudReadStatus::FAIL;
478 thumbnailWait->CloudLoadLcdStatus_ =
479 isLoadSuccess ? CloudReadStatus::SUCCESS : CloudReadStatus::FAIL;
480 break;
481 default:
482 break;
483 }
484 }
485 } else {
486 MEDIA_ERR_LOG("Update CloudLoadThumbnailMap failed, id: %{public}s", id_.c_str());
487 }
488 }
489
Notify()490 void ThumbnailWait::Notify()
491 {
492 unique_lock<shared_mutex> writeLck(mutex_);
493 auto iter = thumbnailMap_.find(id_);
494 if (iter != thumbnailMap_.end()) {
495 auto thumbnailWait = iter->second;
496 {
497 unique_lock<mutex> lck(thumbnailWait->mtx_);
498 if (!dateModified_.empty() && thumbnailWait->latestDateModified_ > dateModified_) {
499 MEDIA_INFO_LOG("Latest task has come, no need to notify, id: %{public}s", id_.c_str());
500 return;
501 }
502 thumbnailMap_.erase(iter);
503 writeLck.unlock();
504 thumbnailWait->isSyncComplete_ = true;
505 }
506 if (thumbnailWait->cloudLoadType_ == CloudLoadType::NONE) {
507 thumbnailWait->cond_.notify_all();
508 } else {
509 thumbnailWait->cond_.notify_one();
510 }
511 }
512 }
513
CheckSavedFileMap(const string & id,ThumbnailType type,const string & dateModified)514 bool ThumbnailSyncStatus::CheckSavedFileMap(const string &id, ThumbnailType type, const string &dateModified)
515 {
516 std::string saveId = id + ThumbnailUtils::GetThumbnailSuffix(type);
517 auto iter = latestSavedFileMap_.find(id);
518 if (iter != latestSavedFileMap_.end() && (iter->second > dateModified)) {
519 return false;
520 }
521 return true;
522 }
523
UpdateSavedFileMap(const string & id,ThumbnailType type,const string & dateModified)524 bool ThumbnailSyncStatus::UpdateSavedFileMap(const string &id, ThumbnailType type, const string &dateModified)
525 {
526 std::string saveId = id + ThumbnailUtils::GetThumbnailSuffix(type);
527 auto iter = latestSavedFileMap_.find(id);
528 if (iter != latestSavedFileMap_.end()) {
529 if (iter->second > dateModified) {
530 return false;
531 } else {
532 iter->second = dateModified;
533 }
534 } else {
535 latestSavedFileMap_.emplace(id, dateModified);
536 }
537 return true;
538 }
539
TryLoadSource(ThumbRdbOpt & opts,ThumbnailData & data)540 bool IThumbnailHelper::TryLoadSource(ThumbRdbOpt &opts, ThumbnailData &data)
541 {
542 if (!data.source.IsEmptySource()) {
543 return true;
544 }
545
546 if (data.loaderOpts.loadingStates.empty()) {
547 MEDIA_ERR_LOG("try load source failed, the loading source states is empty.");
548 return false;
549 }
550
551 if (!ThumbnailUtils::LoadSourceImage(data)) {
552 if (opts.path.empty()) {
553 MEDIA_ERR_LOG("LoadSourceImage faild, %{public}s", DfxUtils::GetSafePath(data.path).c_str());
554 VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN},
555 {KEY_OPT_FILE, data.path}, {KEY_OPT_TYPE, OptType::THUMB}};
556 PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
557 return false;
558 } else {
559 opts.path = "";
560 ThumbnailUtils::GetThumbnailInfo(opts, data);
561 if (access(data.path.c_str(), F_OK) == 0) {
562 return true;
563 }
564 if (!ThumbnailUtils::LoadSourceImage(data)) {
565 VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__},
566 {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN}, {KEY_OPT_FILE, data.path}, {KEY_OPT_TYPE, OptType::THUMB}};
567 PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
568 return false;
569 }
570 }
571 }
572 return true;
573 }
574
TrySavePixelMap(ThumbnailData & data,ThumbnailType type)575 bool IThumbnailHelper::TrySavePixelMap(ThumbnailData &data, ThumbnailType type)
576 {
577 if (!data.needCheckWaitStatus) {
578 int err = ThumbnailUtils::TrySaveFile(data, type);
579 if (err < 0) {
580 MEDIA_ERR_LOG("No wait TrySavePixelMap failed: %{public}d, path: %{public}s", err,
581 DfxUtils::GetSafePath(data.path).c_str());
582 return false;
583 }
584 return true;
585 }
586 ThumbnailWait thumbnailWait(false);
587 if (!thumbnailWait.TrySaveCurrentPixelMap(data, type)) {
588 MEDIA_ERR_LOG("TrySavePixelMap failed, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
589 return false;
590 }
591 return true;
592 }
593
TrySavePicture(ThumbnailData & data,bool isSourceEx,const string & tempOutputPath)594 bool IThumbnailHelper::TrySavePicture(ThumbnailData &data, bool isSourceEx, const string &tempOutputPath)
595 {
596 if (!data.needCheckWaitStatus) {
597 if (!ThumbnailUtils::SaveAfterPacking(data, isSourceEx, tempOutputPath)) {
598 MEDIA_ERR_LOG("No wait TrySavePicture failed, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
599 return false;
600 }
601 return true;
602 }
603 ThumbnailWait thumbnailWait(false);
604 if (!thumbnailWait.TrySaveCurrentPicture(data, isSourceEx, tempOutputPath)) {
605 MEDIA_ERR_LOG("TrySavePicture failed, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
606 return false;
607 }
608 return true;
609 }
610
DoCreateLcd(ThumbRdbOpt & opts,ThumbnailData & data,WaitStatus & ret)611 bool IThumbnailHelper::DoCreateLcd(ThumbRdbOpt &opts, ThumbnailData &data, WaitStatus &ret)
612 {
613 MEDIA_INFO_LOG("Start DoCreateLcd, id: %{public}s, path: %{public}s",
614 data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
615 ThumbnailWait thumbnailWait(true);
616 ret = thumbnailWait.InsertAndWait(data.id, ThumbnailType::LCD, data.dateModified);
617 data.needCheckWaitStatus = true;
618 if (ret != WaitStatus::INSERT && ret != WaitStatus::WAIT_CONTINUE) {
619 return ret == WaitStatus::WAIT_SUCCESS;
620 }
621
622 if (!IsCreateLcdSuccess(opts, data)) {
623 MEDIA_ERR_LOG("Fail to create lcd, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
624 return false;
625 }
626
627 if (data.orientation != 0 && !IsCreateLcdExSuccess(opts, data)) {
628 MEDIA_ERR_LOG("Fail to create lcdEx, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
629 }
630 thumbnailWait.UpdateThumbnailMap();
631 data.needCheckWaitStatus = false;
632 return true;
633 }
634
UpdateLcdDbState(ThumbRdbOpt & opts,ThumbnailData & data)635 void UpdateLcdDbState(ThumbRdbOpt &opts, ThumbnailData &data)
636 {
637 if (opts.table != PhotoColumn::PHOTOS_TABLE) {
638 return;
639 }
640 if (data.isNeedStoreSize) {
641 StoreThumbnailSize(opts, data);
642 }
643 data.isNeedStoreSize = true;
644 int err = 0;
645 if (!ThumbnailUtils::UpdateLcdInfo(opts, data, err)) {
646 MEDIA_INFO_LOG("UpdateLcdInfo faild err : %{public}d", err);
647 }
648 }
649
UpdateHighlightDbState(ThumbRdbOpt & opts,ThumbnailData & data)650 void IThumbnailHelper::UpdateHighlightDbState(ThumbRdbOpt &opts, ThumbnailData &data)
651 {
652 if (opts.table != PhotoColumn::HIGHLIGHT_TABLE) {
653 return;
654 }
655 int err = 0;
656 if (!ThumbnailUtils::UpdateHighlightInfo(opts, data, err)) {
657 MEDIA_ERR_LOG("UpdateHighlightInfo faild err : %{public}d", err);
658 }
659 }
660
SaveLcdPictureSource(ThumbRdbOpt & opts,ThumbnailData & data,bool isSourceEx)661 bool IThumbnailHelper::SaveLcdPictureSource(ThumbRdbOpt &opts, ThumbnailData &data, bool isSourceEx)
662 {
663 shared_ptr<Picture> lcdSource = isSourceEx ? data.source.GetPictureEx() : data.source.GetPicture();
664 if (lcdSource == nullptr) {
665 MEDIA_ERR_LOG("SaveLcdPictureSource failed, lcdSource is null");
666 return false;
667 }
668 if (lcdSource->GetMainPixel() == nullptr || lcdSource->GetGainmapPixelMap() == nullptr) {
669 MEDIA_ERR_LOG("SaveLcdPictureSource failed, mainpixel exist: %{public}d, gainMap exist: %{public}d",
670 lcdSource->GetMainPixel() == nullptr, lcdSource->GetGainmapPixelMap() == nullptr);
671 return false;
672 }
673 bool shouldReverseSize = !isSourceEx && (data.orientation % FLAT_ANGLE != 0);
674 int lcdDesiredWidth = shouldReverseSize ? data.lcdDesiredSize.height : data.lcdDesiredSize.width;
675 int lcdDesiredHeight = shouldReverseSize ? data.lcdDesiredSize.width : data.lcdDesiredSize.height;
676 std::shared_ptr<Picture> copySource;
677 if (lcdDesiredWidth != lcdSource->GetMainPixel()->GetWidth()) {
678 MEDIA_INFO_LOG("Copy and resize picture source for lcd desiredSize: %{public}s",
679 DfxUtils::GetSafePath(data.path).c_str());
680 copySource = ThumbnailImageFrameWorkUtils::CopyPictureSource(lcdSource);
681 CHECK_AND_RETURN_RET_LOG(copySource != nullptr, false, "SaveLcdPictureSource failed, CopyPictureSource failed");
682 if (lcdSource->GetMainPixel()->GetWidth() * lcdSource->GetMainPixel()->GetHeight() == 0) {
683 MEDIA_ERR_LOG("SaveLcdPictureSource failed, invalid mainpixel size");
684 return false;
685 }
686 float widthScale = (1.0f * lcdDesiredWidth) / lcdSource->GetMainPixel()->GetWidth();
687 float heightScale = (1.0f * lcdDesiredHeight) / lcdSource->GetMainPixel()->GetHeight();
688 lcdSource->GetMainPixel()->scale(widthScale, heightScale);
689 lcdSource->GetGainmapPixelMap()->scale(widthScale, heightScale);
690 }
691 std::string tempOutputPath;
692 if (!ThumbnailUtils::CompressPicture(data, isSourceEx, tempOutputPath)) {
693 MEDIA_ERR_LOG("SaveLcdPictureSource failed, CompressPicture failed");
694 return false;
695 }
696 if (!TrySavePicture(data, isSourceEx, tempOutputPath)) {
697 MEDIA_ERR_LOG("SaveLcdPictureSource failed, save picture failed");
698 return false;
699 }
700 if (copySource != nullptr) {
701 lcdSource = copySource;
702 }
703 if (!isSourceEx) {
704 UpdateLcdDbState(opts, data);
705 }
706 return true;
707 }
708
SaveLcdPixelMapSource(ThumbRdbOpt & opts,ThumbnailData & data,bool isSourceEx)709 bool IThumbnailHelper::SaveLcdPixelMapSource(ThumbRdbOpt &opts, ThumbnailData &data, bool isSourceEx)
710 {
711 shared_ptr<PixelMap> lcdSource = isSourceEx ? data.source.GetPixelMapEx() : data.source.GetPixelMap();
712 if (lcdSource == nullptr) {
713 MEDIA_ERR_LOG("SaveLcdPixelMapSource failed, lcdSource is null");
714 return false;
715 }
716 int lcdDesiredWidth;
717 int lcdDesiredHeight;
718 if (isSourceEx) {
719 lcdDesiredWidth = data.lcdDesiredSize.width;
720 lcdDesiredHeight = data.lcdDesiredSize.height;
721 } else {
722 lcdDesiredWidth = data.orientation % FLAT_ANGLE == 0 ? data.lcdDesiredSize.width : data.lcdDesiredSize.height;
723 lcdDesiredHeight = data.orientation % FLAT_ANGLE == 0 ? data.lcdDesiredSize.height : data.lcdDesiredSize.width;
724 }
725 if (lcdDesiredWidth != lcdSource->GetWidth()) {
726 MEDIA_INFO_LOG("Copy and resize data source for lcd desiredSize: %{public}s",
727 DfxUtils::GetSafePath(data.path).c_str());
728 auto copySource = ThumbnailImageFrameWorkUtils::CopyPixelMapSource(lcdSource);
729 lcdSource = std::move(copySource);
730 CHECK_AND_RETURN_RET_LOG(lcdSource != nullptr, false, "LcdSource is nullptr");
731 if (lcdSource->GetWidth() * lcdSource->GetHeight() == 0) {
732 MEDIA_ERR_LOG("CompressImage failed, invalid lcdSource");
733 return false;
734 }
735 float widthScale = (1.0f * lcdDesiredWidth) / lcdSource->GetWidth();
736 float heightScale = (1.0f * lcdDesiredHeight) / lcdSource->GetHeight();
737 lcdSource->scale(widthScale, heightScale);
738 }
739 if (!ThumbnailUtils::CompressImage(lcdSource, data.lcd, false, false, data.thumbnailQuality)) {
740 MEDIA_ERR_LOG("CompressImage failed");
741 return false;
742 }
743
744 if (!TrySavePixelMap(data, isSourceEx ? ThumbnailType::LCD_EX : ThumbnailType::LCD)) {
745 MEDIA_ERR_LOG("SaveLcd PixelMap failed: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
746 return false;
747 }
748
749 data.lcd.clear();
750 if (!isSourceEx) {
751 UpdateLcdDbState(opts, data);
752 }
753 return true;
754 }
755
IsCreateLcdSuccess(ThumbRdbOpt & opts,ThumbnailData & data)756 bool IThumbnailHelper::IsCreateLcdSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
757 {
758 data.loaderOpts.decodeInThumbSize = false;
759 data.loaderOpts.isHdr = true;
760 if (!TryLoadSource(opts, data)) {
761 MEDIA_ERR_LOG("load source is nullptr path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
762 return false;
763 }
764
765 if (data.source.IsEmptySource()) {
766 MEDIA_ERR_LOG("Fail to create lcd, source is nullptr");
767 return false;
768 }
769
770 if (data.source.HasPictureSource()) {
771 return SaveLcdPictureSource(opts, data, false);
772 } else {
773 return SaveLcdPixelMapSource(opts, data, false);
774 }
775 }
776
IsCreateLcdExSuccess(ThumbRdbOpt & opts,ThumbnailData & data)777 bool IThumbnailHelper::IsCreateLcdExSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
778 {
779 if (!data.isLocalFile) {
780 MEDIA_INFO_LOG("Create lcd when cloud loading, no need to create THM_EX, path: %{public}s, id: %{public}s",
781 DfxUtils::GetSafePath(opts.path).c_str(), data.id.c_str());
782 return false;
783 }
784
785 string fileName = GetThumbnailPath(data.path, THUMBNAIL_LCD_EX_SUFFIX);
786 string dirName = MediaFileUtils::GetParentPath(fileName);
787 if (!MediaFileUtils::CreateDirectory(dirName)) {
788 MEDIA_ERR_LOG("Fail to create directory, fileName: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
789 return false;
790 }
791
792 if (data.source.IsEmptySource()) {
793 MEDIA_ERR_LOG("Fail to create lcdEx, source is nullptr");
794 return false;
795 }
796
797 if (data.source.HasPictureSource()) {
798 return SaveLcdPictureSource(opts, data, true);
799 } else {
800 return SaveLcdPixelMapSource(opts, data, true);
801 }
802 }
803
GenThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,const ThumbnailType type)804 bool IThumbnailHelper::GenThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, const ThumbnailType type)
805 {
806 auto pixelMap = data.source.GetPixelMap();
807 if (pixelMap == nullptr) {
808 MEDIA_ERR_LOG("source is nullptr when generate type: %{public}s", TYPE_NAME_MAP.at(type).c_str());
809 return false;
810 }
811
812 if (type == ThumbnailType::THUMB || type == ThumbnailType::THUMB_ASTC) {
813 if (!ThumbnailUtils::CompressImage(pixelMap, type == ThumbnailType::THUMB ? data.thumbnail : data.thumbAstc,
814 type == ThumbnailType::THUMB_ASTC)) {
815 MEDIA_ERR_LOG("CompressImage faild id %{public}s", opts.row.c_str());
816 VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN},
817 {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
818 PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
819 return false;
820 }
821 } else if (type == ThumbnailType::MTH_ASTC || type == ThumbnailType::YEAR_ASTC) {
822 if (!ThumbnailUtils::CheckDateTaken(opts, data)) {
823 MEDIA_ERR_LOG("CheckDateTaken failed in GenThumbnail");
824 return false;
825 }
826 if (!GenMonthAndYearAstcData(data, type)) {
827 MEDIA_ERR_LOG("GenMonthAndYearAstcData failed in GenThumbnail");
828 return false;
829 }
830 } else {
831 MEDIA_ERR_LOG("invalid thumbnail type: %{public}d", type);
832 return false;
833 }
834
835 if (!TrySavePixelMap(data, type)) {
836 MEDIA_ERR_LOG("SaveThumbnailData failed: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
837 return false;
838 }
839 data.thumbnail.clear();
840 return true;
841 }
842
GenThumbnailEx(ThumbRdbOpt & opts,ThumbnailData & data)843 bool IThumbnailHelper::GenThumbnailEx(ThumbRdbOpt &opts, ThumbnailData &data)
844 {
845 if (!data.isLocalFile) {
846 MEDIA_INFO_LOG("Create thumb when cloud loading, no need to create THM_EX, path: %{public}s, id: %{public}s",
847 DfxUtils::GetSafePath(opts.path).c_str(), data.id.c_str());
848 return false;
849 }
850
851 string fileName = GetThumbnailPath(data.path, THUMBNAIL_THUMB_EX_SUFFIX);
852 string dirName = MediaFileUtils::GetParentPath(fileName);
853 if (!MediaFileUtils::CreateDirectory(dirName)) {
854 MEDIA_ERR_LOG("Fail to create directory, fileName: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
855 return false;
856 }
857
858 auto pixelMapEx = data.source.GetPixelMapEx();
859 if (pixelMapEx == nullptr) {
860 MEDIA_ERR_LOG("sourceEx is nullptr when generate thumbnailEx, path: %{public}s",
861 DfxUtils::GetSafePath(opts.path).c_str());
862 return false;
863 }
864
865 if (!ThumbnailUtils::CompressImage(pixelMapEx, data.thumbnail, false)) {
866 MEDIA_ERR_LOG("CompressImage failed id %{public}s", opts.row.c_str());
867 return false;
868 }
869
870 if (!TrySavePixelMap(data, ThumbnailType::THUMB_EX)) {
871 MEDIA_ERR_LOG("SaveThumbnailEx failed: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
872 return false;
873 }
874 data.thumbnail.clear();
875 return true;
876 }
877
GenMonthAndYearAstcData(ThumbnailData & data,const ThumbnailType type)878 bool IThumbnailHelper::GenMonthAndYearAstcData(ThumbnailData &data, const ThumbnailType type)
879 {
880 Size size;
881 if (type == ThumbnailType::MTH_ASTC) {
882 size = {DEFAULT_MTH_SIZE, DEFAULT_MTH_SIZE };
883 } else if (type == ThumbnailType::YEAR_ASTC) {
884 size = {DEFAULT_YEAR_SIZE, DEFAULT_YEAR_SIZE };
885 } else {
886 MEDIA_ERR_LOG("invalid thumbnail type");
887 return false;
888 }
889 ThumbnailUtils::GenTargetPixelmap(data, size);
890 auto pixelMap = data.source.GetPixelMap();
891 #ifdef IMAGE_COLORSPACE_FLAG
892 if (pixelMap->ApplyColorSpace(ColorManager::ColorSpaceName::DISPLAY_P3) != E_OK) {
893 MEDIA_ERR_LOG("ApplyColorSpace to p3 failed");
894 }
895 #endif
896 if (!ThumbnailUtils::CompressImage(pixelMap,
897 (type == ThumbnailType::MTH_ASTC) ? data.monthAstc : data.yearAstc, true)) {
898 MEDIA_ERR_LOG("CompressImage to astc failed");
899 return false;
900 }
901 return true;
902 }
903
904 // After all thumbnails are generated, the value of column "thumbnail_ready" in rdb needs to be updated,
905 // And if generate successfully, application should receive a notification at the same time.
UpdateThumbnailState(const ThumbRdbOpt & opts,ThumbnailData & data,const bool isSuccess)906 bool IThumbnailHelper::UpdateThumbnailState(const ThumbRdbOpt &opts, ThumbnailData &data, const bool isSuccess)
907 {
908 if (data.fileUri.empty()) {
909 data.fileUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::DEFAULT_PHOTO_URI + "/", data.id,
910 MediaFileUtils::GetExtraUri(data.displayName, data.path));
911 }
912 return isSuccess ? UpdateSuccessState(opts, data) : UpdateFailState(opts, data);
913 }
914
915 // This method has to be called before updating rdb
IsPhotoVisible(const ThumbRdbOpt & opts,const ThumbnailData & data)916 static int32_t IsPhotoVisible(const ThumbRdbOpt &opts, const ThumbnailData &data)
917 {
918 vector<string> columns = {
919 PhotoColumn::PHOTO_THUMBNAIL_VISIBLE
920 };
921 if (data.id.empty() && opts.row.empty()) {
922 MEDIA_ERR_LOG("SendThumbNotify thumb is empty");
923 return 0;
924 }
925 string fileId = data.id.empty() ? opts.row : data.id;
926 string strQueryCondition = MEDIA_DATA_DB_ID + " = " + fileId;
927 RdbPredicates rdbPredicates(PhotoColumn::PHOTOS_TABLE);
928 rdbPredicates.SetWhereClause(strQueryCondition);
929 if (opts.store == nullptr) {
930 MEDIA_ERR_LOG("SendThumbNotify opts.store is nullptr");
931 return 0;
932 }
933 auto resultSet = opts.store->QueryByStep(rdbPredicates, columns);
934 if (resultSet == nullptr) {
935 MEDIA_ERR_LOG("SendThumbNotify result is null");
936 return 0;
937 }
938 auto ret = resultSet->GoToFirstRow();
939 if (ret != NativeRdb::E_OK) {
940 MEDIA_ERR_LOG("SendThumbNotify go to first row failed");
941 return 0;
942 }
943 return GetInt32Val(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, resultSet);
944 }
945
UpdateSuccessState(const ThumbRdbOpt & opts,const ThumbnailData & data)946 bool IThumbnailHelper::UpdateSuccessState(const ThumbRdbOpt &opts, const ThumbnailData &data)
947 {
948 int thumbnailVisible = IsPhotoVisible(opts, data);
949 int32_t err = UpdateThumbDbState(opts, data);
950 if (err != E_OK) {
951 MEDIA_ERR_LOG("update thumbnail_ready failed, err = %{public}d", err);
952 return false;
953 }
954
955 auto watch = MediaLibraryNotify::GetInstance();
956 if (watch == nullptr) {
957 MEDIA_ERR_LOG("SendThumbNotify watch is nullptr");
958 return false;
959 }
960 if (thumbnailVisible) {
961 watch->Notify(data.fileUri, NotifyType::NOTIFY_THUMB_UPDATE);
962 } else {
963 watch->Notify(data.fileUri, NotifyType::NOTIFY_THUMB_ADD);
964 }
965 return true;
966 }
967
UpdateFailState(const ThumbRdbOpt & opts,const ThumbnailData & data)968 bool IThumbnailHelper::UpdateFailState(const ThumbRdbOpt &opts, const ThumbnailData &data)
969 {
970 if (opts.store == nullptr) {
971 MEDIA_ERR_LOG("opts.store is nullptr");
972 return false;
973 }
974 ValuesBucket values;
975 int changedRows;
976 values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_READY, static_cast<int64_t>(ThumbnailReady::GENERATE_THUMB_RETRY));
977 values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, 1);
978 int32_t err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
979 vector<string> { data.id });
980 if (err != NativeRdb::E_OK) {
981 MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
982 return false;
983 }
984 return true;
985 }
986
UpdateThumbDbState(const ThumbRdbOpt & opts,const ThumbnailData & data)987 int32_t IThumbnailHelper::UpdateThumbDbState(const ThumbRdbOpt &opts, const ThumbnailData &data)
988 {
989 ValuesBucket values;
990 int changedRows;
991 values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_READY, MediaFileUtils::UTCTimeMilliSeconds());
992 values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, 1);
993 Size lcdSize;
994 if (ThumbnailUtils::GetLocalThumbSize(data, ThumbnailType::LCD, lcdSize)) {
995 ThumbnailUtils::SetThumbnailSizeValue(values, lcdSize, PhotoColumn::PHOTO_LCD_SIZE);
996 values.PutLong(PhotoColumn::PHOTO_LCD_VISIT_TIME, static_cast<int64_t>(LcdReady::GENERATE_LCD_COMPLETED));
997 }
998 Size thumbSize;
999 if (ThumbnailUtils::GetLocalThumbSize(data, ThumbnailType::THUMB, thumbSize)) {
1000 ThumbnailUtils::SetThumbnailSizeValue(values, thumbSize, PhotoColumn::PHOTO_THUMB_SIZE);
1001 }
1002 int32_t err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
1003 vector<string> { data.id });
1004 StoreThumbnailSize(opts, data);
1005 if (err != NativeRdb::E_OK) {
1006 MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
1007 return E_ERR;
1008 }
1009 return E_OK;
1010 }
1011
DoCreateThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,WaitStatus & ret)1012 bool IThumbnailHelper::DoCreateThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, WaitStatus &ret)
1013 {
1014 MEDIA_INFO_LOG("Start DoCreateThumbnail, id: %{public}s, path: %{public}s",
1015 data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
1016 int64_t startTime = MediaFileUtils::UTCTimeMilliSeconds();
1017 ThumbnailWait thumbnailWait(true);
1018 ret = thumbnailWait.InsertAndWait(data.id, ThumbnailType::THUMB, data.dateModified);
1019 data.needCheckWaitStatus = true;
1020 if (ret != WaitStatus::INSERT && ret != WaitStatus::WAIT_CONTINUE) {
1021 return ret == WaitStatus::WAIT_SUCCESS;
1022 }
1023
1024 if (!IsCreateThumbnailSuccess(opts, data)) {
1025 MEDIA_ERR_LOG("Fail to create thumbnail, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
1026 return false;
1027 }
1028
1029 if (data.orientation != 0 && !IsCreateThumbnailExSuccess(opts, data)) {
1030 MEDIA_ERR_LOG("Fail to create thumbnailEx, path: %{public}s", DfxUtils::GetSafePath(opts.path).c_str());
1031 }
1032 thumbnailWait.UpdateThumbnailMap();
1033 data.needCheckWaitStatus = false;
1034 MediaLibraryAstcStat::GetInstance().AddAstcInfo(startTime, data.stats.scene,
1035 AstcGenScene::SCREEN_ON, data.id);
1036 return true;
1037 }
1038
IsCreateThumbnailSuccess(ThumbRdbOpt & opts,ThumbnailData & data)1039 bool IThumbnailHelper::IsCreateThumbnailSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
1040 {
1041 data.loaderOpts.decodeInThumbSize = true;
1042 if (!TryLoadSource(opts, data)) {
1043 MEDIA_ERR_LOG("DoCreateThumbnail failed, try to load source failed, id: %{public}s", data.id.c_str());
1044 return false;
1045 }
1046 auto pixelMap = data.source.GetPixelMap();
1047 if (pixelMap != nullptr && pixelMap->IsHdr()) {
1048 uint32_t ret = pixelMap->ToSdr();
1049 if (ret != E_OK) {
1050 MEDIA_ERR_LOG("DoCreateThumbnail failed to transform to sdr, id: %{public}s.", data.id.c_str());
1051 return false;
1052 }
1053 }
1054 if (!GenThumbnail(opts, data, ThumbnailType::THUMB)) {
1055 return false;
1056 }
1057 if (opts.table == AudioColumn::AUDIOS_TABLE) {
1058 MEDIA_DEBUG_LOG("AUDIOS_TABLE, no need to create all thumbnail");
1059 return true;
1060 }
1061
1062 if (ThumbnailUtils::IsSupportGenAstc() && !GenThumbnail(opts, data, ThumbnailType::THUMB_ASTC)) {
1063 return false;
1064 }
1065
1066 if (!data.tracks.empty()) {
1067 MEDIA_INFO_LOG("generate highlight frame, no need to create month and year astc");
1068 return true;
1069 }
1070
1071 // for some device that do not support KvStore, no need to generate the month and year astc.
1072 if (MediaLibraryKvStoreManager::GetInstance()
1073 .GetKvStore(KvStoreRoleType::OWNER, KvStoreValueType::MONTH_ASTC) == nullptr) {
1074 MEDIA_DEBUG_LOG("kvStore is nullptr, no need to create month and year astc");
1075 return true;
1076 }
1077 if (!GenThumbnail(opts, data, ThumbnailType::MTH_ASTC)) {
1078 return false;
1079 }
1080 if (!GenThumbnail(opts, data, ThumbnailType::YEAR_ASTC)) {
1081 return false;
1082 }
1083 return true;
1084 }
1085
IsCreateThumbnailExSuccess(ThumbRdbOpt & opts,ThumbnailData & data)1086 bool IThumbnailHelper::IsCreateThumbnailExSuccess(ThumbRdbOpt &opts, ThumbnailData &data)
1087 {
1088 if (!GenThumbnailEx(opts, data)) {
1089 MEDIA_ERR_LOG("Fail to create thumbnailEx, fileName: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1090 return false;
1091 }
1092 return true;
1093 }
1094
DoRotateThumbnail(ThumbRdbOpt & opts,ThumbnailData & data)1095 bool IThumbnailHelper::DoRotateThumbnail(ThumbRdbOpt &opts, ThumbnailData &data)
1096 {
1097 auto pixelMap = data.source.GetPixelMap();
1098 if (pixelMap == nullptr) {
1099 MEDIA_ERR_LOG("source is nullptr when rotate thumbnail path: %{public}s",
1100 DfxUtils::GetSafePath(data.path).c_str());
1101 return false;
1102 }
1103
1104 if (!ThumbnailUtils::CompressImage(pixelMap, data.thumbnail, false)) {
1105 MEDIA_ERR_LOG("CompressImage faild id %{public}s", data.id.c_str());
1106 return false;
1107 }
1108
1109 if (!TrySavePixelMap(data, ThumbnailType::THUMB)) {
1110 MEDIA_ERR_LOG("DoRotateThumbnail failed: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1111 return false;
1112 }
1113 data.thumbnail.clear();
1114 return true;
1115 }
1116
ScaleLcdToThumbnail(ThumbnailData & data)1117 static bool ScaleLcdToThumbnail(ThumbnailData &data)
1118 {
1119 if (data.source.IsEmptySource()) {
1120 MEDIA_ERR_LOG("data source is empty when scaling from lcd to thumb");
1121 return false;
1122 }
1123
1124 data.loaderOpts.decodeInThumbSize = true;
1125 if (data.source.HasPictureSource()) {
1126 MEDIA_INFO_LOG("Scale from picture source, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1127 auto mainPixelMap = data.source.GetPicture()->GetMainPixel();
1128 data.source.SetPixelMap(mainPixelMap);
1129 }
1130 if (!ThumbnailUtils::ScaleThumbnailFromSource(data, false)) {
1131 MEDIA_ERR_LOG("Fail to scale from LCD to THM, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1132 return false;
1133 }
1134
1135 if (data.orientation != 0 && data.source.HasPictureSource()) {
1136 MEDIA_INFO_LOG("Scale from picture source, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1137 auto mainPixelMapEx = data.source.GetPictureEx()->GetMainPixel();
1138 data.source.SetPixelMapEx(mainPixelMapEx);
1139 }
1140 if (data.orientation != 0 && !ThumbnailUtils::ScaleThumbnailFromSource(data, true)) {
1141 MEDIA_ERR_LOG("Fail to scale from LCD_EX to THM_EX, path: %{public}s",
1142 DfxUtils::GetSafePath(data.path).c_str());
1143 }
1144 return true;
1145 }
1146
DoCreateLcdAndThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,WaitStatus & ret)1147 bool IThumbnailHelper::DoCreateLcdAndThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, WaitStatus &ret)
1148 {
1149 MEDIA_INFO_LOG("Start DoCreateLcdAndThumbnail, id: %{public}s, path: %{public}s",
1150 data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
1151 data.isNeedStoreSize = false;
1152 DoCreateLcd(opts, data, ret);
1153 ScaleLcdToThumbnail(data);
1154 return DoCreateThumbnail(opts, data, ret);
1155 }
1156
GetAvailableThumbnailSuffix(ThumbnailData & data)1157 std::string GetAvailableThumbnailSuffix(ThumbnailData &data)
1158 {
1159 // Check whether the thumbnail data exist, firstly thumb then lcd, and return the corresponding suffix.
1160 // When there is no thumbnail data, return empty string.
1161 if (access(GetThumbnailPath(data.path, THUMBNAIL_THUMB_SUFFIX).c_str(), F_OK) == 0) {
1162 return THUMBNAIL_THUMB_SUFFIX;
1163 }
1164 if (access(GetThumbnailPath(data.path, THUMBNAIL_LCD_SUFFIX).c_str(), F_OK) == 0) {
1165 return THUMBNAIL_LCD_SUFFIX;
1166 }
1167 return "";
1168 }
1169
DoCreateAstc(ThumbRdbOpt & opts,ThumbnailData & data)1170 bool IThumbnailHelper::DoCreateAstc(ThumbRdbOpt &opts, ThumbnailData &data)
1171 {
1172 MEDIA_INFO_LOG("Start DoCreateAstc, id: %{public}s, path: %{public}s",
1173 data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
1174 data.loaderOpts.decodeInThumbSize = true;
1175 if (!TryLoadSource(opts, data)) {
1176 MEDIA_ERR_LOG("DoCreateAstc failed, try to load exist thumbnail failed, id: %{public}s", data.id.c_str());
1177 return false;
1178 }
1179 auto pixelMap = data.source.GetPixelMap();
1180 if (pixelMap != nullptr && pixelMap->IsHdr()) {
1181 uint32_t ret = pixelMap->ToSdr();
1182 if (ret != E_OK) {
1183 MEDIA_ERR_LOG("DoCreateAstc failed to transform to sdr, id: %{public}s.", data.id.c_str());
1184 return false;
1185 }
1186 }
1187 if (!GenThumbnail(opts, data, ThumbnailType::THUMB)) {
1188 MEDIA_ERR_LOG("DoCreateAstc GenThumbnail THUMB failed, id: %{public}s", data.id.c_str());
1189 return false;
1190 }
1191 if (!GenThumbnail(opts, data, ThumbnailType::THUMB_ASTC)) {
1192 VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__},
1193 {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN}, {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
1194 PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
1195 return false;
1196 }
1197 if (!GenThumbnail(opts, data, ThumbnailType::MTH_ASTC) || !GenThumbnail(opts, data, ThumbnailType::YEAR_ASTC)) {
1198 VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__},
1199 {KEY_ERR_CODE, E_THUMBNAIL_UNKNOWN}, {KEY_OPT_FILE, opts.path}, {KEY_OPT_TYPE, OptType::THUMB}};
1200 PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
1201 return false;
1202 }
1203 return true;
1204 }
1205
DoCreateAstcMthAndYear(ThumbRdbOpt & opts,ThumbnailData & data)1206 bool IThumbnailHelper::DoCreateAstcMthAndYear(ThumbRdbOpt &opts, ThumbnailData &data)
1207 {
1208 MEDIA_INFO_LOG("Start DoCreateAstcMthAndYear, id: %{public}s, path: %{public}s",
1209 data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
1210 data.loaderOpts.decodeInThumbSize = true;
1211 data.loaderOpts.desiredType = ThumbnailType::MTH_ASTC;
1212 if (!TryLoadSource(opts, data)) {
1213 MEDIA_ERR_LOG("DoCreateAstcMthAndYear failed, try load source failed, id: %{public}s", data.id.c_str());
1214 return false;
1215 }
1216 auto pixelMap = data.source.GetPixelMap();
1217 if (pixelMap == nullptr) {
1218 MEDIA_ERR_LOG("DoCreateAstc failed, no available pixelMap, id: %{public}s.", data.id.c_str());
1219 return false;
1220 }
1221 if (!GenThumbnail(opts, data, ThumbnailType::MTH_ASTC) || !GenThumbnail(opts, data, ThumbnailType::YEAR_ASTC)) {
1222 MEDIA_ERR_LOG("DoCreateAstc failed, GenThumbnail failed, id: %{public}s.", data.id.c_str());
1223 return false;
1224 }
1225 return true;
1226 }
1227
GenerateRotatedThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,ThumbnailType thumbType)1228 bool GenerateRotatedThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, ThumbnailType thumbType)
1229 {
1230 WaitStatus status;
1231 if (thumbType == ThumbnailType::LCD && !IThumbnailHelper::DoCreateLcd(opts, data, status)) {
1232 MEDIA_ERR_LOG("Get lcd thumbnail pixelmap, rotate lcd failed: %{public}s",
1233 DfxUtils::GetSafePath(data.path).c_str());
1234 return false;
1235 }
1236 if (thumbType != ThumbnailType::LCD && !IThumbnailHelper::DoRotateThumbnail(opts, data)) {
1237 MEDIA_ERR_LOG("Get default thumbnail pixelmap, rotate thumbnail failed: %{public}s",
1238 DfxUtils::GetSafePath(data.path).c_str());
1239 return false;
1240 }
1241 return true;
1242 }
1243
DecodeThumbnailFromFd(int32_t fd)1244 unique_ptr<PixelMap> DecodeThumbnailFromFd(int32_t fd)
1245 {
1246 SourceOptions opts;
1247 uint32_t err = 0;
1248 unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(fd, opts, err);
1249 if (imageSource == nullptr) {
1250 MEDIA_ERR_LOG("Decode thumbnail from fd failed, CreateImageSource err: %{public}d", err);
1251 return nullptr;
1252 }
1253
1254 ImageInfo imageInfo;
1255 err = imageSource->GetImageInfo(0, imageInfo);
1256 if (err != E_OK) {
1257 MEDIA_ERR_LOG("Decode thumbnail from fd failed, GetImageInfo err: %{public}d", err);
1258 return nullptr;
1259 }
1260
1261 DecodeOptions decodeOpts;
1262 decodeOpts.desiredDynamicRange = DecodeDynamicRange::SDR;
1263 decodeOpts.desiredPixelFormat = PixelFormat::RGBA_8888;
1264 unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, err);
1265 if (pixelMap == nullptr) {
1266 MEDIA_ERR_LOG("Decode thumbnail from fd failed, CreatePixelMap err: %{public}d", err);
1267 return nullptr;
1268 }
1269 return pixelMap;
1270 }
1271
DoCreateAstcEx(ThumbRdbOpt & opts,ThumbnailData & data,WaitStatus & ret)1272 bool IThumbnailHelper::DoCreateAstcEx(ThumbRdbOpt &opts, ThumbnailData &data, WaitStatus &ret)
1273 {
1274 ThumbnailWait thumbnailWait(true);
1275 ret = thumbnailWait.CloudInsertAndWait(data.id, CloudLoadType::CLOUD_DOWNLOAD);
1276 if (ret != WaitStatus::INSERT && ret != WaitStatus::WAIT_CONTINUE) {
1277 return ret == WaitStatus::WAIT_SUCCESS;
1278 }
1279
1280 MEDIA_INFO_LOG("Start DoCreateAstcEx, id: %{public}s, path: %{public}s",
1281 data.id.c_str(), DfxUtils::GetSafePath(data.path).c_str());
1282 string fileName = GetThumbnailPath(data.path, THUMBNAIL_LCD_EX_SUFFIX);
1283 if (access(fileName.c_str(), F_OK) != 0) {
1284 MEDIA_ERR_LOG("No available file in THM_EX, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1285 return false;
1286 }
1287
1288 if (!DoCreateLcd(opts, data, ret)) {
1289 MEDIA_ERR_LOG("Fail to create lcd, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1290 return false;
1291 }
1292
1293 data.loaderOpts.decodeInThumbSize = true;
1294 if (data.source.HasPictureSource()) {
1295 MEDIA_INFO_LOG("Scale from picture source, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1296 auto mainPixelMap = data.source.GetPicture()->GetMainPixel();
1297 data.source.SetPixelMap(mainPixelMap);
1298 }
1299 if (!ThumbnailUtils::ScaleThumbnailFromSource(data, false)) {
1300 MEDIA_ERR_LOG("Fail to scale from LCD to THM, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1301 return false;
1302 }
1303 if (!DoCreateThumbnail(opts, data, ret)) {
1304 MEDIA_ERR_LOG("Fail to create thumbnail, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1305 return false;
1306 }
1307
1308 thumbnailWait.UpdateCloudLoadThumbnailMap(CloudLoadType::CLOUD_DOWNLOAD, true);
1309 return true;
1310 }
1311
DoRotateThumbnailEx(ThumbRdbOpt & opts,ThumbnailData & data,int32_t fd,ThumbnailType thumbType)1312 bool IThumbnailHelper::DoRotateThumbnailEx(ThumbRdbOpt &opts, ThumbnailData &data, int32_t fd, ThumbnailType thumbType)
1313 {
1314 ThumbnailWait thumbnailWait(true);
1315 auto ret = thumbnailWait.CloudInsertAndWait(data.id, thumbType == ThumbnailType::LCD ?
1316 CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB);
1317 if (ret != WaitStatus::INSERT && ret != WaitStatus::WAIT_CONTINUE) {
1318 close(fd);
1319 return ret == WaitStatus::WAIT_SUCCESS;
1320 }
1321
1322 auto dataSourcePtr = DecodeThumbnailFromFd(fd);
1323 std::shared_ptr<PixelMap> dataSource = std::move(dataSourcePtr);
1324 if (dataSource == nullptr) {
1325 MEDIA_ERR_LOG("GetThumbnailPixelMap failed, dataSource is nullptr, path: %{public}s",
1326 DfxUtils::GetSafePath(data.path).c_str());
1327 close(fd);
1328 thumbnailWait.UpdateCloudLoadThumbnailMap(thumbType == ThumbnailType::LCD ?
1329 CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB, false);
1330 return false;
1331 }
1332 close(fd);
1333
1334 PostProc::RotateInRectangularSteps(*(dataSource.get()), static_cast<float>(data.orientation), true);
1335 data.source.SetPixelMap(dataSource);
1336 if (!GenerateRotatedThumbnail(opts, data, thumbType)) {
1337 MEDIA_ERR_LOG("GenerateRotatedThumbnail failed, path: %{public}s", DfxUtils::GetSafePath(data.path).c_str());
1338 thumbnailWait.UpdateCloudLoadThumbnailMap(thumbType == ThumbnailType::LCD ?
1339 CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB, false);
1340 return false;
1341 }
1342
1343 thumbnailWait.UpdateCloudLoadThumbnailMap(thumbType == ThumbnailType::LCD ?
1344 CloudLoadType::CLOUD_READ_LCD : CloudLoadType::CLOUD_READ_THUMB, true);
1345 return true;
1346 }
1347
IsPureCloudImage(ThumbRdbOpt & opts)1348 bool IThumbnailHelper::IsPureCloudImage(ThumbRdbOpt &opts)
1349 {
1350 vector<string> columns = {
1351 MEDIA_DATA_DB_ID,
1352 PhotoColumn::PHOTO_POSITION
1353 };
1354 if (opts.row.empty() || opts.table.empty()) {
1355 MEDIA_ERR_LOG("IsPureCloudImage opts.row is empty");
1356 return false;
1357 }
1358 string strQueryCondition = MEDIA_DATA_DB_ID + " = " + opts.row;
1359 RdbPredicates rdbPredicates(opts.table);
1360 rdbPredicates.SetWhereClause(strQueryCondition);
1361 if (opts.store == nullptr) {
1362 MEDIA_ERR_LOG("IsPureCloudImage opts.store is nullptr");
1363 return false;
1364 }
1365 auto resultSet = opts.store->QueryByStep(rdbPredicates, columns);
1366 if (resultSet == nullptr) {
1367 MEDIA_ERR_LOG("IsPureCloudImage result set is null");
1368 return false;
1369 }
1370 auto ret = resultSet->GoToFirstRow();
1371 if (ret != NativeRdb::E_OK) {
1372 MEDIA_ERR_LOG("IsPureCloudImage go to first row failed");
1373 return false;
1374 }
1375 int photoPosition = GetInt32Val(PhotoColumn::PHOTO_POSITION, resultSet);
1376
1377 // if current image is a pure cloud image, it's photo position column in database will be 2
1378 return photoPosition == 2;
1379 }
1380 } // namespace Media
1381 } // namespace OHOS