• 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 "MovingPhotoFileUtils"
17 
18 #include "moving_photo_file_utils.h"
19 
20 #include <fcntl.h>
21 #include <regex>
22 #include <sstream>
23 #include <sys/sendfile.h>
24 #include <sys/stat.h>
25 #include <map>
26 #include <unistd.h>
27 
28 #include "avmetadatahelper.h"
29 #include "directory_ex.h"
30 #include "media_file_utils.h"
31 #include "media_log.h"
32 #include "medialibrary_errno.h"
33 #include "medialibrary_tracer.h"
34 #include "medialibrary_type_const.h"
35 #include "string_ex.h"
36 #include "unique_fd.h"
37 
38 using namespace std;
39 
40 namespace OHOS::Media {
41 const std::string MEDIA_EXTRA_DATA_DIR = MEDIA_EDIT_DATA_DIR;
42 
43 const std::string LIVE_PHOTO_CINEMAGRAPH_INFO = "CinemagraphInfo";
44 const std::string LIVE_PHOTO_VIDEO_INFO_METADATA = "VideoInfoMetadata";
45 const std::string LIVE_PHOTO_SIGHT_TREMBLE_META_DATA = "SightTrembleMetadata";
46 const std::string LIVE_PHOTO_VERSION_AND_FRAME_NUM = "VersionAndFrameNum";
47 constexpr int32_t HEX_BASE = 16;
48 constexpr int64_t AUTO_PLAY_DURATION_MS = 600;
49 
GetVersionPositionTag(uint32_t frame,bool hasExtraData,const string & data="",bool isCameraShotMovingPhoto=false)50 static string GetVersionPositionTag(uint32_t frame, bool hasExtraData,
51     const string& data = "", bool isCameraShotMovingPhoto = false)
52 {
53     string buffer;
54     bool hasCinemagraph{false};
55     if (data.size() != 0) {
56         uint32_t version{0};
57         uint32_t frameIndex{0};
58         if (MovingPhotoFileUtils::GetVersionAndFrameNum(data, version, frameIndex, hasCinemagraph) != E_OK) {
59             return buffer;
60         }
61         buffer = "v" + to_string(version) + "_f";
62     } else if (hasExtraData) {
63         return buffer;
64     } else {
65         buffer += isCameraShotMovingPhoto ? "v6_f" : "v3_f";
66     }
67     buffer += to_string(frame);
68     if (hasCinemagraph) {
69         buffer += "_c";
70     }
71     uint32_t left = LIVE_TAG_LEN - buffer.length();
72     for (uint32_t i = 0; i < left; ++i) {
73         buffer += ' ';
74     }
75     return buffer;
76 }
77 
GetDurationTag(int64_t coverPosition,const string & data="")78 static string GetDurationTag(int64_t coverPosition, const string& data = "")
79 {
80     int64_t frame = coverPosition / 1000;
81     if (coverPosition < 0) {
82         frame = 0;
83         MEDIA_WARN_LOG("coverPosition data err %{public}" PRId64, coverPosition);
84     }
85     string buffer;
86     if (data.size() != 0 && !MediaFileUtils::StartsWith(data, "0:0")) {
87         buffer += data;
88     } else {
89         if (frame < AUTO_PLAY_DURATION_MS) {
90             buffer += "0:" + to_string(frame);
91         } else {
92             buffer += to_string(frame - AUTO_PLAY_DURATION_MS) + ":" + to_string(frame);
93         }
94     }
95     uint16_t left = PLAY_INFO_LEN - buffer.length();
96     for (uint16_t i = 0; i < left; ++i) {
97         buffer += ' ';
98     }
99     return buffer;
100 }
101 
GetVideoInfoTag(off_t fileSize)102 static string GetVideoInfoTag(off_t fileSize)
103 {
104     string buffer = "LIVE_" + to_string(fileSize);
105     uint16_t left = VERSION_TAG_LEN - buffer.length();
106     for (uint16_t i = 0; i < left; ++i) {
107         buffer += ' ';
108     }
109     return buffer;
110 }
111 
GetFileSize(const int32_t fd)112 static off_t GetFileSize(const int32_t fd)
113 {
114     if (fd < 0) {
115         MEDIA_ERR_LOG("file is error");
116         return E_ERR;
117     }
118     struct stat st;
119     if (fstat(fd, &st) != E_OK) {
120         MEDIA_ERR_LOG("failed to get file size, errno: %{public}d", errno);
121         return E_ERR;
122     }
123     return st.st_size;
124 }
125 
GetFileSize(const string & path)126 static off_t GetFileSize(const string& path)
127 {
128     struct stat st;
129     if (stat(path.c_str(), &st) != E_OK) {
130         MEDIA_ERR_LOG("failed to get file size, errno: %{public}d", errno);
131         return E_ERR;
132     }
133     return st.st_size;
134 }
135 
WriteContentTofile(const UniqueFd & destFd,const UniqueFd & srcFd)136 static int32_t WriteContentTofile(const UniqueFd& destFd, const UniqueFd& srcFd)
137 {
138     const uint32_t BUFFER_LENGTH = 16 * 1024; // 16KB
139     if (lseek(srcFd.Get(), 0, SEEK_SET) == E_ERR) {
140         MEDIA_ERR_LOG("failed to lseek file, errno: %{public}d", errno);
141         return E_ERR;
142     }
143     char buffer[BUFFER_LENGTH];
144     ssize_t bytesRead = 0;
145     ssize_t bytesWritten = 0;
146     while ((bytesRead = read(srcFd.Get(), buffer, BUFFER_LENGTH)) > 0) {
147         bytesWritten = write(destFd.Get(), buffer, bytesRead);
148         if (bytesWritten != bytesRead) {
149             MEDIA_ERR_LOG("failed to write file, errno: %{public}d", errno);
150             return E_ERR;
151         }
152     }
153     if (bytesRead < 0) {
154         MEDIA_ERR_LOG("failed to read from srcFd:%{public}d, errno:%{public}d", srcFd.Get(), errno);
155         return E_ERR;
156     }
157     return E_OK;
158 }
159 
AddStringToFile(const UniqueFd & destFd,const string & temp)160 static int32_t AddStringToFile(const UniqueFd& destFd, const string& temp)
161 {
162     ssize_t ret = write(destFd.Get(), temp.c_str(), temp.size());
163     if (ret < 0 || static_cast<size_t>(ret) != temp.size()) {
164         MEDIA_ERR_LOG("failed to write file, errno: %{public}d, ret: %{public}" PRId64, errno,
165             static_cast<int64_t>(ret));
166         return E_ERR;
167     }
168     return E_OK;
169 }
170 
GetExtraData(const UniqueFd & fd,off_t fileSize,off_t offset,off_t needSize)171 static string GetExtraData(const UniqueFd& fd, off_t fileSize, off_t offset, off_t needSize)
172 {
173     bool cond = (fileSize < 0 || offset < 0 || needSize < 0);
174     CHECK_AND_RETURN_RET_LOG(!cond, "", "failed to check fileSize: %{public}" PRId64
175         ", offset: %{public}" PRId64 ", needSize: %{public}" PRId64, fileSize, offset, needSize);
176 
177     off_t readPosition = fileSize >= offset ? fileSize - offset : 0;
178     if (lseek(fd.Get(), readPosition, SEEK_SET) == E_ERR) {
179         MEDIA_ERR_LOG("failed to lseek extra file errno: %{public}d", errno);
180         return "";
181     }
182     char* buffer = new (std::nothrow) char[needSize + 1];
183     if (buffer == nullptr) {
184         MEDIA_ERR_LOG("failed to allocate buffer");
185         return "";
186     }
187     memset_s(buffer, needSize + 1, 0, needSize + 1);
188     ssize_t bytesRead;
189     if ((bytesRead = read(fd.Get(), buffer, needSize)) < 0) {
190         MEDIA_ERR_LOG("failed to read extra file errno: %{public}d", errno);
191         delete[] buffer;
192         buffer = nullptr;
193         return "";
194     }
195     string content(buffer, bytesRead);
196     delete[] buffer;
197     buffer = nullptr;
198     return content;
199 }
200 
ReadExtraFile(const std::string & extraPath,map<string,string> & extraData)201 static int32_t ReadExtraFile(const std::string& extraPath, map<string, string>& extraData)
202 {
203     string absExtraPath;
204     if (!PathToRealPath(extraPath, absExtraPath)) {
205         MEDIA_ERR_LOG("file is not real path: %{private}s, errno: %{public}d", extraPath.c_str(), errno);
206         return E_HAS_FS_ERROR;
207     }
208     UniqueFd fd(open(absExtraPath.c_str(), O_RDONLY));
209     if (fd.Get() == E_ERR) {
210         MEDIA_ERR_LOG("failed to open extra file, errno: %{public}d", errno);
211         return E_ERR;
212     }
213     uint32_t version{0};
214     uint32_t frameIndex{0};
215     bool hasCinemagraphInfo{false};
216     bool hasVersion = MovingPhotoFileUtils::GetVersionAndFrameNum(
217         fd.Get(), version, frameIndex, hasCinemagraphInfo) == E_OK;
218     off_t fileSize = GetFileSize(fd.Get());
219     extraData[LIVE_PHOTO_VIDEO_INFO_METADATA] = GetExtraData(fd, fileSize, LIVE_TAG_LEN, LIVE_TAG_LEN);
220     extraData[LIVE_PHOTO_SIGHT_TREMBLE_META_DATA] = GetExtraData(fd, fileSize, LIVE_TAG_LEN + PLAY_INFO_LEN,
221         PLAY_INFO_LEN);
222     if (hasVersion) {
223         extraData[LIVE_PHOTO_VERSION_AND_FRAME_NUM] = GetExtraData(fd, fileSize, MIN_STANDARD_SIZE, VERSION_TAG_LEN);
224         if (hasCinemagraphInfo) {
225             extraData[LIVE_PHOTO_CINEMAGRAPH_INFO] = GetExtraData(fd, fileSize, fileSize, fileSize - MIN_STANDARD_SIZE);
226         }
227     } else if (fileSize > LIVE_TAG_LEN + PLAY_INFO_LEN) {
228         extraData[LIVE_PHOTO_CINEMAGRAPH_INFO] = GetExtraData(fd, fileSize, fileSize,
229             fileSize - LIVE_TAG_LEN - PLAY_INFO_LEN);
230     }
231     return E_OK;
232 }
233 
WriteExtraData(const string & extraPath,const UniqueFd & livePhotoFd,const UniqueFd & videoFd,int64_t coverPosition)234 static int32_t WriteExtraData(const string& extraPath, const UniqueFd& livePhotoFd, const UniqueFd& videoFd,
235     int64_t coverPosition)
236 {
237     map<string, string> extraData;
238     bool hasExtraData{false};
239     if (MediaFileUtils::IsFileValid(extraPath)) {
240         hasExtraData = true;
241         if (ReadExtraFile(extraPath, extraData) == E_ERR) {
242             MEDIA_ERR_LOG("read extra file err");
243             return E_ERR;
244         }
245         if (AddStringToFile(livePhotoFd, extraData[LIVE_PHOTO_CINEMAGRAPH_INFO]) == E_ERR) {
246             MEDIA_ERR_LOG("write cinemagraph info err");
247             return E_ERR;
248         }
249     }
250     string versonAndFrameNum = GetVersionPositionTag(MovingPhotoFileUtils::GetFrameIndex(coverPosition, videoFd.Get()),
251         hasExtraData, extraData[LIVE_PHOTO_VERSION_AND_FRAME_NUM]);
252     if (AddStringToFile(livePhotoFd, versonAndFrameNum) == E_ERR) {
253         MEDIA_ERR_LOG("write version position tag err");
254         return E_ERR;
255     }
256     if (AddStringToFile(livePhotoFd,
257         GetDurationTag(coverPosition, extraData[LIVE_PHOTO_SIGHT_TREMBLE_META_DATA])) == E_ERR) {
258         MEDIA_ERR_LOG("write duration tag err");
259         return E_ERR;
260     }
261     off_t fileSize = GetFileSize(videoFd.Get());
262     if (fileSize <= 0) {
263         MEDIA_ERR_LOG("failed to check fileSize: %{public}" PRId64, fileSize);
264         return E_ERR;
265     }
266     if (AddStringToFile(livePhotoFd, GetVideoInfoTag(static_cast<size_t>(fileSize) +
267         versonAndFrameNum.size() + extraData[LIVE_PHOTO_CINEMAGRAPH_INFO].size())) == E_ERR) {
268         MEDIA_ERR_LOG("write video info tag err");
269         return E_ERR;
270     }
271     return E_OK;
272 }
273 
GetExtraDataLen(const string & imagePath,const string & videoPath,uint32_t frameIndex,int64_t coverPosition,off_t & fileSize,bool isCameraShotMovingPhoto)274 int32_t MovingPhotoFileUtils::GetExtraDataLen(const string& imagePath, const string& videoPath,
275     uint32_t frameIndex, int64_t coverPosition, off_t &fileSize, bool isCameraShotMovingPhoto)
276 {
277     string absImagePath;
278     if (!PathToRealPath(imagePath, absImagePath)) {
279         MEDIA_ERR_LOG("file is not real path: %{private}s, errno: %{public}d", imagePath.c_str(), errno);
280         return E_HAS_FS_ERROR;
281     }
282     string extraDir = MovingPhotoFileUtils::GetMovingPhotoExtraDataDir(absImagePath);
283     string extraPath = MovingPhotoFileUtils::GetMovingPhotoExtraDataPath(absImagePath);
284     if (MediaFileUtils::IsFileValid(extraPath)) {
285         fileSize = GetFileSize(extraPath);
286         return E_OK;
287     }
288     CHECK_AND_RETURN_RET_LOG(
289         MediaFileUtils::CreateDirectory(extraDir), E_ERR, "Cannot create dir %{private}s, errno:%{public}d",
290         extraDir.c_str(), errno);
291     if (!MediaFileUtils::IsFileExists(extraPath) && MediaFileUtils::CreateAsset(extraPath) != E_OK) {
292         MEDIA_ERR_LOG("Failed to create file, path:%{private}s, errno:%{public}d", extraPath.c_str(), errno);
293         return E_HAS_FS_ERROR;
294     }
295     UniqueFd extraDataFd(open(extraPath.c_str(), O_WRONLY | O_TRUNC));
296     if (extraDataFd.Get() == E_ERR) {
297         MEDIA_ERR_LOG("failed to open extra data, errno:%{public}d", errno);
298         return E_ERR;
299     }
300     if (AddStringToFile(extraDataFd, GetVersionPositionTag(frameIndex, false, "", isCameraShotMovingPhoto)) == E_ERR) {
301         MEDIA_ERR_LOG("write version position tag err");
302         return E_ERR;
303     }
304     if (AddStringToFile(extraDataFd, GetDurationTag(coverPosition)) == E_ERR) {
305         MEDIA_ERR_LOG("write duration tag err");
306         return E_ERR;
307     }
308     if (AddStringToFile(extraDataFd, GetVideoInfoTag(GetFileSize(videoPath) + VERSION_TAG_LEN)) == E_ERR) {
309         MEDIA_ERR_LOG("write video info tag err");
310         return E_ERR;
311     }
312     fileSize = MIN_STANDARD_SIZE;
313     return E_OK;
314 }
315 
MergeFile(const UniqueFd & imageFd,const UniqueFd & videoFd,const UniqueFd & livePhotoFd,const string & extraPath,int64_t coverPosition)316 static int32_t MergeFile(const UniqueFd& imageFd, const UniqueFd& videoFd, const UniqueFd& livePhotoFd,
317     const string& extraPath, int64_t coverPosition)
318 {
319     if (WriteContentTofile(livePhotoFd, imageFd) == E_ERR) {
320         MEDIA_ERR_LOG("failed to sendfile from image file");
321         return E_ERR;
322     }
323     if (WriteContentTofile(livePhotoFd, videoFd) == E_ERR) {
324         MEDIA_ERR_LOG("failed to sendfile from video file");
325         return E_ERR;
326     }
327     if (WriteExtraData(extraPath, livePhotoFd, videoFd, coverPosition) == E_ERR) {
328         MEDIA_ERR_LOG("write cinemagraph info err");
329         return E_ERR;
330     }
331     return E_OK;
332 }
333 
GetFrameIndex(int64_t time,const int32_t fd)334 uint32_t MovingPhotoFileUtils::GetFrameIndex(int64_t time, const int32_t fd)
335 {
336     MediaLibraryTracer tracer;
337     tracer.Start("GetFrameIndex");
338     uint32_t index{0};
339     if (time == 0) {
340         return index;
341     }
342     if (fd < 0) {
343         MEDIA_ERR_LOG("file is error");
344         return index;
345     }
346     std::shared_ptr<AVMetadataHelper> avMetadataHelper = AVMetadataHelperFactory::CreateAVMetadataHelper();
347     if (avMetadataHelper == nullptr) {
348         MEDIA_ERR_LOG("AV metadata helper is null");
349         return index;
350     }
351     if (avMetadataHelper->SetSource(fd, 0, static_cast<int64_t>(GetFileSize(fd)),
352         AV_META_USAGE_FRAME_INDEX_CONVERT) != E_OK) {
353         MEDIA_ERR_LOG("failed to set source");
354         return index;
355     }
356     if (avMetadataHelper->GetFrameIndexByTime(time, index) != E_OK) {
357         MEDIA_ERR_LOG("failed to get frame index");
358         return index;
359     }
360     tracer.Finish();
361     return index;
362 }
363 
ConvertToLivePhoto(const string & movingPhotoImagepath,int64_t coverPosition,std::string & livePhotoPath,int32_t userId)364 int32_t MovingPhotoFileUtils::ConvertToLivePhoto(const string& movingPhotoImagepath, int64_t coverPosition,
365     std::string &livePhotoPath, int32_t userId)
366 {
367     string imagePath = AppendUserId(movingPhotoImagepath, userId);
368     string videoPath = GetMovingPhotoVideoPath(movingPhotoImagepath, userId);
369     string cacheDir = GetLivePhotoCacheDir(movingPhotoImagepath, userId);
370     string extraPath = GetMovingPhotoExtraDataPath(movingPhotoImagepath, userId);
371     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::CreateDirectory(cacheDir),
372         E_HAS_FS_ERROR, "Cannot create dir %{private}s, errno %{public}d", cacheDir.c_str(), errno);
373     string cachePath = GetLivePhotoCachePath(movingPhotoImagepath, userId);
374     if (MediaFileUtils::IsFileExists(cachePath)) {
375         livePhotoPath = cachePath;
376         return E_OK;
377     }
378     string absImagePath;
379     CHECK_AND_RETURN_RET_LOG(PathToRealPath(imagePath, absImagePath),
380         E_HAS_FS_ERROR, "file is not real path: %{private}s, errno: %{public}d", imagePath.c_str(), errno);
381     UniqueFd imageFd(open(absImagePath.c_str(), O_RDONLY));
382     if (imageFd.Get() == E_ERR) {
383         MEDIA_ERR_LOG("failed to open image file, errno: %{public}d", errno);
384         return E_ERR;
385     }
386     string absVideoPath;
387     CHECK_AND_RETURN_RET_LOG(PathToRealPath(videoPath, absVideoPath),
388         E_HAS_FS_ERROR, "file is not real path: %{private}s, errno: %{public}d", videoPath.c_str(), errno);
389     UniqueFd videoFd(open(absVideoPath.c_str(), O_RDONLY));
390     if (videoFd.Get() == E_ERR) {
391         MEDIA_ERR_LOG("failed to open video file, errno: %{public}d", errno);
392         return E_ERR;
393     }
394     if (MediaFileUtils::CreateAsset(cachePath) != E_OK) {
395         MEDIA_ERR_LOG("Failed to create file, path:%{private}s", cachePath.c_str());
396         return E_ERR;
397     }
398     string absCachePath;
399     CHECK_AND_RETURN_RET_LOG(PathToRealPath(cachePath, absCachePath),
400         E_HAS_FS_ERROR, "file is not real path: %{private}s, errno: %{public}d", cachePath.c_str(), errno);
401     UniqueFd livePhotoFd(open(absCachePath.c_str(), O_WRONLY | O_TRUNC));
402     if (livePhotoFd.Get() == E_ERR) {
403         MEDIA_ERR_LOG("failed to open live photo file, errno: %{public}d", errno);
404         return E_ERR;
405     }
406     if (MergeFile(imageFd, videoFd, livePhotoFd, extraPath, coverPosition) == E_ERR) {
407         MEDIA_ERR_LOG("failed to MergeFile file");
408         if (!MediaFileUtils::DeleteFile(absCachePath)) {
409             MEDIA_ERR_LOG("failed to delete cache file, errno: %{public}d", errno);
410         }
411         return E_ERR;
412     }
413     livePhotoPath = absCachePath;
414     return E_OK;
415 }
416 
ConvertToSourceLivePhoto(const string & movingPhotoImagePath,string & sourceLivePhotoPath,int32_t userId)417 int32_t MovingPhotoFileUtils::ConvertToSourceLivePhoto(const string& movingPhotoImagePath,
418     string& sourceLivePhotoPath, int32_t userId)
419 {
420     string sourceImagePath = GetSourceMovingPhotoImagePath(movingPhotoImagePath, userId);
421     string sourceVideoPath = GetSourceMovingPhotoVideoPath(movingPhotoImagePath, userId);
422     if (!MediaFileUtils::IsFileExists(sourceVideoPath)) {
423         sourceVideoPath = GetMovingPhotoVideoPath(movingPhotoImagePath, userId);
424     }
425     string extraDataPath = GetMovingPhotoExtraDataPath(movingPhotoImagePath, userId);
426     string cacheDir = GetLivePhotoCacheDir(movingPhotoImagePath, userId);
427     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::CreateDirectory(cacheDir), E_HAS_FS_ERROR,
428         "Cannot create dir %{private}s, errno %{public}d", cacheDir.c_str(), errno);
429     string sourceCachePath = GetSourceLivePhotoCachePath(movingPhotoImagePath, userId);
430     if (MediaFileUtils::IsFileExists(sourceCachePath)) {
431         sourceLivePhotoPath = sourceCachePath;
432         MEDIA_INFO_LOG("source live photo exists: %{private}s", sourceCachePath.c_str());
433         return E_OK;
434     }
435     string absSourceImagePath;
436     CHECK_AND_RETURN_RET_LOG(PathToRealPath(sourceImagePath, absSourceImagePath),
437         E_HAS_FS_ERROR, "file is not real path: %{private}s, errno: %{public}d", sourceImagePath.c_str(), errno);
438     UniqueFd imageFd(open(absSourceImagePath.c_str(), O_RDONLY));
439     CHECK_AND_RETURN_RET_LOG(imageFd.Get() >= 0, E_HAS_FS_ERROR,
440         "Failed to open source image:%{private}s, errno:%{public}d", sourceImagePath.c_str(), errno);
441     string absSourceVideoPath;
442     CHECK_AND_RETURN_RET_LOG(PathToRealPath(sourceVideoPath, absSourceVideoPath),
443         E_HAS_FS_ERROR, "file is not real path: %{private}s, errno: %{public}d", sourceVideoPath.c_str(), errno);
444     UniqueFd videoFd(open(absSourceVideoPath.c_str(), O_RDONLY));
445     CHECK_AND_RETURN_RET_LOG(videoFd.Get() >= 0, E_HAS_FS_ERROR,
446         "Failed to open source video:%{private}s, errno:%{public}d", sourceVideoPath.c_str(), errno);
447     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::CreateAsset(sourceCachePath) == E_OK, E_HAS_FS_ERROR,
448         "Failed to create source live photo:%{private}s, errno:%{public}d", sourceCachePath.c_str(), errno);
449     string absSourceCachePath;
450     CHECK_AND_RETURN_RET_LOG(PathToRealPath(sourceCachePath, absSourceCachePath),
451         E_HAS_FS_ERROR, "file is not real path: %{private}s, errno: %{public}d", sourceCachePath.c_str(), errno);
452     UniqueFd livePhotoFd(open(absSourceCachePath.c_str(), O_WRONLY | O_TRUNC));
453     CHECK_AND_RETURN_RET_LOG(livePhotoFd.Get() >= 0, E_HAS_FS_ERROR,
454         "Failed to open source live photo:%{private}s, errno:%{public}d", absSourceCachePath.c_str(), errno);
455 
456     if (MergeFile(imageFd, videoFd, livePhotoFd, extraDataPath, 0) != E_OK) {
457         MEDIA_ERR_LOG("Failed to merge file of sourve live photo");
458         return E_ERR;
459     }
460     sourceLivePhotoPath = absSourceCachePath;
461     return E_OK;
462 }
463 
IsLivePhoto(const string & path)464 bool MovingPhotoFileUtils::IsLivePhoto(const string& path)
465 {
466     string absPath;
467     if (!PathToRealPath(path, absPath)) {
468         MEDIA_ERR_LOG("file is not real path: %{private}s, errno: %{public}d", path.c_str(), errno);
469         return false;
470     }
471     UniqueFd livePhotoFd(open(absPath.c_str(), O_RDONLY));
472     if (GetFileSize(livePhotoFd.Get()) < LIVE_TAG_LEN) {
473         MEDIA_ERR_LOG("failed to get file size errno: %{public}d", errno);
474         return false;
475     }
476     off_t offset = lseek(livePhotoFd.Get(), -LIVE_TAG_LEN, SEEK_END);
477     if (offset == E_ERR) {
478         MEDIA_ERR_LOG("failed to lseek file errno: %{public}d", errno);
479         return false;
480     }
481     char buffer[LIVE_TAG_LEN + 1];
482     ssize_t bytesRead = read(livePhotoFd.Get(), buffer, LIVE_TAG_LEN);
483     if (bytesRead == E_ERR) {
484         MEDIA_ERR_LOG("failed to read file errno: %{public}d", errno);
485         return false;
486     }
487     buffer[bytesRead] = '\0';
488     for (uint16_t i = 0; i < LIVE_TAG.size(); i++) {
489         if (LIVE_TAG[i] != buffer[i]) {
490             return false;
491         }
492     }
493     return true;
494 }
495 
GetLivePhotoSize(int32_t fd,int64_t & liveSize)496 int32_t MovingPhotoFileUtils::GetLivePhotoSize(int32_t fd, int64_t &liveSize)
497 {
498     if (fd < 0) {
499         MEDIA_ERR_LOG("invalid live photo fd");
500         return E_ERR;
501     }
502     if (lseek(fd, -LIVE_TAG_LEN, SEEK_END) == E_ERR) {
503         MEDIA_ERR_LOG("failed to lseek file, errno: %{public}d", errno);
504         return E_ERR;
505     }
506     char buffer[LIVE_TAG_LEN + 1];
507     ssize_t bytesRead = read(fd, buffer, LIVE_TAG_LEN);
508     if (bytesRead == E_ERR) {
509         MEDIA_ERR_LOG("failed to read file, errno: %{public}d", errno);
510         return E_ERR;
511     }
512     buffer[bytesRead] = '\0';
513     for (size_t i = 0; i < LIVE_TAG.size(); i++) {
514         if (LIVE_TAG[i] != buffer[i]) {
515             return E_ERR;
516         }
517     }
518     liveSize = atoi(buffer + LIVE_TAG.length());
519     return E_OK;
520 }
521 
SendLivePhoto(const int32_t & livePhotoFd,const string & destPath,int64_t sizeToSend,off_t & offset)522 static int32_t SendLivePhoto(const int32_t &livePhotoFd, const string &destPath, int64_t sizeToSend, off_t &offset)
523 {
524     struct stat64 statSrc {};
525     CHECK_AND_RETURN_RET_LOG(livePhotoFd >= 0, livePhotoFd, "Failed to check src fd of live photo");
526     CHECK_AND_RETURN_RET_LOG(fstat64(livePhotoFd, &statSrc) == 0, E_HAS_FS_ERROR,
527         "Failed to get file state of live photo, errno = %{public}d", errno);
528     off_t totalSize = statSrc.st_size;
529     CHECK_AND_RETURN_RET_LOG(sizeToSend <= totalSize - offset, E_INVALID_LIVE_PHOTO, "Failed to check sizeToSend");
530 
531     if (!MediaFileUtils::IsFileExists(destPath) && MediaFileUtils::CreateAsset(destPath) != E_OK) {
532         MEDIA_ERR_LOG("Failed to create file, path:%{private}s", destPath.c_str());
533         return E_HAS_FS_ERROR;
534     }
535     string absDestPath;
536     if (!PathToRealPath(destPath, absDestPath)) {
537         MEDIA_ERR_LOG("file is not real path: %{private}s, errno: %{public}d", destPath.c_str(), errno);
538         return E_HAS_FS_ERROR;
539     }
540     UniqueFd destFd(open(absDestPath.c_str(), O_WRONLY));
541     if (destFd.Get() < 0) {
542         MEDIA_ERR_LOG("Failed to open dest path:%{private}s, errno:%{public}d", absDestPath.c_str(), errno);
543         return destFd.Get();
544     }
545 
546     while (sizeToSend > 0) {
547         ssize_t sent = sendfile(destFd.Get(), livePhotoFd, &offset, sizeToSend);
548         if (sent < 0) {
549             MEDIA_ERR_LOG("Failed to sendfile with errno=%{public}d", errno);
550             return sent;
551         }
552         sizeToSend -= sent;
553     }
554     return E_OK;
555 }
556 
IsValidHexInteger(const string & hexStr)557 static bool IsValidHexInteger(const string &hexStr)
558 {
559     constexpr int32_t HEX_INT_LENGTH = 8;
560     if (hexStr.length() > HEX_INT_LENGTH) {
561         MEDIA_ERR_LOG("hexStr length > HEX_INT_LENGTH");
562         return false;
563     }
564     char* end = nullptr;
565     errno = 0;
566     uint64_t num = std::strtoull(hexStr.c_str(), &end, HEX_BASE);
567     if (errno == ERANGE || end == nullptr || end == hexStr.c_str() || *end != '\0') {
568         MEDIA_ERR_LOG("strtoull exec error");
569         return false;
570     }
571     int32_t maxInteger = numeric_limits<int32_t>::max();
572     if (num > static_cast<uint64_t>(maxInteger)) {
573         MEDIA_ERR_LOG("num > int32_t.max, num: %{public}llu", static_cast<unsigned long long>(num));
574         return false;
575     }
576     return true;
577 }
578 
ReadLivePhoto(const int32_t & fd,void * buffer,off_t needSize,off_t offset)579 static int32_t ReadLivePhoto(const int32_t &fd, void *buffer, off_t needSize, off_t offset)
580 {
581     if (buffer == nullptr) {
582         return E_OK;
583     }
584 
585     if (lseek(fd, offset, SEEK_SET) == E_ERR) {
586         MEDIA_ERR_LOG("failed to lseek extra file errno: %{public}d", errno);
587         return E_ERR;
588     }
589     memset_s(buffer, needSize + 1, 0, needSize + 1);
590     while (needSize > 0) {
591         ssize_t bytesRead = read(fd, buffer, needSize);
592         if (bytesRead < 0) {
593             MEDIA_ERR_LOG("Failed to read from live photo, errno=%{public}d", errno);
594             return bytesRead;
595         }
596         needSize -= bytesRead;
597     }
598     return E_OK;
599 }
600 
GetExtraDataSize(int32_t livePhotoFd,int64_t & extraDataSize,int64_t maxFileSize)601 static int32_t GetExtraDataSize(int32_t livePhotoFd, int64_t &extraDataSize, int64_t maxFileSize)
602 {
603     struct stat64 st;
604     CHECK_AND_RETURN_RET_LOG(fstat64(livePhotoFd, &st) == 0, E_HAS_FS_ERROR,
605         "Failed to get file state of live photo, errno:%{public}d", errno);
606     int64_t totalSize = st.st_size;
607     CHECK_AND_RETURN_RET_LOG(totalSize > MIN_STANDARD_SIZE, E_INVALID_LIVE_PHOTO,
608         "Failed to check live photo, total size is %{public}" PRId64, totalSize);
609 
610     char versionTag[VERSION_TAG_LEN + 1] = {0};
611     CHECK_AND_RETURN_RET_LOG(lseek(livePhotoFd, -MIN_STANDARD_SIZE, SEEK_END) != -1, E_HAS_FS_ERROR,
612         "Failed to lseek version tag, errno:%{public}d", errno);
613     CHECK_AND_RETURN_RET_LOG(read(livePhotoFd, versionTag, VERSION_TAG_LEN) != -1, E_HAS_FS_ERROR,
614         "Failed to read version tag, errno:%{public}d", errno);
615 
616     uint32_t version = 0;
617     uint32_t frameIndex = 0;
618     bool hasCinemagraph = false;
619     int32_t ret = MovingPhotoFileUtils::GetVersionAndFrameNum(versionTag, version, frameIndex, hasCinemagraph);
620     if (ret != E_OK) { // not standard version tag
621         extraDataSize = LIVE_TAG_LEN + PLAY_INFO_LEN;
622         return E_OK;
623     }
624 
625     if (!hasCinemagraph) { // extra data without cinemagraph
626         extraDataSize = MIN_STANDARD_SIZE;
627         return E_OK;
628     }
629 
630     // extra data with cinemagraph
631     CHECK_AND_RETURN_RET_LOG(totalSize > MIN_STANDARD_SIZE + CINEMAGRAPH_INFO_SIZE_LEN, E_INVALID_LIVE_PHOTO,
632         "Failed to check live photo with cinemagraph, total size is %{public}" PRId64, totalSize);
633     char cinemagraphSize[CINEMAGRAPH_INFO_SIZE_LEN] = {0};
634     CHECK_AND_RETURN_RET_LOG(lseek(livePhotoFd, -(MIN_STANDARD_SIZE + CINEMAGRAPH_INFO_SIZE_LEN), SEEK_END) != -1,
635         E_HAS_FS_ERROR, "Failed to lseek cinemagraph size, errno:%{public}d", errno);
636     CHECK_AND_RETURN_RET_LOG(read(livePhotoFd, cinemagraphSize, CINEMAGRAPH_INFO_SIZE_LEN) != -1, E_HAS_FS_ERROR,
637         "Failed to read cinemagraph size, errno:%{public}d", errno);
638     stringstream cinemagraphSizeStream;
639     for (int32_t i = 0; i < CINEMAGRAPH_INFO_SIZE_LEN; i++) {
640         cinemagraphSizeStream << hex << static_cast<int32_t>(cinemagraphSize[i]);
641     }
642     if (!IsValidHexInteger(cinemagraphSizeStream.str())) {
643         extraDataSize = MIN_STANDARD_SIZE;
644         MEDIA_WARN_LOG("hex string over int max %{public}s", cinemagraphSizeStream.str().c_str());
645         return E_OK;
646     }
647     extraDataSize = MIN_STANDARD_SIZE + std::stoi(cinemagraphSizeStream.str(), 0, HEX_BASE);
648     if (extraDataSize >= maxFileSize) {
649         extraDataSize = MIN_STANDARD_SIZE;
650         MEDIA_WARN_LOG("extra data size over total file size %{public}" PRId64, extraDataSize);
651     }
652     return E_OK;
653 }
654 
ConvertToMovingPhoto(const std::string & livePhotoPath,const string & movingPhotoImagePath,const string & movingPhotoVideoPath,const string & extraDataPath)655 int32_t MovingPhotoFileUtils::ConvertToMovingPhoto(const std::string &livePhotoPath, const string &movingPhotoImagePath,
656     const string &movingPhotoVideoPath, const string &extraDataPath)
657 {
658     string absLivePhotoPath;
659     if (!PathToRealPath(livePhotoPath, absLivePhotoPath)) {
660         MEDIA_ERR_LOG("file is not real path: %{private}s, errno: %{public}d", livePhotoPath.c_str(), errno);
661         return E_HAS_FS_ERROR;
662     }
663     CHECK_AND_RETURN_RET_LOG(livePhotoPath.compare(movingPhotoVideoPath) != 0 &&
664         livePhotoPath.compare(extraDataPath) != 0, E_INVALID_VALUES, "Failed to check dest path");
665     UniqueFd livePhotoFd(open(absLivePhotoPath.c_str(), O_RDONLY));
666     CHECK_AND_RETURN_RET_LOG(livePhotoFd.Get() >= 0, E_HAS_FS_ERROR,
667         "Failed to open live photo:%{private}s, errno:%{public}d", absLivePhotoPath.c_str(), errno);
668 
669     struct stat64 st;
670     CHECK_AND_RETURN_RET_LOG(fstat64(livePhotoFd.Get(), &st) == 0, E_HAS_FS_ERROR,
671         "Failed to get file state of live photo, errno:%{public}d", errno);
672     int64_t totalSize = st.st_size;
673     CHECK_AND_RETURN_RET_LOG(totalSize > MIN_STANDARD_SIZE, E_INVALID_LIVE_PHOTO,
674         "Failed to check live photo, total size is %{public}" PRId64, totalSize);
675     char liveTag[LIVE_TAG_LEN + 1] = {0};
676     CHECK_AND_RETURN_RET_LOG(lseek(livePhotoFd.Get(), -LIVE_TAG_LEN, SEEK_END) != -1, E_HAS_FS_ERROR,
677         "Failed to lseek live tag, errno:%{public}d", errno);
678     CHECK_AND_RETURN_RET_LOG(read(livePhotoFd.Get(), liveTag, LIVE_TAG_LEN) != -1, E_HAS_FS_ERROR,
679         "Failed to read live tag, errno:%{public}d", errno);
680     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::StartsWith(liveTag, LIVE_TAG), E_INVALID_VALUES, "Invalid live photo");
681 
682     int64_t liveSize = atoi(liveTag + LIVE_TAG.length());
683     int64_t imageSize = totalSize - liveSize - LIVE_TAG_LEN - PLAY_INFO_LEN;
684     int64_t extraDataSize = 0;
685     int32_t err = GetExtraDataSize(livePhotoFd.Get(), extraDataSize, totalSize - imageSize);
686     CHECK_AND_RETURN_RET_LOG(err == E_OK, E_INVALID_LIVE_PHOTO,
687         "Failed to get size of extra data, err:%{public}" PRId64, extraDataSize);
688     int64_t videoSize = totalSize - imageSize - extraDataSize;
689     CHECK_AND_RETURN_RET_LOG(imageSize > 0 && videoSize > 0, E_INVALID_LIVE_PHOTO,
690         "Failed to check live photo, image size:%{public}" PRId64 "video size:%{public}" PRId64, imageSize, videoSize);
691     off_t offset = 0;
692     bool isSameImagePath = livePhotoPath.compare(movingPhotoImagePath) == 0;
693     string tempImagePath = isSameImagePath ? movingPhotoImagePath + ".temp" : movingPhotoImagePath;
694     CHECK_AND_RETURN_RET_LOG((err = SendLivePhoto(livePhotoFd.Get(), tempImagePath, imageSize, offset)) == E_OK, err,
695         "Failed to copy image of live photo");
696     CHECK_AND_RETURN_RET_LOG((err = SendLivePhoto(livePhotoFd.Get(), movingPhotoVideoPath, videoSize, offset)) == E_OK,
697         err, "Failed to copy video of live photo");
698     if (!extraDataPath.empty()) {
699         CHECK_AND_RETURN_RET_LOG((err = SendLivePhoto(livePhotoFd.Get(), extraDataPath, extraDataSize, offset)) == E_OK,
700             err, "Failed to copy extra data of live photo");
701     }
702     if (isSameImagePath) {
703         err = rename(tempImagePath.c_str(), movingPhotoImagePath.c_str());
704         CHECK_AND_RETURN_RET_LOG(err == E_OK, err, "Failed to rename image:%{public}d, errno:%{public}d", err, errno);
705     }
706     return E_OK;
707 }
708 
GetMovingPhotoDetailedSize(const int32_t fd,int64_t & imageSize,int64_t & videoSize,int64_t & extraDataSize)709 int32_t MovingPhotoFileUtils::GetMovingPhotoDetailedSize(const int32_t fd,
710     int64_t &imageSize, int64_t &videoSize, int64_t &extraDataSize)
711 {
712     CHECK_AND_RETURN_RET_LOG(fd >= 0, E_HAS_FS_ERROR, "fd is invalid");
713     struct stat64 st;
714     CHECK_AND_RETURN_RET_LOG(fstat64(fd, &st) == 0, E_HAS_FS_ERROR,
715         "Failed to get file state of live photo, errno:%{public}d", errno);
716     int64_t totalSize = st.st_size;
717     CHECK_AND_RETURN_RET_LOG(totalSize > MIN_STANDARD_SIZE, E_INVALID_LIVE_PHOTO,
718         "Failed to check live photo, total size is %{public}" PRId64, totalSize);
719     char liveTag[LIVE_TAG_LEN + 1] = {0};
720     CHECK_AND_RETURN_RET_LOG(lseek(fd, -LIVE_TAG_LEN, SEEK_END) != -1, E_HAS_FS_ERROR,
721         "Failed to lseek live tag, errno:%{public}d", errno);
722     CHECK_AND_RETURN_RET_LOG(read(fd, liveTag, LIVE_TAG_LEN) != -1, E_HAS_FS_ERROR,
723         "Failed to read live tag, errno:%{public}d", errno);
724     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::StartsWith(liveTag, LIVE_TAG), E_INVALID_VALUES, "Invalid live photo");
725 
726     int64_t liveSize = atoi(liveTag + LIVE_TAG.length());
727     imageSize = totalSize - liveSize - LIVE_TAG_LEN - PLAY_INFO_LEN;
728     int32_t err = GetExtraDataSize(fd, extraDataSize, totalSize - imageSize);
729     CHECK_AND_RETURN_RET_LOG(err == E_OK, E_INVALID_LIVE_PHOTO,
730         "Failed to get size of extra data, err:%{public}" PRId64, extraDataSize);
731     videoSize = totalSize - imageSize - extraDataSize;
732     CHECK_AND_RETURN_RET_LOG(imageSize > 0 && videoSize > 0, E_INVALID_LIVE_PHOTO,
733         "Failed to check live photo, image size:%{public}" PRId64 "video size:%{public}" PRId64, imageSize, videoSize);
734     return E_OK;
735 }
736 
ConvertToMovingPhoto(const int32_t fd,const string & movingPhotoImagePath,const string & movingPhotoVideoPath,const string & extraDataPath)737 int32_t MovingPhotoFileUtils::ConvertToMovingPhoto(const int32_t fd, const string &movingPhotoImagePath,
738     const string &movingPhotoVideoPath, const string &extraDataPath)
739 {
740     CHECK_AND_RETURN_RET_LOG(fd >= 0, E_HAS_FS_ERROR, "fd is invalid");
741     int64_t imageSize = 0;
742     int64_t videoSize = 0;
743     int64_t extraDataSize = 0;
744     int32_t err = GetMovingPhotoDetailedSize(fd, imageSize, videoSize, extraDataSize);
745     CHECK_AND_RETURN_RET_LOG(err == E_OK, err, "Failed to get detailed size of moving photo");
746     off_t offset = 0;
747     if (!movingPhotoImagePath.empty()) {
748         CHECK_AND_RETURN_RET_LOG((err = SendLivePhoto(fd, movingPhotoImagePath, imageSize, offset)) == E_OK, err,
749             "Failed to copy image of live photo");
750     }
751     if (!movingPhotoVideoPath.empty()) {
752         offset = imageSize;
753         CHECK_AND_RETURN_RET_LOG((err = SendLivePhoto(fd, movingPhotoVideoPath, videoSize, offset)) == E_OK, err,
754             "Failed to copy video of live photo");
755     }
756     if (!extraDataPath.empty()) {
757         offset = imageSize + videoSize;
758         CHECK_AND_RETURN_RET_LOG((err = SendLivePhoto(fd, extraDataPath, extraDataSize, offset)) == E_OK, err,
759             "Failed to copy extra data of live photo");
760     }
761     return E_OK;
762 }
763 
ConvertToMovingPhoto(const int32_t fd,void * imageArrayBuffer,void * videoArrayBuffer,void * extraDataArrayBuffer)764 int32_t MovingPhotoFileUtils::ConvertToMovingPhoto(const int32_t fd, void *imageArrayBuffer,
765     void *videoArrayBuffer, void *extraDataArrayBuffer)
766 {
767     CHECK_AND_RETURN_RET_LOG(fd >= 0, E_HAS_FS_ERROR, "fd is invalid");
768     int64_t imageSize = 0;
769     int64_t videoSize = 0;
770     int64_t extraDataSize = 0;
771     int32_t err = GetMovingPhotoDetailedSize(fd, imageSize, videoSize, extraDataSize);
772     CHECK_AND_RETURN_RET_LOG(err == E_OK, err, "Failed to get detailed size of moving photo");
773     CHECK_AND_RETURN_RET_LOG((err = ReadLivePhoto(fd, imageArrayBuffer, imageSize, 0)) == E_OK, err,
774         "Failed to copy image of live photo");
775     CHECK_AND_RETURN_RET_LOG((err = ReadLivePhoto(fd, videoArrayBuffer, videoSize, imageSize)) == E_OK, err,
776         "Failed to copy video of live photo");
777     CHECK_AND_RETURN_RET_LOG(
778         (err = ReadLivePhoto(fd, extraDataArrayBuffer, extraDataSize, imageSize + videoSize)) == E_OK, err,
779         "Failed to copy extra data of live photo");
780     return E_OK;
781 }
782 
GetMovingPhotoCoverPosition(const UniqueFd & uniqueFd,const int64_t size,const uint32_t frameIndex,uint64_t & coverPosition,int32_t scene)783 static int32_t GetMovingPhotoCoverPosition(const UniqueFd &uniqueFd, const int64_t size,
784     const uint32_t frameIndex, uint64_t &coverPosition, int32_t scene)
785 {
786     MediaLibraryTracer tracer;
787     tracer.Start("AVMetadataHelper");
788     shared_ptr<AVMetadataHelper> helper = AVMetadataHelperFactory::CreateAVMetadataHelper();
789     if (helper == nullptr) {
790         MEDIA_ERR_LOG("AV metadata helper is null");
791         return E_AVMETADATA;
792     }
793 
794     // notify media_service clone event.
795     if (scene == Scene::AV_META_SCENE_CLONE) {
796         helper->SetScene(static_cast<Scene>(scene));
797     }
798     int32_t err = helper->SetSource(uniqueFd.Get(), 0, size, AV_META_USAGE_FRAME_INDEX_CONVERT);
799     tracer.Finish();
800     if (err != 0) {
801         MEDIA_ERR_LOG("SetSource failed for the given fd, err = %{public}d", err);
802         return E_AVMETADATA;
803     }
804 
805     tracer.Start("AVMetadataHelper->GetTimeByFrameIndex");
806     err = helper->GetTimeByFrameIndex(frameIndex, coverPosition);
807     tracer.Finish();
808     if (err != 0) {
809         MEDIA_ERR_LOG("Failed to GetTimeByFrameIndex, err = %{public}d", err);
810         return E_AVMETADATA;
811     }
812     return E_OK;
813 }
814 
GetCoverPosition(const std::string & videoPath,const uint32_t frameIndex,uint64_t & coverPosition,int32_t scene)815 int32_t MovingPhotoFileUtils::GetCoverPosition(const std::string &videoPath, const uint32_t frameIndex,
816     uint64_t &coverPosition, int32_t scene)
817 {
818     string absVideoPath;
819     if (!PathToRealPath(videoPath, absVideoPath)) {
820         MEDIA_ERR_LOG("Failed to get real path: %{private}s, errno: %{public}d", videoPath.c_str(), errno);
821         return E_HAS_FS_ERROR;
822     }
823 
824     UniqueFd uniqueFd(open(absVideoPath.c_str(), O_RDONLY));
825     if (uniqueFd.Get() < 0) {
826         MEDIA_ERR_LOG("Failed to open %{private}s, errno: %{public}d", absVideoPath.c_str(), errno);
827         return E_HAS_FS_ERROR;
828     }
829     struct stat64 st;
830     if (fstat64(uniqueFd.Get(), &st) != 0) {
831         MEDIA_ERR_LOG("Failed to get file state, errno: %{public}d", errno);
832         return E_HAS_FS_ERROR;
833     }
834     return GetMovingPhotoCoverPosition(uniqueFd, st.st_size, frameIndex, coverPosition, scene);
835 }
836 
EndsWith(const string & str,const string & endStr)837 bool EndsWith(const string &str, const string &endStr)
838 {
839     if (str.length() < endStr.length()) {
840         return false;
841     }
842     return str.rfind(endStr) == str.length() - endStr.length();
843 }
844 
GetVersionAndFrameNum(const string & tag,uint32_t & version,uint32_t & frameIndex,bool & hasCinemagraphInfo)845 int32_t MovingPhotoFileUtils::GetVersionAndFrameNum(const string &tag,
846     uint32_t &version, uint32_t &frameIndex, bool &hasCinemagraphInfo)
847 {
848     static const string VERSION_TAG_REGEX = "^[vV](\\d+)_[fF](\\d+).*";
849     std::regex pattern(VERSION_TAG_REGEX);
850     std::smatch result;
851     if (!std::regex_search(tag, result, pattern)) {
852         MEDIA_WARN_LOG("tag is not standard version tag: %{public}s", tag.c_str());
853         return E_INVALID_VALUES;
854     }
855 
856     constexpr int32_t VERSION_POSITION = 1;
857     constexpr int32_t FRAME_INDEX_POSITION = 2;
858     version = static_cast<uint32_t>(atoi(result[VERSION_POSITION].str().c_str()));
859     frameIndex = static_cast<uint32_t>(atoi(result[FRAME_INDEX_POSITION].str().c_str()));
860     size_t blankIndex = tag.find_first_of(' ');
861     string tagTrimmed = tag;
862     if (blankIndex != string::npos) {
863         tagTrimmed = tagTrimmed.substr(0, blankIndex);
864     }
865     hasCinemagraphInfo = EndsWith(tagTrimmed, "_c") || EndsWith(tagTrimmed, "_C");
866     return E_OK;
867 }
868 
GetVersionAndFrameNum(int32_t fd,uint32_t & version,uint32_t & frameIndex,bool & hasCinemagraphInfo)869 int32_t MovingPhotoFileUtils::GetVersionAndFrameNum(int32_t fd,
870     uint32_t &version, uint32_t &frameIndex, bool &hasCinemagraphInfo)
871 {
872     CHECK_AND_RETURN_RET_LOG(fd >= 0, E_HAS_FS_ERROR, "Failed to check fd, errno:%{public}d", errno);
873     struct stat64 st;
874     CHECK_AND_RETURN_RET_LOG(fstat64(fd, &st) == 0, E_HAS_FS_ERROR,
875         "Failed to get file state, errno:%{public}d", errno);
876     int64_t totalSize = st.st_size;
877     CHECK_AND_RETURN_RET_LOG(totalSize >= MIN_STANDARD_SIZE, E_INVALID_LIVE_PHOTO,
878         "Failed to fetch version tag, total size is %{public}" PRId64, totalSize);
879 
880     char versionTag[VERSION_TAG_LEN + 1] = {0};
881     CHECK_AND_RETURN_RET_LOG(lseek(fd, -MIN_STANDARD_SIZE, SEEK_END) != -1, E_HAS_FS_ERROR,
882         "Failed to lseek version tag, errno:%{public}d", errno);
883     CHECK_AND_RETURN_RET_LOG(read(fd, versionTag, VERSION_TAG_LEN) != -1, E_HAS_FS_ERROR,
884         "Failed to read version tag, errno:%{public}d", errno);
885     return MovingPhotoFileUtils::GetVersionAndFrameNum(versionTag, version, frameIndex, hasCinemagraphInfo);
886 }
887 
GetMovingPhotoVideoPath(const string & imagePath,int32_t userId)888 string MovingPhotoFileUtils::GetMovingPhotoVideoPath(const string &imagePath, int32_t userId)
889 {
890     return MediaFileUtils::GetMovingPhotoVideoPath(AppendUserId(imagePath, userId));
891 }
892 
GetMovingPhotoExtraDataDir(const string & imagePath,int32_t userId)893 string MovingPhotoFileUtils::GetMovingPhotoExtraDataDir(const string &imagePath, int32_t userId)
894 {
895     if (imagePath.length() < ROOT_MEDIA_DIR.length() || !MediaFileUtils::StartsWith(imagePath, ROOT_MEDIA_DIR)) {
896         return "";
897     }
898     return AppendUserId(MEDIA_EXTRA_DATA_DIR, userId) + imagePath.substr(ROOT_MEDIA_DIR.length());
899 }
900 
GetMovingPhotoExtraDataPath(const string & imagePath,int32_t userId)901 string MovingPhotoFileUtils::GetMovingPhotoExtraDataPath(const string &imagePath, int32_t userId)
902 {
903     string parentPath = GetMovingPhotoExtraDataDir(imagePath, userId);
904     if (parentPath.empty()) {
905         return "";
906     }
907     return parentPath + "/extraData";
908 }
909 
GetSourceMovingPhotoImagePath(const string & imagePath,int32_t userId)910 string MovingPhotoFileUtils::GetSourceMovingPhotoImagePath(const string& imagePath, int32_t userId)
911 {
912     return GetEditDataSourcePath(imagePath, userId);
913 }
914 
GetSourceMovingPhotoVideoPath(const string & imagePath,int32_t userId)915 string MovingPhotoFileUtils::GetSourceMovingPhotoVideoPath(const string& imagePath, int32_t userId)
916 {
917     return GetMovingPhotoVideoPath(GetSourceMovingPhotoImagePath(imagePath, userId));
918 }
919 
GetLivePhotoCacheDir(const string & imagePath,int32_t userId)920 string MovingPhotoFileUtils::GetLivePhotoCacheDir(const string &imagePath, int32_t userId)
921 {
922     if (imagePath.length() < ROOT_MEDIA_DIR.length() || !MediaFileUtils::StartsWith(imagePath, ROOT_MEDIA_DIR)) {
923         return "";
924     }
925     return AppendUserId(MEDIA_CACHE_DIR, userId) + imagePath.substr(ROOT_MEDIA_DIR.length());
926 }
927 
GetLivePhotoCachePath(const string & imagePath,int32_t userId)928 string MovingPhotoFileUtils::GetLivePhotoCachePath(const string &imagePath, int32_t userId)
929 {
930     string parentPath = GetLivePhotoCacheDir(imagePath, userId);
931     if (parentPath.empty()) {
932         return "";
933     }
934     return parentPath + "/livePhoto." + MediaFileUtils::GetExtensionFromPath(imagePath);
935 }
936 
GetSourceLivePhotoCachePath(const string & imagePath,int32_t userId)937 string MovingPhotoFileUtils::GetSourceLivePhotoCachePath(const string& imagePath, int32_t userId)
938 {
939     string parentPath = GetLivePhotoCacheDir(imagePath, userId);
940     if (parentPath.empty()) {
941         return "";
942     }
943     return parentPath + "/sourceLivePhoto." + MediaFileUtils::GetExtensionFromPath(imagePath);
944 }
945 
IsMovingPhoto(int32_t subtype,int32_t effectMode,int32_t originalSubtype)946 bool MovingPhotoFileUtils::IsMovingPhoto(int32_t subtype, int32_t effectMode, int32_t originalSubtype)
947 {
948     return subtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) ||
949            effectMode == static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY) ||
950            IsGraffiti(subtype, originalSubtype);
951 }
952 
IsGraffiti(int32_t subtype,int32_t originalSubtype)953 bool MovingPhotoFileUtils::IsGraffiti(int32_t subtype, int32_t originalSubtype)
954 {
955     return subtype == static_cast<int32_t>(PhotoSubType::DEFAULT) &&
956            originalSubtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO);
957 }
958 
GetMovingPhotoSize(const std::string & imagePath,int32_t userId)959 size_t MovingPhotoFileUtils::GetMovingPhotoSize(const std::string &imagePath, int32_t userId)
960 {
961     string movingPhotoImagePath = AppendUserId(imagePath, userId);
962     string movingPhotoVideoPath = GetMovingPhotoVideoPath(imagePath, userId);
963     string movingPhotoExtraDataPath = GetMovingPhotoExtraDataPath(imagePath, userId);
964     size_t imageSize = 0;
965     size_t videoSize = 0;
966     size_t extraDataSize = 0;
967     (void)MediaFileUtils::GetFileSize(movingPhotoImagePath, imageSize);
968     (void)MediaFileUtils::GetFileSize(movingPhotoVideoPath, videoSize);
969     (void)MediaFileUtils::GetFileSize(movingPhotoExtraDataPath, extraDataSize);
970     return imageSize + videoSize + extraDataSize;
971 }
972 } // namespace OHOS::Media