• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 
16 #define MLOG_TAG "MovingPhotoProcessor"
17 
18 #include "moving_photo_processor.h"
19 
20 #include <fcntl.h>
21 
22 #include "abs_rdb_predicates.h"
23 #include "cloud_sync_helper.h"
24 #include "directory_ex.h"
25 #include "media_column.h"
26 #include "media_file_utils.h"
27 #include "media_log.h"
28 #include "medialibrary_db_const.h"
29 #include "medialibrary_errno.h"
30 #include "medialibrary_rdb_utils.h"
31 #include "medialibrary_rdbstore.h"
32 #include "medialibrary_unistore_manager.h"
33 #include "mimetype_utils.h"
34 #include "moving_photo_file_utils.h"
35 #include "parameters.h"
36 #include "rdb_store.h"
37 #include "rdb_utils.h"
38 #include "result_set_utils.h"
39 #include "scanner_utils.h"
40 #include "userfile_manager_types.h"
41 #include "values_bucket.h"
42 
43 using namespace std;
44 using namespace OHOS::NativeRdb;
45 
46 namespace OHOS {
47 namespace Media {
48 static constexpr int32_t MOVING_PHOTO_PROCESS_NUM = 100;
49 static constexpr int32_t DIRTY_NOT_UPLOADING = -1;
50 static constexpr int32_t DEFAULT_EXTRA_DATA_SIZE = MIN_STANDARD_SIZE;
51 static constexpr int32_t LIVE_PHOTO_QUERY_NUM = 3000;
52 static constexpr int32_t LIVE_PHOTO_PROCESS_NUM = 200;
53 
54 static const string MOVING_PHOTO_PROCESS_FLAG = "multimedia.medialibrary.cloneFlag";
55 static const string LIVE_PHOTO_COMPAT_DONE = "0";
56 
57 bool MovingPhotoProcessor::isProcessing_ = false;
58 
IsCloudLivePhotoRefreshed()59 static bool IsCloudLivePhotoRefreshed()
60 {
61     string refreshStatus = system::GetParameter(REFRESH_CLOUD_LIVE_PHOTO_FLAG, CLOUD_LIVE_PHOTO_REFRESHED);
62     return refreshStatus.compare(CLOUD_LIVE_PHOTO_REFRESHED) == 0;
63 }
64 
StartProcessMovingPhoto()65 void MovingPhotoProcessor::StartProcessMovingPhoto()
66 {
67     auto resultSet = QueryMovingPhoto();
68     CHECK_AND_RETURN_LOG(resultSet != nullptr, "Failed to query moving photo");
69 
70     MovingPhotoDataList dataList;
71     ParseMovingPhotoData(resultSet, dataList);
72     CHECK_AND_RETURN_LOG(!dataList.movingPhotos.empty(), "No moving photo need to be processed");
73 
74     isProcessing_ = true;
75     CompatMovingPhoto(dataList);
76 }
77 
GetLivePhotoCompatId()78 static string GetLivePhotoCompatId()
79 {
80     return system::GetParameter(COMPAT_LIVE_PHOTO_FILE_ID, LIVE_PHOTO_COMPAT_DONE);
81 }
82 
IsLivePhotoCompatDone()83 static bool IsLivePhotoCompatDone()
84 {
85     string currentFileId = GetLivePhotoCompatId();
86     return currentFileId.compare(LIVE_PHOTO_COMPAT_DONE) == 0;
87 }
88 
SetLivePhotoCompatId(string fileId)89 static void SetLivePhotoCompatId(string fileId)
90 {
91     bool ret = system::SetParameter(COMPAT_LIVE_PHOTO_FILE_ID, fileId);
92     CHECK_AND_PRINT_LOG(ret, "Failed to set parameter for compating local live photo: %{public}s",
93         fileId.c_str());
94 }
95 
StartProcessLivePhoto()96 void MovingPhotoProcessor::StartProcessLivePhoto()
97 {
98     CHECK_AND_RETURN_LOG(!IsLivePhotoCompatDone(), "Live photo compat done or no need to compat");
99     auto resultSet = QueryCandidateLivePhoto();
100     CHECK_AND_RETURN_LOG(resultSet != nullptr, "Failed to query candidate live photo");
101 
102     LivePhotoDataList dataList;
103     ParseLivePhotoData(resultSet, dataList);
104     if (dataList.livePhotos.empty()) {
105         SetLivePhotoCompatId(LIVE_PHOTO_COMPAT_DONE);
106         MEDIA_INFO_LOG("No live photo need to compat");
107         return;
108     }
109 
110     isProcessing_ = true;
111     CompatLivePhoto(dataList);
112 }
113 
StartProcess()114 void MovingPhotoProcessor::StartProcess()
115 {
116     MEDIA_DEBUG_LOG("Start processing moving photo task");
117 
118     // 1. compat old moving photo
119     StartProcessMovingPhoto();
120 
121     // 2. compat local live photo
122     StartProcessLivePhoto();
123 
124     // 3. refresh cloud live photo if needed
125     if (!IsCloudLivePhotoRefreshed()) {
126         MEDIA_INFO_LOG("Strat reset cloud cursor for cloud live photo");
127         FileManagement::CloudSync::CloudSyncManager::GetInstance().ResetCursor();
128         MEDIA_INFO_LOG("End reset cloud cursor for cloud live photo");
129         bool ret = system::SetParameter(REFRESH_CLOUD_LIVE_PHOTO_FLAG, CLOUD_LIVE_PHOTO_REFRESHED);
130         MEDIA_INFO_LOG("Set parameter of isRefreshed to 1, ret: %{public}d", ret);
131     }
132 
133     isProcessing_ = false;
134     MEDIA_DEBUG_LOG("Finsh processing moving photo task");
135 }
136 
StopProcess()137 void MovingPhotoProcessor::StopProcess()
138 {
139     isProcessing_ = false;
140 }
141 
QueryMovingPhoto()142 shared_ptr<NativeRdb::ResultSet> MovingPhotoProcessor::QueryMovingPhoto()
143 {
144     const vector<string> columns = {
145         PhotoColumn::MEDIA_ID,
146         PhotoColumn::PHOTO_SUBTYPE,
147         PhotoColumn::MOVING_PHOTO_EFFECT_MODE,
148         PhotoColumn::MEDIA_SIZE,
149         PhotoColumn::MEDIA_FILE_PATH,
150     };
151     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
152     predicates.EqualTo(PhotoColumn::PHOTO_DIRTY, DIRTY_NOT_UPLOADING)
153         ->And()
154         ->BeginWrap()
155         ->EqualTo(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::MOVING_PHOTO))
156         ->Or()
157         ->EqualTo(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY))
158         ->EndWrap()
159         ->And()
160         ->EqualTo(PhotoColumn::PHOTO_IS_TEMP, 0)
161         ->And()
162         ->EqualTo(PhotoColumn::MEDIA_TIME_PENDING, 0)
163         ->And()
164         ->BeginWrap()
165         ->EqualTo(PhotoColumn::PHOTO_QUALITY, static_cast<int32_t>(MultiStagesPhotoQuality::FULL))
166         ->Or()
167         ->IsNull(PhotoColumn::PHOTO_QUALITY)
168         ->EndWrap()
169         ->Limit(MOVING_PHOTO_PROCESS_NUM);
170     return MediaLibraryRdbStore::QueryWithFilter(predicates, columns);
171 }
172 
ParseMovingPhotoData(shared_ptr<NativeRdb::ResultSet> & resultSet,MovingPhotoDataList & dataList)173 void MovingPhotoProcessor::ParseMovingPhotoData(shared_ptr<NativeRdb::ResultSet>& resultSet,
174     MovingPhotoDataList& dataList)
175 {
176     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
177         int32_t fileId = get<int32_t>(
178             ResultSetUtils::GetValFromColumn(PhotoColumn::MEDIA_ID, resultSet, TYPE_INT32));
179         int32_t subtype = get<int32_t>(
180             ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_SUBTYPE, resultSet, TYPE_INT32));
181         int32_t effectMode = get<int32_t>(
182             ResultSetUtils::GetValFromColumn(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, resultSet, TYPE_INT32));
183         int64_t size = get<int64_t>(
184             ResultSetUtils::GetValFromColumn(PhotoColumn::MEDIA_SIZE, resultSet, TYPE_INT64));
185         std::string path = get<std::string>(
186             ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_FILE_PATH, resultSet, TYPE_STRING));
187 
188         MovingPhotoData movingPhotoData;
189         movingPhotoData.fileId = fileId;
190         movingPhotoData.subtype = subtype;
191         movingPhotoData.effectMode = effectMode;
192         movingPhotoData.size = size;
193         movingPhotoData.path = path;
194         dataList.movingPhotos.push_back(movingPhotoData);
195     }
196 }
197 
UpdateMovingPhotoData(const MovingPhotoData & movingPhotoData)198 void MovingPhotoProcessor::UpdateMovingPhotoData(const MovingPhotoData& movingPhotoData)
199 {
200     ValuesBucket values;
201     string whereClause = PhotoColumn::MEDIA_ID + " = ? AND " + PhotoColumn::PHOTO_DIRTY + " = ?";
202     vector<string> whereArgs = { to_string(movingPhotoData.fileId), to_string(DIRTY_NOT_UPLOADING) };
203     values.PutInt(PhotoColumn::PHOTO_SUBTYPE, movingPhotoData.subtype);
204     values.PutLong(PhotoColumn::MEDIA_SIZE, movingPhotoData.size);
205     values.PutInt(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyTypes::TYPE_NEW));
206     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
207 
208     CHECK_AND_RETURN_LOG(rdbStore != nullptr, "rdbStore is null");
209     CHECK_AND_RETURN_LOG(isProcessing_, "stop updateing moving photo data");
210     int32_t updateCount = 0;
211     int32_t result = rdbStore->Update(updateCount, PhotoColumn::PHOTOS_TABLE, values, whereClause, whereArgs);
212     bool cond = (result != NativeRdb::E_OK || updateCount <= 0);
213     CHECK_AND_RETURN_LOG(!cond, "Update failed. result: %{public}d, updateCount: %{public}d", result, updateCount);
214 }
215 
GetDefaultExtraData()216 static string GetDefaultExtraData()
217 {
218     static string defaultExtraData = "v3_f0               0:0                 LIVE_10000000       ";
219     return defaultExtraData;
220 }
221 
GetUpdatedMovingPhotoData(const MovingPhotoData & currentData,MovingPhotoData & newData)222 int32_t MovingPhotoProcessor::GetUpdatedMovingPhotoData(const MovingPhotoData& currentData,
223     MovingPhotoData& newData)
224 {
225     newData = currentData;
226     string imagePath = currentData.path;
227     string videoPath = MovingPhotoFileUtils::GetMovingPhotoVideoPath(imagePath);
228     string extraDataPath = MovingPhotoFileUtils::GetMovingPhotoExtraDataPath(imagePath);
229     size_t imageSize = 0;
230     size_t videoSize = 0;
231     size_t extraSize = 0;
232     if (!MediaFileUtils::GetFileSize(imagePath, imageSize) || imageSize == 0) {
233         MEDIA_WARN_LOG("Failed to get image of moving photo, id: %{public}d", currentData.fileId);
234         newData.size = -1; // set abnormal size to -1 if original size is 0
235         newData.subtype = static_cast<int32_t>(PhotoSubType::DEFAULT);
236         return E_OK;
237     }
238 
239     if (!MediaFileUtils::GetFileSize(videoPath, videoSize) || videoSize == 0) {
240         MEDIA_WARN_LOG("Failed to get video of moving photo, id: %{public}d", currentData.fileId);
241         newData.size = static_cast<int64_t>(imageSize);
242         newData.subtype = static_cast<int32_t>(PhotoSubType::DEFAULT);
243         return E_OK;
244     }
245 
246     if (MediaFileUtils::GetFileSize(extraDataPath, extraSize) && extraSize > 0) {
247         newData.size = static_cast<int64_t>(imageSize + videoSize + extraSize);
248         return E_OK;
249     }
250 
251     string extraDataDir = MovingPhotoFileUtils::GetMovingPhotoExtraDataDir(imagePath);
252     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::CreateDirectory(extraDataDir), E_HAS_FS_ERROR,
253         "Cannot create dir %{private}s, errno:%{public}d", extraDataDir.c_str(), errno);
254     bool cond = (!MediaFileUtils::IsFileExists(extraDataPath) && MediaFileUtils::CreateAsset(extraDataPath) != E_OK);
255     CHECK_AND_RETURN_RET_LOG(!cond, E_HAS_FS_ERROR,
256         "Failed to create extraData:%{private}s, errno:%{public}d", extraDataPath.c_str(), errno);
257     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::WriteStrToFile(extraDataPath, GetDefaultExtraData()),
258         E_HAS_FS_ERROR, "Failed to write extraData, errno:%{public}d", errno);
259     newData.size = static_cast<int64_t>(imageSize + videoSize + DEFAULT_EXTRA_DATA_SIZE);
260     return E_OK;
261 }
262 
CompatMovingPhoto(const MovingPhotoDataList & dataList)263 void MovingPhotoProcessor::CompatMovingPhoto(const MovingPhotoDataList& dataList)
264 {
265     MEDIA_INFO_LOG("Start processing %{public}zu moving photos", dataList.movingPhotos.size());
266     int32_t count = 0;
267     for (const auto& movingPhoto : dataList.movingPhotos) {
268         CHECK_AND_RETURN_LOG(isProcessing_, "stop compating moving photo");
269         MovingPhotoData newData;
270         if (GetUpdatedMovingPhotoData(movingPhoto, newData) != E_OK) {
271             MEDIA_INFO_LOG("Failed to get updated data of moving photo, id: %{public}d", movingPhoto.fileId);
272             continue;
273         }
274         UpdateMovingPhotoData(newData);
275         count += 1;
276     }
277     MEDIA_INFO_LOG("Finish processing %{public}d moving photos", count);
278 }
279 
QueryCandidateLivePhoto()280 shared_ptr<NativeRdb::ResultSet> MovingPhotoProcessor::QueryCandidateLivePhoto()
281 {
282     const vector<string> columns = {
283         PhotoColumn::MEDIA_ID,
284         PhotoColumn::MEDIA_TYPE,
285         PhotoColumn::PHOTO_SUBTYPE,
286         PhotoColumn::PHOTO_POSITION,
287         PhotoColumn::PHOTO_EDIT_TIME,
288         PhotoColumn::MEDIA_FILE_PATH,
289     };
290     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
291     string currentFileIdStr = GetLivePhotoCompatId();
292     int32_t currentFileId = std::atoi(currentFileIdStr.c_str());
293     MEDIA_INFO_LOG("Start query candidate live photo from file_id: %{public}d", currentFileId);
294     predicates.GreaterThanOrEqualTo(PhotoColumn::MEDIA_ID, currentFileId)
295         ->And()
296         ->EqualTo(PhotoColumn::MEDIA_TYPE, static_cast<int32_t>(MEDIA_TYPE_IMAGE))
297         ->And()
298         ->EqualTo(PhotoColumn::PHOTO_IS_TEMP, 0)
299         ->And()
300         ->EqualTo(PhotoColumn::MEDIA_TIME_PENDING, 0)
301         ->And()
302         ->BeginWrap()
303         ->EqualTo(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::DEFAULT))
304         ->Or()
305         ->EqualTo(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::CAMERA))
306         ->EndWrap()
307         ->And()
308         ->BeginWrap()
309         ->EqualTo(PhotoColumn::PHOTO_POSITION, static_cast<int32_t>(PhotoPositionType::LOCAL))
310         ->Or()
311         ->EqualTo(PhotoColumn::PHOTO_POSITION, static_cast<int32_t>(PhotoPositionType::LOCAL_AND_CLOUD))
312         ->EndWrap()
313         ->OrderByAsc(PhotoColumn::MEDIA_ID)
314         ->Limit(LIVE_PHOTO_QUERY_NUM);
315     return MediaLibraryRdbStore::QueryWithFilter(predicates, columns);
316 }
317 
ParseLivePhotoData(shared_ptr<NativeRdb::ResultSet> & resultSet,LivePhotoDataList & dataList)318 void MovingPhotoProcessor::ParseLivePhotoData(shared_ptr<NativeRdb::ResultSet>& resultSet,
319     LivePhotoDataList& dataList)
320 {
321     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
322         int32_t fileId = get<int32_t>(
323             ResultSetUtils::GetValFromColumn(PhotoColumn::MEDIA_ID, resultSet, TYPE_INT32));
324         int32_t mediaType = get<int32_t>(
325             ResultSetUtils::GetValFromColumn(PhotoColumn::MEDIA_TYPE, resultSet, TYPE_INT32));
326         int32_t subtype = get<int32_t>(
327             ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_SUBTYPE, resultSet, TYPE_INT32));
328         int32_t position = get<int32_t>(
329             ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_POSITION, resultSet, TYPE_INT32));
330         int64_t editTime = get<int64_t>(
331             ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_EDIT_TIME, resultSet, TYPE_INT64));
332         std::string path = get<std::string>(
333             ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_FILE_PATH, resultSet, TYPE_STRING));
334 
335         LivePhotoData livePhotoData;
336         livePhotoData.isLivePhoto = false;
337         livePhotoData.fileId = fileId;
338         livePhotoData.mediaType = mediaType;
339         livePhotoData.subtype = subtype;
340         livePhotoData.position = position;
341         livePhotoData.editTime = editTime;
342         livePhotoData.path = path;
343         dataList.livePhotos.push_back(livePhotoData);
344     }
345 }
346 
CompatLivePhoto(const LivePhotoDataList & dataList)347 void MovingPhotoProcessor::CompatLivePhoto(const LivePhotoDataList& dataList)
348 {
349     MEDIA_INFO_LOG("Start processing %{public}zu candidate live photos", dataList.livePhotos.size());
350     int32_t count = 0;
351     int32_t livePhotoCount = 0;
352     int32_t processedFileId = 0;
353     for (const auto& livePhoto : dataList.livePhotos) {
354         if (!isProcessing_) {
355             SetLivePhotoCompatId(std::to_string(livePhoto.fileId));
356             MEDIA_INFO_LOG("Stop compating live photo, file_id: %{public}d", livePhoto.fileId);
357             return;
358         }
359         processedFileId = livePhoto.fileId;
360         LivePhotoData newData;
361         if (GetUpdatedLivePhotoData(livePhoto, newData) != E_OK) {
362             MEDIA_INFO_LOG("Failed to get updated data of candidate live photo, id: %{public}d", livePhoto.fileId);
363             continue;
364         }
365         if (newData.isLivePhoto) {
366             UpdateLivePhotoData(newData);
367             livePhotoCount += 1;
368         }
369         count += 1;
370 
371         if (livePhotoCount >= LIVE_PHOTO_PROCESS_NUM) {
372             SetLivePhotoCompatId(std::to_string(livePhoto.fileId + 1));
373             MEDIA_INFO_LOG("Stop compating live photo, %{public}d processed", livePhotoCount);
374             return;
375         }
376     }
377     SetLivePhotoCompatId(std::to_string(processedFileId + 1));
378     MEDIA_INFO_LOG("Finish processing %{public}d candidates, contains %{public}d live photos, file_id: %{public}d",
379         count, livePhotoCount, processedFileId);
380 }
381 
addCompatPathSuffix(const string & oldPath,const string & suffix,string & newPath)382 static void addCompatPathSuffix(const string &oldPath, const string &suffix, string &newPath)
383 {
384     bool cond = (oldPath.empty() || suffix.empty());
385     CHECK_AND_RETURN_LOG(!cond, "oldPath or suffix is empty");
386     newPath = oldPath + ".compat" + suffix;
387     while (MediaFileUtils::IsFileExists(newPath)) {
388         newPath += ".dup" + suffix;
389     }
390 }
391 
MoveMovingPhoto(const string & path,const string & compatImagePath,const string & compatVideoPath,const string & compatExtraDataPath)392 static int32_t MoveMovingPhoto(const string &path,
393     const string &compatImagePath, const string &compatVideoPath, const string &compatExtraDataPath)
394 {
395     string movingPhotoVideoPath = MovingPhotoFileUtils::GetMovingPhotoVideoPath(path);
396     string movingPhotoExtraDataPath = MovingPhotoFileUtils::GetMovingPhotoExtraDataPath(path);
397     CHECK_AND_RETURN_RET_LOG(!movingPhotoVideoPath.empty(), E_INVALID_VALUES, "Failed to get video path");
398     CHECK_AND_RETURN_RET_LOG(!movingPhotoExtraDataPath.empty(), E_INVALID_VALUES, "Failed to get extraData path");
399     CHECK_AND_RETURN_RET_LOG(
400         !MediaFileUtils::IsFileExists(movingPhotoVideoPath), E_INVALID_VALUES, "Video path exists!");
401     CHECK_AND_RETURN_RET_LOG(
402         !MediaFileUtils::IsFileExists(movingPhotoExtraDataPath), E_INVALID_VALUES, "extraData path exists");
403     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::CreateDirectory(MovingPhotoFileUtils::GetMovingPhotoExtraDataDir(path)),
404         E_HAS_FS_ERROR, "Failed to create extraData dir of %{private}s", path.c_str());
405 
406     int32_t ret = rename(compatExtraDataPath.c_str(), movingPhotoExtraDataPath.c_str());
407     CHECK_AND_RETURN_RET_LOG(ret >= 0, ret, "Failed to rename extraData, src:"
408         " %{public}s, dest: %{public}s, errno: %{public}d",
409         compatExtraDataPath.c_str(), movingPhotoExtraDataPath.c_str(), errno);
410 
411     ret = rename(compatVideoPath.c_str(), movingPhotoVideoPath.c_str());
412     CHECK_AND_RETURN_RET_LOG(ret >= 0, ret, "Failed to rename video, src: %{public}s,"
413         " dest: %{public}s, errno: %{public}d",
414         compatVideoPath.c_str(), movingPhotoVideoPath.c_str(), errno);
415 
416     ret = rename(compatImagePath.c_str(), path.c_str());
417     CHECK_AND_RETURN_RET_LOG(ret >= 0, ret, "Failed to rename image, src: %{public}s,"
418         " dest: %{public}s, errno: %{public}d",
419         compatImagePath.c_str(), path.c_str(), errno);
420     return ret;
421 }
422 
ProcessLocalLivePhoto(LivePhotoData & data)423 int32_t MovingPhotoProcessor::ProcessLocalLivePhoto(LivePhotoData& data)
424 {
425     data.isLivePhoto = false;
426     bool isLivePhoto = MovingPhotoFileUtils::IsLivePhoto(data.path);
427     CHECK_AND_RETURN_RET(isLivePhoto, E_OK);
428 
429     string livePhotoPath = data.path;
430     string compatImagePath;
431     string compatVideoPath;
432     string compatExtraDataPath;
433     addCompatPathSuffix(livePhotoPath, ".jpg", compatImagePath);
434     addCompatPathSuffix(livePhotoPath, ".mp4", compatVideoPath);
435     addCompatPathSuffix(livePhotoPath, ".extra", compatExtraDataPath);
436     int32_t ret = MovingPhotoFileUtils::ConvertToMovingPhoto(
437         livePhotoPath, compatImagePath, compatVideoPath, compatExtraDataPath);
438     if (ret != E_OK) {
439         MEDIA_ERR_LOG("Failed to convert live photo, ret:%{public}d, file_id:%{public}d", ret, data.fileId);
440         (void)MediaFileUtils::DeleteFile(compatImagePath);
441         (void)MediaFileUtils::DeleteFile(compatVideoPath);
442         (void)MediaFileUtils::DeleteFile(compatExtraDataPath);
443         return ret;
444     }
445 
446     uint64_t coverPosition = 0;
447     uint32_t version = 0;
448     uint32_t frameIndex = 0;
449     bool hasCinemagraphInfo = false;
450     string absExtraDataPath;
451 
452     CHECK_AND_RETURN_RET_LOG(PathToRealPath(compatExtraDataPath, absExtraDataPath), E_HAS_FS_ERROR,
453         "extraData is not real path: %{private}s, errno: %{public}d", compatExtraDataPath.c_str(), errno);
454     UniqueFd extraDataFd(open(absExtraDataPath.c_str(), O_RDONLY));
455     (void)MovingPhotoFileUtils::GetVersionAndFrameNum(extraDataFd.Get(), version, frameIndex, hasCinemagraphInfo);
456     (void)MovingPhotoFileUtils::GetCoverPosition(compatVideoPath, frameIndex, coverPosition);
457     data.coverPosition = static_cast<int64_t>(coverPosition);
458 
459     ret = MoveMovingPhoto(livePhotoPath, compatImagePath, compatVideoPath, compatExtraDataPath);
460     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to move moving photo, file_id:%{public}d", data.fileId);
461     data.subtype = static_cast<int32_t>(PhotoSubType::MOVING_PHOTO);
462     data.isLivePhoto = true;
463     return E_OK;
464 }
465 
ProcessLocalCloudLivePhoto(LivePhotoData & data)466 int32_t MovingPhotoProcessor::ProcessLocalCloudLivePhoto(LivePhotoData& data)
467 {
468     CHECK_AND_RETURN_RET(data.editTime != 0, ProcessLocalLivePhoto(data));
469     data.isLivePhoto = false;
470     string sourcePath = PhotoFileUtils::GetEditDataSourcePath(data.path);
471     bool isLivePhotoEdited = MovingPhotoFileUtils::IsLivePhoto(sourcePath);
472     CHECK_AND_RETURN_RET(isLivePhotoEdited, E_OK);
473     data.metaDateModified = MediaFileUtils::UTCTimeMilliSeconds();
474     data.isLivePhoto = true;
475     return E_OK;
476 }
477 
GetUpdatedLivePhotoData(const LivePhotoData & currentData,LivePhotoData & newData)478 int32_t MovingPhotoProcessor::GetUpdatedLivePhotoData(const LivePhotoData& currentData, LivePhotoData& newData)
479 {
480     newData = currentData;
481     string path = currentData.path;
482     string extension = ScannerUtils::GetFileExtension(path);
483     string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extension);
484     if (mimeType.compare("image/jpeg") != 0) {
485         newData.isLivePhoto = false;
486         return E_OK;
487     }
488 
489     if (currentData.position == static_cast<int32_t>(PhotoPositionType::LOCAL)) {
490         return ProcessLocalLivePhoto(newData);
491     } else if (currentData.position == static_cast<int32_t>(PhotoPositionType::LOCAL_AND_CLOUD)) {
492         return ProcessLocalCloudLivePhoto(newData);
493     } else {
494         MEDIA_ERR_LOG("Invalid position to process: %{public}d", currentData.position);
495         return E_INVALID_VALUES;
496     }
497 }
498 
UpdateLivePhotoData(const LivePhotoData & livePhotoData)499 void MovingPhotoProcessor::UpdateLivePhotoData(const LivePhotoData& livePhotoData)
500 {
501     CHECK_AND_RETURN_LOG(livePhotoData.isLivePhoto, "Not a live photo Update Failed");
502     bool cond = (livePhotoData.position != static_cast<int32_t>(PhotoPositionType::LOCAL) &&
503         livePhotoData.position != static_cast<int32_t>(PhotoPositionType::LOCAL_AND_CLOUD));
504     CHECK_AND_RETURN_LOG(!cond, "Invalid position: %{public}d", livePhotoData.position);
505 
506     ValuesBucket values;
507     string whereClause = PhotoColumn::MEDIA_ID + " = ?";
508     vector<string> whereArgs = { to_string(livePhotoData.fileId) };
509     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
510     CHECK_AND_RETURN_LOG(rdbStore != nullptr, "rdbStore is null");
511 
512     if (livePhotoData.editTime == 0) {
513         values.PutInt(PhotoColumn::PHOTO_SUBTYPE, livePhotoData.subtype);
514         values.PutLong(PhotoColumn::PHOTO_COVER_POSITION, livePhotoData.coverPosition);
515     } else {
516         values.PutLong(PhotoColumn::PHOTO_META_DATE_MODIFIED, livePhotoData.metaDateModified);
517     }
518 
519     int32_t updateCount = 0;
520     int32_t result = rdbStore->Update(updateCount, PhotoColumn::PHOTOS_TABLE, values, whereClause, whereArgs);
521     cond = (result != NativeRdb::E_OK || updateCount <= 0);
522     CHECK_AND_RETURN_LOG(!cond, "Update failed. result: %{public}d, updateCount: %{public}d", result, updateCount);
523 }
524 } // namespace Media
525 } // namespace OHOS
526