1 /*
2 * Copyright (C) 2025 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 #include "cover_position_parser.h"
17
18 #include <fcntl.h>
19
20 #include "dfx_utils.h"
21 #include "directory_ex.h"
22 #include "ffrt_inner.h"
23 #include "media_column.h"
24 #include "medialibrary_notify.h"
25 #include "medialibrary_unistore_manager.h"
26 #include "moving_photo_file_utils.h"
27 #include "unique_fd.h"
28 #include "userfile_manager_types.h"
29
30 namespace OHOS {
31 namespace Media {
32 using namespace std;
33 using namespace OHOS::NativeRdb;
34
35 const int32_t MAX_TASK_NUM = 100;
36
GetInstance()37 CoverPositionParser &CoverPositionParser::GetInstance()
38 {
39 static CoverPositionParser instance_;
40 return instance_;
41 }
42
AddTask(const string & path,const string & fileUri)43 bool CoverPositionParser::AddTask(const string &path, const string &fileUri)
44 {
45 lock_guard<mutex> lock(mtx_);
46 if (tasks_.size() >= MAX_TASK_NUM) {
47 MEDIA_INFO_LOG("The max queue length has been reached, ignore current task: %{public}s",
48 DfxUtils::GetSafePath(path).c_str());
49 return false;
50 }
51 tasks_.push(make_pair(path, fileUri));
52 if (tasks_.size() == 1 && !processing_) {
53 MEDIA_DEBUG_LOG("queue has task, start process");
54 processing_ = true;
55 StartTask();
56 }
57 return true;
58 }
59
StartTask()60 void CoverPositionParser::StartTask()
61 {
62 ffrt::submit([this]() { ProcessCoverPosition(); });
63 }
64
ProcessCoverPosition()65 void CoverPositionParser::ProcessCoverPosition()
66 {
67 bool hasTask = true;
68 while (hasTask) {
69 pair<string, string> task = GetNextTask();
70 if (task.first.empty()) {
71 hasTask = false;
72 continue;
73 }
74 UpdateCoverPosition(task.first);
75 SendUpdateNotify(task.second);
76 }
77 }
78
GetNextTask()79 pair<string, string> CoverPositionParser::GetNextTask()
80 {
81 lock_guard<mutex> lock(mtx_);
82 if (tasks_.empty()) {
83 MEDIA_DEBUG_LOG("queue is empty, stop process");
84 processing_ = false;
85 return make_pair("", "");
86 }
87 pair<string, string> task = tasks_.front();
88 tasks_.pop();
89 return task;
90 }
91
UpdateCoverPosition(const string & path)92 void CoverPositionParser::UpdateCoverPosition(const string &path)
93 {
94 string extraDataPath = MovingPhotoFileUtils::GetMovingPhotoExtraDataPath(path);
95 string absExtraDataPath;
96 if (!PathToRealPath(extraDataPath, absExtraDataPath)) {
97 MEDIA_ERR_LOG("realpath fail: %{public}s, errno: %{public}d", DfxUtils::GetSafePath(extraDataPath).c_str(),
98 errno);
99 return;
100 }
101
102 uint64_t coverPosition = 0;
103 uint32_t version = 0;
104 uint32_t frameIndex = 0;
105 bool hasCinemagraphInfo = false;
106 UniqueFd extraDataFd(open(absExtraDataPath.c_str(), O_RDONLY));
107 (void)MovingPhotoFileUtils::GetVersionAndFrameNum(extraDataFd.Get(), version, frameIndex, hasCinemagraphInfo);
108 if (frameIndex != 0) {
109 string videoPath = MovingPhotoFileUtils::GetMovingPhotoVideoPath(path);
110 (void)MovingPhotoFileUtils::GetCoverPosition(videoPath, frameIndex, coverPosition);
111 }
112
113 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
114 CHECK_AND_RETURN_LOG(rdbStore != nullptr, "rdbStore is nullptr!");
115
116 AbsRdbPredicates predicates = AbsRdbPredicates(PhotoColumn::PHOTOS_TABLE);
117 predicates.EqualTo(PhotoColumn::MEDIA_FILE_PATH, path);
118 ValuesBucket values;
119 values.PutLong(PhotoColumn::PHOTO_COVER_POSITION, coverPosition);
120 values.PutInt(PhotoColumn::PHOTO_IS_RECTIFICATION_COVER, 1);
121
122 int32_t changeRows = -1;
123 int32_t ret = rdbStore->Update(changeRows, values, predicates);
124 CHECK_AND_PRINT_LOG(ret == E_OK, "execute update cover_position failed, ret = %{public}d", ret);
125 }
126
SendUpdateNotify(const string & fileUri)127 void CoverPositionParser::SendUpdateNotify(const string &fileUri)
128 {
129 auto watch = MediaLibraryNotify::GetInstance();
130 if (watch == nullptr) {
131 MEDIA_ERR_LOG("Can not get MediaLibraryNotify, fail to send new asset notify.");
132 return;
133 }
134 watch->Notify(fileUri, NotifyType::NOTIFY_UPDATE);
135 }
136 } // namespace Media
137 } // namespace OHOS