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