1 /*
2 * Copyright (C) 2022-2023 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 #define MLOG_TAG "Thumbnail"
16
17 #include "ithumbnail_helper.h"
18
19 #include "ability_manager_client.h"
20 #include "hitrace_meter.h"
21 #include "media_column.h"
22 #include "medialibrary_errno.h"
23 #include "media_file_utils.h"
24 #include "media_log.h"
25 #include "rdb_helper.h"
26 #include "single_kvstore.h"
27 #include "thumbnail_const.h"
28
29 using namespace std;
30 using namespace OHOS::DistributedKv;
31 using namespace OHOS::NativeRdb;
32
33 namespace OHOS {
34 namespace Media {
GetThumbnailInfo(ThumbRdbOpt & opts,ThumbnailData & outData)35 void IThumbnailHelper::GetThumbnailInfo(ThumbRdbOpt &opts, ThumbnailData &outData)
36 {
37 if (opts.store == nullptr) {
38 return;
39 }
40 if (!opts.path.empty()) {
41 outData.path = opts.path;
42 outData.id = opts.row;
43 return;
44 }
45 string filesTableName = opts.table;
46 int errCode = E_ERR;
47 if (!opts.networkId.empty()) {
48 filesTableName = opts.store->ObtainDistributedTableName(opts.networkId, opts.table, errCode);
49 }
50 if (filesTableName.empty()) {
51 return;
52 }
53 opts.table = filesTableName;
54 int err;
55 ThumbnailUtils::QueryThumbnailInfo(opts, outData, err);
56 if (err != E_OK) {
57 MEDIA_ERR_LOG("query fail [%{public}d]", err);
58 }
59 return;
60 }
61
CreateLcd(AsyncTaskData * data)62 void IThumbnailHelper::CreateLcd(AsyncTaskData* data)
63 {
64 GenerateAsyncTaskData* taskData = static_cast<GenerateAsyncTaskData*>(data);
65 DoCreateLcd(taskData->opts, taskData->thumbnailData);
66 }
67
CreateThumbnail(AsyncTaskData * data)68 void IThumbnailHelper::CreateThumbnail(AsyncTaskData* data)
69 {
70 GenerateAsyncTaskData* taskData = static_cast<GenerateAsyncTaskData*>(data);
71 DoCreateThumbnail(taskData->opts, taskData->thumbnailData);
72 }
73
AddAsyncTask(MediaLibraryExecute executor,ThumbRdbOpt & opts,ThumbnailData & data,bool isFront)74 void IThumbnailHelper::AddAsyncTask(MediaLibraryExecute executor, ThumbRdbOpt &opts, ThumbnailData &data, bool isFront)
75 {
76 shared_ptr<MediaLibraryAsyncWorker> asyncWorker = MediaLibraryAsyncWorker::GetInstance();
77 if (asyncWorker == nullptr) {
78 MEDIA_DEBUG_LOG("IThumbnailHelper::AddAsyncTask asyncWorker is null");
79 return;
80 }
81 GenerateAsyncTaskData* taskData = new (nothrow)GenerateAsyncTaskData();
82 if (taskData == nullptr) {
83 MEDIA_DEBUG_LOG("IThumbnailHelper::GenerateAsyncTaskData taskData is null");
84 return;
85 }
86 taskData->opts = opts;
87 taskData->thumbnailData = data;
88
89 shared_ptr<MediaLibraryAsyncTask> generateAsyncTask = make_shared<MediaLibraryAsyncTask>(executor, taskData);
90 asyncWorker->AddTask(generateAsyncTask, isFront);
91 }
92
ThumbnailWait(bool release)93 ThumbnailWait::ThumbnailWait(bool release) : needRelease_(release)
94 {}
95
~ThumbnailWait()96 ThumbnailWait::~ThumbnailWait()
97 {
98 if (needRelease_) {
99 Notify();
100 }
101 }
102
103 ThumbnailMap ThumbnailWait::thumbnailMap_;
104 std::shared_mutex ThumbnailWait::mutex_;
105
WaitFor(const shared_ptr<SyncStatus> & thumbnailWait,int waitMs,unique_lock<mutex> & lck)106 static bool WaitFor(const shared_ptr<SyncStatus>& thumbnailWait, int waitMs, unique_lock<mutex> &lck)
107 {
108 bool ret = thumbnailWait->cond_.wait_for(lck, chrono::milliseconds(waitMs),
109 [thumbnailWait]() { return thumbnailWait->isSyncComplete_; });
110 if (!ret) {
111 MEDIA_INFO_LOG("IThumbnailHelper::Wait wait for lock timeout");
112 }
113 return ret;
114 }
115
InsertAndWait(const string & id,bool isLcd)116 WaitStatus ThumbnailWait::InsertAndWait(const string &id, bool isLcd)
117 {
118 id_ = id;
119
120 if (isLcd) {
121 id_ += THUMBNAIL_LCD_SUFFIX;
122 } else {
123 id_ += THUMBNAIL_THUMB_SUFFIX;
124 }
125 unique_lock<shared_mutex> writeLck(mutex_);
126 auto iter = thumbnailMap_.find(id_);
127 if (iter != thumbnailMap_.end()) {
128 auto thumbnailWait = iter->second;
129 unique_lock<mutex> lck(thumbnailWait->mtx_);
130 writeLck.unlock();
131 bool ret = WaitFor(thumbnailWait, WAIT_FOR_MS, lck);
132 if (ret) {
133 return WaitStatus::WAIT_SUCCESS;
134 } else {
135 return WaitStatus::TIMEOUT;
136 }
137 } else {
138 shared_ptr<SyncStatus> thumbnailWait = make_shared<SyncStatus>();
139 thumbnailMap_.insert(ThumbnailMap::value_type(id_, thumbnailWait));
140 return WaitStatus::INSERT;
141 }
142 }
143
CheckAndWait(const string & id,bool isLcd)144 void ThumbnailWait::CheckAndWait(const string &id, bool isLcd)
145 {
146 id_ = id;
147
148 if (isLcd) {
149 id_ += THUMBNAIL_LCD_SUFFIX;
150 } else {
151 id_ += THUMBNAIL_THUMB_SUFFIX;
152 }
153 shared_lock<shared_mutex> readLck(mutex_);
154 auto iter = thumbnailMap_.find(id_);
155 if (iter != thumbnailMap_.end()) {
156 auto thumbnailWait = iter->second;
157 unique_lock<mutex> lck(thumbnailWait->mtx_);
158 readLck.unlock();
159 WaitFor(thumbnailWait, WAIT_FOR_MS, lck);
160 }
161 }
162
Notify()163 void ThumbnailWait::Notify()
164 {
165 unique_lock<shared_mutex> writeLck(mutex_);
166 auto iter = thumbnailMap_.find(id_);
167 if (iter != thumbnailMap_.end()) {
168 auto thumbnailWait = iter->second;
169 thumbnailMap_.erase(iter);
170 {
171 unique_lock<mutex> lck(thumbnailWait->mtx_);
172 writeLck.unlock();
173 thumbnailWait->isSyncComplete_ = true;
174 }
175 thumbnailWait->cond_.notify_all();
176 }
177 }
178
TryLoadSource(ThumbRdbOpt & opts,ThumbnailData & data,const Size & size,const string & suffix)179 bool IThumbnailHelper::TryLoadSource(ThumbRdbOpt &opts, ThumbnailData &data, const Size &size, const string &suffix)
180 {
181 if (!ThumbnailUtils::LoadSourceImage(data, size, suffix == THUMBNAIL_THUMB_SUFFIX)) {
182 if (opts.path.empty()) {
183 MEDIA_ERR_LOG("LoadSourceImage faild, %{private}s", data.path.c_str());
184 return false;
185 } else {
186 opts.path = "";
187 GetThumbnailInfo(opts, data);
188 string fileName = GetThumbnailPath(data.path, suffix);
189 if (access(fileName.c_str(), F_OK) == 0) {
190 return true;
191 }
192 if (!ThumbnailUtils::LoadSourceImage(data, size, suffix == THUMBNAIL_THUMB_SUFFIX)) {
193 return false;
194 }
195 }
196 }
197 return true;
198 }
199
200
DoCreateLcd(ThumbRdbOpt & opts,ThumbnailData & data)201 bool IThumbnailHelper::DoCreateLcd(ThumbRdbOpt &opts, ThumbnailData &data)
202 {
203 ThumbnailWait thumbnailWait(true);
204 auto ret = thumbnailWait.InsertAndWait(data.id, true);
205 if (ret == WaitStatus::WAIT_SUCCESS) {
206 return true;
207 }
208
209 if (!TryLoadSource(opts, data, opts.screenSize, THUMBNAIL_LCD_SUFFIX)) {
210 return false;
211 }
212
213 if (!ThumbnailUtils::CompressImage(data.source, data.lcd)) {
214 MEDIA_ERR_LOG("CompressImage faild");
215 return false;
216 }
217
218 int err = ThumbnailUtils::TrySaveFile(data, ThumbnailType::LCD);
219 if (err < 0) {
220 MEDIA_ERR_LOG("SaveLcd faild %{public}d", err);
221 return false;
222 }
223
224 data.lcd.clear();
225 if (!ThumbnailUtils::UpdateLcdInfo(opts, data, err)) {
226 MEDIA_INFO_LOG("UpdateLcdInfo faild err : %{public}d", err);
227 return false;
228 }
229
230 return true;
231 }
232
GenThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,const ThumbnailType type)233 bool IThumbnailHelper::GenThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, const ThumbnailType type)
234 {
235 bool isThumb = false;
236 if (type == ThumbnailType::THUMB) {
237 isThumb = true;
238 }
239 Size size;
240 if (isThumb) {
241 size = { DEFAULT_THUMB_SIZE, DEFAULT_THUMB_SIZE };
242 if (!TryLoadSource(opts, data, size, THUMBNAIL_THUMB_SUFFIX)) {
243 return false;
244 }
245 if (!ThumbnailUtils::CompressImage(data.source, data.thumbnail)) {
246 MEDIA_ERR_LOG("CompressImage faild id %{private}s", opts.row.c_str());
247 return false;
248 }
249 } else {
250 if (type == ThumbnailType::MTH) {
251 size = {DEFAULT_MTH_SIZE, DEFAULT_MTH_SIZE };
252 } else {
253 size = { DEFAULT_YEAR_SIZE, DEFAULT_YEAR_SIZE };
254 }
255 ThumbnailUtils::GenTargetPixelmap(data, size);
256 }
257
258 int err = ThumbnailUtils::TrySaveFile(data, type);
259 if (err < 0) {
260 MEDIA_ERR_LOG("SaveThumbnailData faild %{public}d", err);
261 return false;
262 }
263 data.thumbnail.clear();
264 return true;
265 }
266
DoCreateThumbnail(ThumbRdbOpt & opts,ThumbnailData & data)267 bool IThumbnailHelper::DoCreateThumbnail(ThumbRdbOpt &opts, ThumbnailData &data)
268 {
269 ThumbnailWait thumbnailWait(true);
270 auto ret = thumbnailWait.InsertAndWait(data.id, false);
271 if (ret == WaitStatus::WAIT_SUCCESS) {
272 return true;
273 }
274
275 if (!GenThumbnail(opts, data, ThumbnailType::THUMB)) {
276 return false;
277 }
278 if (!GenThumbnail(opts, data, ThumbnailType::MTH)) {
279 return false;
280 }
281 if (!GenThumbnail(opts, data, ThumbnailType::YEAR)) {
282 return false;
283 }
284 return true;
285 }
286 } // namespace Media
287 } // namespace OHOS