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 UniqueFd & livePhotoFd,const string & destPath,int64_t sizeToSend,off_t & offset)522 static int32_t SendLivePhoto(const UniqueFd &livePhotoFd, const string &destPath, int64_t sizeToSend, off_t &offset)
523 {
524 struct stat64 statSrc {};
525 CHECK_AND_RETURN_RET_LOG(livePhotoFd.Get() >= 0, livePhotoFd.Get(), "Failed to check src fd of live photo");
526 CHECK_AND_RETURN_RET_LOG(fstat64(livePhotoFd.Get(), &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.Get(), &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 return false;
562 }
563 uint64_t num = stoull(hexStr, nullptr, HEX_BASE);
564 int32_t maxInteger = numeric_limits<int32_t>::max();
565 if (num > static_cast<uint64_t>(maxInteger)) {
566 return false;
567 }
568 return true;
569 }
570
GetExtraDataSize(const UniqueFd & livePhotoFd,int64_t & extraDataSize,int64_t maxFileSize)571 static int32_t GetExtraDataSize(const UniqueFd &livePhotoFd, int64_t &extraDataSize, int64_t maxFileSize)
572 {
573 struct stat64 st;
574 CHECK_AND_RETURN_RET_LOG(fstat64(livePhotoFd.Get(), &st) == 0, E_HAS_FS_ERROR,
575 "Failed to get file state of live photo, errno:%{public}d", errno);
576 int64_t totalSize = st.st_size;
577 CHECK_AND_RETURN_RET_LOG(totalSize > MIN_STANDARD_SIZE, E_INVALID_LIVE_PHOTO,
578 "Failed to check live photo, total size is %{public}" PRId64, totalSize);
579
580 char versionTag[VERSION_TAG_LEN + 1] = {0};
581 CHECK_AND_RETURN_RET_LOG(lseek(livePhotoFd.Get(), -MIN_STANDARD_SIZE, SEEK_END) != -1, E_HAS_FS_ERROR,
582 "Failed to lseek version tag, errno:%{public}d", errno);
583 CHECK_AND_RETURN_RET_LOG(read(livePhotoFd.Get(), versionTag, VERSION_TAG_LEN) != -1, E_HAS_FS_ERROR,
584 "Failed to read version tag, errno:%{public}d", errno);
585
586 uint32_t version = 0;
587 uint32_t frameIndex = 0;
588 bool hasCinemagraph = false;
589 int32_t ret = MovingPhotoFileUtils::GetVersionAndFrameNum(versionTag, version, frameIndex, hasCinemagraph);
590 if (ret != E_OK) { // not standard version tag
591 extraDataSize = LIVE_TAG_LEN + PLAY_INFO_LEN;
592 return E_OK;
593 }
594
595 if (!hasCinemagraph) { // extra data without cinemagraph
596 extraDataSize = MIN_STANDARD_SIZE;
597 return E_OK;
598 }
599
600 // extra data with cinemagraph
601 CHECK_AND_RETURN_RET_LOG(totalSize > MIN_STANDARD_SIZE + CINEMAGRAPH_INFO_SIZE_LEN, E_INVALID_LIVE_PHOTO,
602 "Failed to check live photo with cinemagraph, total size is %{public}" PRId64, totalSize);
603 char cinemagraphSize[CINEMAGRAPH_INFO_SIZE_LEN] = {0};
604 CHECK_AND_RETURN_RET_LOG(lseek(livePhotoFd.Get(), -(MIN_STANDARD_SIZE + CINEMAGRAPH_INFO_SIZE_LEN), SEEK_END) != -1,
605 E_HAS_FS_ERROR, "Failed to lseek cinemagraph size, errno:%{public}d", errno);
606 CHECK_AND_RETURN_RET_LOG(read(livePhotoFd.Get(), cinemagraphSize, CINEMAGRAPH_INFO_SIZE_LEN) != -1, E_HAS_FS_ERROR,
607 "Failed to read cinemagraph size, errno:%{public}d", errno);
608 stringstream cinemagraphSizeStream;
609 for (int32_t i = 0; i < CINEMAGRAPH_INFO_SIZE_LEN; i++) {
610 cinemagraphSizeStream << hex << static_cast<int32_t>(cinemagraphSize[i]);
611 }
612 if (!IsValidHexInteger(cinemagraphSizeStream.str())) {
613 extraDataSize = MIN_STANDARD_SIZE;
614 MEDIA_WARN_LOG("hex string over int max %{public}s", cinemagraphSizeStream.str().c_str());
615 return E_OK;
616 }
617 extraDataSize = MIN_STANDARD_SIZE + std::stoi(cinemagraphSizeStream.str(), 0, HEX_BASE);
618 if (extraDataSize >= maxFileSize) {
619 extraDataSize = MIN_STANDARD_SIZE;
620 MEDIA_WARN_LOG("extra data size over total file size %{public}" PRId64, extraDataSize);
621 }
622 return E_OK;
623 }
624
ConvertToMovingPhoto(const std::string & livePhotoPath,const string & movingPhotoImagePath,const string & movingPhotoVideoPath,const string & extraDataPath)625 int32_t MovingPhotoFileUtils::ConvertToMovingPhoto(const std::string &livePhotoPath, const string &movingPhotoImagePath,
626 const string &movingPhotoVideoPath, const string &extraDataPath)
627 {
628 string absLivePhotoPath;
629 if (!PathToRealPath(livePhotoPath, absLivePhotoPath)) {
630 MEDIA_ERR_LOG("file is not real path: %{private}s, errno: %{public}d", livePhotoPath.c_str(), errno);
631 return E_HAS_FS_ERROR;
632 }
633 CHECK_AND_RETURN_RET_LOG(livePhotoPath.compare(movingPhotoVideoPath) != 0 &&
634 livePhotoPath.compare(extraDataPath) != 0, E_INVALID_VALUES, "Failed to check dest path");
635 UniqueFd livePhotoFd(open(absLivePhotoPath.c_str(), O_RDONLY));
636 CHECK_AND_RETURN_RET_LOG(livePhotoFd.Get() >= 0, E_HAS_FS_ERROR,
637 "Failed to open live photo:%{private}s, errno:%{public}d", absLivePhotoPath.c_str(), errno);
638
639 struct stat64 st;
640 CHECK_AND_RETURN_RET_LOG(fstat64(livePhotoFd.Get(), &st) == 0, E_HAS_FS_ERROR,
641 "Failed to get file state of live photo, errno:%{public}d", errno);
642 int64_t totalSize = st.st_size;
643 CHECK_AND_RETURN_RET_LOG(totalSize > MIN_STANDARD_SIZE, E_INVALID_LIVE_PHOTO,
644 "Failed to check live photo, total size is %{public}" PRId64, totalSize);
645 char liveTag[LIVE_TAG_LEN + 1] = {0};
646 CHECK_AND_RETURN_RET_LOG(lseek(livePhotoFd.Get(), -LIVE_TAG_LEN, SEEK_END) != -1, E_HAS_FS_ERROR,
647 "Failed to lseek live tag, errno:%{public}d", errno);
648 CHECK_AND_RETURN_RET_LOG(read(livePhotoFd.Get(), liveTag, LIVE_TAG_LEN) != -1, E_HAS_FS_ERROR,
649 "Failed to read live tag, errno:%{public}d", errno);
650 CHECK_AND_RETURN_RET_LOG(MediaFileUtils::StartsWith(liveTag, LIVE_TAG), E_INVALID_VALUES, "Invalid live photo");
651
652 int64_t liveSize = atoi(liveTag + LIVE_TAG.length());
653 int64_t imageSize = totalSize - liveSize - LIVE_TAG_LEN - PLAY_INFO_LEN;
654 int64_t extraDataSize = 0;
655 int32_t err = GetExtraDataSize(livePhotoFd, extraDataSize, totalSize - imageSize);
656 CHECK_AND_RETURN_RET_LOG(err == E_OK, E_INVALID_LIVE_PHOTO,
657 "Failed to get size of extra data, err:%{public}" PRId64, extraDataSize);
658 int64_t videoSize = totalSize - imageSize - extraDataSize;
659 CHECK_AND_RETURN_RET_LOG(imageSize > 0 && videoSize > 0, E_INVALID_LIVE_PHOTO,
660 "Failed to check live photo, image size:%{public}" PRId64 "video size:%{public}" PRId64, imageSize, videoSize);
661 off_t offset = 0;
662 bool isSameImagePath = livePhotoPath.compare(movingPhotoImagePath) == 0;
663 string tempImagePath = isSameImagePath ? movingPhotoImagePath + ".temp" : movingPhotoImagePath;
664 CHECK_AND_RETURN_RET_LOG((err = SendLivePhoto(livePhotoFd, tempImagePath, imageSize, offset)) == E_OK, err,
665 "Failed to copy image of live photo");
666 CHECK_AND_RETURN_RET_LOG((err = SendLivePhoto(livePhotoFd, movingPhotoVideoPath, videoSize, offset)) == E_OK, err,
667 "Failed to copy video of live photo");
668 if (!extraDataPath.empty()) {
669 CHECK_AND_RETURN_RET_LOG((err = SendLivePhoto(livePhotoFd, extraDataPath, extraDataSize, offset)) == E_OK, err,
670 "Failed to copy extra data of live photo");
671 }
672 if (isSameImagePath) {
673 err = rename(tempImagePath.c_str(), movingPhotoImagePath.c_str());
674 CHECK_AND_RETURN_RET_LOG(err == E_OK, err, "Failed to rename image:%{public}d, errno:%{public}d", err, errno);
675 }
676 return E_OK;
677 }
678
GetMovingPhotoCoverPosition(const UniqueFd & uniqueFd,const int64_t size,const uint32_t frameIndex,uint64_t & coverPosition,int32_t scene)679 static int32_t GetMovingPhotoCoverPosition(const UniqueFd &uniqueFd, const int64_t size,
680 const uint32_t frameIndex, uint64_t &coverPosition, int32_t scene)
681 {
682 MediaLibraryTracer tracer;
683 tracer.Start("AVMetadataHelper");
684 shared_ptr<AVMetadataHelper> helper = AVMetadataHelperFactory::CreateAVMetadataHelper();
685 if (helper == nullptr) {
686 MEDIA_ERR_LOG("AV metadata helper is null");
687 return E_AVMETADATA;
688 }
689
690 // notify media_service clone event.
691 if (scene == Scene::AV_META_SCENE_CLONE) {
692 helper->SetScene(static_cast<Scene>(scene));
693 }
694 int32_t err = helper->SetSource(uniqueFd.Get(), 0, size, AV_META_USAGE_FRAME_INDEX_CONVERT);
695 tracer.Finish();
696 if (err != 0) {
697 MEDIA_ERR_LOG("SetSource failed for the given fd, err = %{public}d", err);
698 return E_AVMETADATA;
699 }
700
701 tracer.Start("AVMetadataHelper->GetTimeByFrameIndex");
702 err = helper->GetTimeByFrameIndex(frameIndex, coverPosition);
703 tracer.Finish();
704 if (err != 0) {
705 MEDIA_ERR_LOG("Failed to GetTimeByFrameIndex, err = %{public}d", err);
706 return E_AVMETADATA;
707 }
708 return E_OK;
709 }
710
GetCoverPosition(const std::string & videoPath,const uint32_t frameIndex,uint64_t & coverPosition,int32_t scene)711 int32_t MovingPhotoFileUtils::GetCoverPosition(const std::string &videoPath, const uint32_t frameIndex,
712 uint64_t &coverPosition, int32_t scene)
713 {
714 string absVideoPath;
715 if (!PathToRealPath(videoPath, absVideoPath)) {
716 MEDIA_ERR_LOG("Failed to get real path: %{private}s, errno: %{public}d", videoPath.c_str(), errno);
717 return E_HAS_FS_ERROR;
718 }
719
720 UniqueFd uniqueFd(open(absVideoPath.c_str(), O_RDONLY));
721 if (uniqueFd.Get() < 0) {
722 MEDIA_ERR_LOG("Failed to open %{private}s, errno: %{public}d", absVideoPath.c_str(), errno);
723 return E_HAS_FS_ERROR;
724 }
725 struct stat64 st;
726 if (fstat64(uniqueFd.Get(), &st) != 0) {
727 MEDIA_ERR_LOG("Failed to get file state, errno: %{public}d", errno);
728 return E_HAS_FS_ERROR;
729 }
730 return GetMovingPhotoCoverPosition(uniqueFd, st.st_size, frameIndex, coverPosition, scene);
731 }
732
EndsWith(const string & str,const string & endStr)733 bool EndsWith(const string &str, const string &endStr)
734 {
735 if (str.length() < endStr.length()) {
736 return false;
737 }
738 return str.rfind(endStr) == str.length() - endStr.length();
739 }
740
GetVersionAndFrameNum(const string & tag,uint32_t & version,uint32_t & frameIndex,bool & hasCinemagraphInfo)741 int32_t MovingPhotoFileUtils::GetVersionAndFrameNum(const string &tag,
742 uint32_t &version, uint32_t &frameIndex, bool &hasCinemagraphInfo)
743 {
744 static const string VERSION_TAG_REGEX = "^[vV](\\d+)_[fF](\\d+).*";
745 std::regex pattern(VERSION_TAG_REGEX);
746 std::smatch result;
747 if (!std::regex_search(tag, result, pattern)) {
748 MEDIA_WARN_LOG("tag is not standard version tag: %{public}s", tag.c_str());
749 return E_INVALID_VALUES;
750 }
751
752 constexpr int32_t VERSION_POSITION = 1;
753 constexpr int32_t FRAME_INDEX_POSITION = 2;
754 version = static_cast<uint32_t>(atoi(result[VERSION_POSITION].str().c_str()));
755 frameIndex = static_cast<uint32_t>(atoi(result[FRAME_INDEX_POSITION].str().c_str()));
756 size_t blankIndex = tag.find_first_of(' ');
757 string tagTrimmed = tag;
758 if (blankIndex != string::npos) {
759 tagTrimmed = tagTrimmed.substr(0, blankIndex);
760 }
761 hasCinemagraphInfo = EndsWith(tagTrimmed, "_c") || EndsWith(tagTrimmed, "_C");
762 return E_OK;
763 }
764
GetVersionAndFrameNum(int32_t fd,uint32_t & version,uint32_t & frameIndex,bool & hasCinemagraphInfo)765 int32_t MovingPhotoFileUtils::GetVersionAndFrameNum(int32_t fd,
766 uint32_t &version, uint32_t &frameIndex, bool &hasCinemagraphInfo)
767 {
768 CHECK_AND_RETURN_RET_LOG(fd >= 0, E_HAS_FS_ERROR, "Failed to check fd, errno:%{public}d", errno);
769 struct stat64 st;
770 CHECK_AND_RETURN_RET_LOG(fstat64(fd, &st) == 0, E_HAS_FS_ERROR,
771 "Failed to get file state, errno:%{public}d", errno);
772 int64_t totalSize = st.st_size;
773 CHECK_AND_RETURN_RET_LOG(totalSize >= MIN_STANDARD_SIZE, E_INVALID_LIVE_PHOTO,
774 "Failed to fetch version tag, total size is %{public}" PRId64, totalSize);
775
776 char versionTag[VERSION_TAG_LEN + 1] = {0};
777 CHECK_AND_RETURN_RET_LOG(lseek(fd, -MIN_STANDARD_SIZE, SEEK_END) != -1, E_HAS_FS_ERROR,
778 "Failed to lseek version tag, errno:%{public}d", errno);
779 CHECK_AND_RETURN_RET_LOG(read(fd, versionTag, VERSION_TAG_LEN) != -1, E_HAS_FS_ERROR,
780 "Failed to read version tag, errno:%{public}d", errno);
781 return MovingPhotoFileUtils::GetVersionAndFrameNum(versionTag, version, frameIndex, hasCinemagraphInfo);
782 }
783
GetMovingPhotoVideoPath(const string & imagePath,int32_t userId)784 string MovingPhotoFileUtils::GetMovingPhotoVideoPath(const string &imagePath, int32_t userId)
785 {
786 return MediaFileUtils::GetMovingPhotoVideoPath(AppendUserId(imagePath, userId));
787 }
788
GetMovingPhotoExtraDataDir(const string & imagePath,int32_t userId)789 string MovingPhotoFileUtils::GetMovingPhotoExtraDataDir(const string &imagePath, int32_t userId)
790 {
791 if (imagePath.length() < ROOT_MEDIA_DIR.length() || !MediaFileUtils::StartsWith(imagePath, ROOT_MEDIA_DIR)) {
792 return "";
793 }
794 return AppendUserId(MEDIA_EXTRA_DATA_DIR, userId) + imagePath.substr(ROOT_MEDIA_DIR.length());
795 }
796
GetMovingPhotoExtraDataPath(const string & imagePath,int32_t userId)797 string MovingPhotoFileUtils::GetMovingPhotoExtraDataPath(const string &imagePath, int32_t userId)
798 {
799 string parentPath = GetMovingPhotoExtraDataDir(imagePath, userId);
800 if (parentPath.empty()) {
801 return "";
802 }
803 return parentPath + "/extraData";
804 }
805
GetSourceMovingPhotoImagePath(const string & imagePath,int32_t userId)806 string MovingPhotoFileUtils::GetSourceMovingPhotoImagePath(const string& imagePath, int32_t userId)
807 {
808 return GetEditDataSourcePath(imagePath, userId);
809 }
810
GetSourceMovingPhotoVideoPath(const string & imagePath,int32_t userId)811 string MovingPhotoFileUtils::GetSourceMovingPhotoVideoPath(const string& imagePath, int32_t userId)
812 {
813 return GetMovingPhotoVideoPath(GetSourceMovingPhotoImagePath(imagePath, userId));
814 }
815
GetLivePhotoCacheDir(const string & imagePath,int32_t userId)816 string MovingPhotoFileUtils::GetLivePhotoCacheDir(const string &imagePath, int32_t userId)
817 {
818 if (imagePath.length() < ROOT_MEDIA_DIR.length() || !MediaFileUtils::StartsWith(imagePath, ROOT_MEDIA_DIR)) {
819 return "";
820 }
821 return AppendUserId(MEDIA_CACHE_DIR, userId) + imagePath.substr(ROOT_MEDIA_DIR.length());
822 }
823
GetLivePhotoCachePath(const string & imagePath,int32_t userId)824 string MovingPhotoFileUtils::GetLivePhotoCachePath(const string &imagePath, int32_t userId)
825 {
826 string parentPath = GetLivePhotoCacheDir(imagePath, userId);
827 if (parentPath.empty()) {
828 return "";
829 }
830 return parentPath + "/livePhoto." + MediaFileUtils::GetExtensionFromPath(imagePath);
831 }
832
GetSourceLivePhotoCachePath(const string & imagePath,int32_t userId)833 string MovingPhotoFileUtils::GetSourceLivePhotoCachePath(const string& imagePath, int32_t userId)
834 {
835 string parentPath = GetLivePhotoCacheDir(imagePath, userId);
836 if (parentPath.empty()) {
837 return "";
838 }
839 return parentPath + "/sourceLivePhoto." + MediaFileUtils::GetExtensionFromPath(imagePath);
840 }
841
IsMovingPhoto(int32_t subtype,int32_t effectMode,int32_t originalSubtype)842 bool MovingPhotoFileUtils::IsMovingPhoto(int32_t subtype, int32_t effectMode, int32_t originalSubtype)
843 {
844 return subtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) ||
845 effectMode == static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY) ||
846 IsGraffiti(subtype, originalSubtype);
847 }
848
IsGraffiti(int32_t subtype,int32_t originalSubtype)849 bool MovingPhotoFileUtils::IsGraffiti(int32_t subtype, int32_t originalSubtype)
850 {
851 return subtype == static_cast<int32_t>(PhotoSubType::DEFAULT) &&
852 originalSubtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO);
853 }
854
GetMovingPhotoSize(const std::string & imagePath,int32_t userId)855 size_t MovingPhotoFileUtils::GetMovingPhotoSize(const std::string &imagePath, int32_t userId)
856 {
857 string movingPhotoImagePath = AppendUserId(imagePath, userId);
858 string movingPhotoVideoPath = GetMovingPhotoVideoPath(imagePath, userId);
859 string movingPhotoExtraDataPath = GetMovingPhotoExtraDataPath(imagePath, userId);
860 size_t imageSize = 0;
861 size_t videoSize = 0;
862 size_t extraDataSize = 0;
863 (void)MediaFileUtils::GetFileSize(movingPhotoImagePath, imageSize);
864 (void)MediaFileUtils::GetFileSize(movingPhotoVideoPath, videoSize);
865 (void)MediaFileUtils::GetFileSize(movingPhotoExtraDataPath, extraDataSize);
866 return imageSize + videoSize + extraDataSize;
867 }
868 } // namespace OHOS::Media