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 "thumbnail_utils.h"
18
19 #include <fcntl.h>
20 #include <malloc.h>
21 #include <sys/stat.h>
22
23 #include "cloud_sync_helper.h"
24 #include "datashare_abs_result_set.h"
25 #ifdef DISTRIBUTED
26 #include "device_manager.h"
27 #endif
28 #include "distributed_kv_data_manager.h"
29 #include "hitrace_meter.h"
30 #include "image_packer.h"
31 #include "medialibrary_common_utils.h"
32 #include "medialibrary_errno.h"
33 #include "medialibrary_sync_operation.h"
34 #include "medialibrary_tracer.h"
35 #include "media_file_utils.h"
36 #include "media_log.h"
37 #include "mimetype_utils.h"
38 #include "parameter.h"
39 #include "post_proc.h"
40 #include "rdb_errno.h"
41 #include "rdb_predicates.h"
42 #include "thumbnail_const.h"
43 #include "unique_fd.h"
44
45 using namespace std;
46 using namespace OHOS::DistributedKv;
47 using namespace OHOS::NativeRdb;
48
49 namespace OHOS {
50 namespace Media {
51 constexpr int32_t KEY_INDEX = 0;
52 constexpr int32_t VALUE_INDEX = 1;
53 constexpr float EPSILON = 1e-6;
UpdateRemotePath(string & path,const string & networkId)54 bool ThumbnailUtils::UpdateRemotePath(string &path, const string &networkId)
55 {
56 MEDIA_DEBUG_LOG("ThumbnailUtils::UpdateRemotePath IN path = %{private}s, networkId = %{private}s",
57 path.c_str(), networkId.c_str());
58 if (path.empty() || networkId.empty()) {
59 return false;
60 }
61
62 size_t pos = path.find(MEDIA_DATA_DEVICE_PATH);
63 if (pos == string::npos) {
64 return false;
65 }
66
67 path.replace(pos, MEDIA_DATA_DEVICE_PATH.size(), networkId);
68 return true;
69 }
70
71 #ifdef DISTRIBUTED
DeleteLcdData(ThumbRdbOpt & opts,ThumbnailData & thumbnailData)72 bool ThumbnailUtils::DeleteLcdData(ThumbRdbOpt &opts, ThumbnailData &thumbnailData)
73 {
74 if (thumbnailData.lcdKey.empty()) {
75 MEDIA_ERR_LOG("lcd Key is empty");
76 return false;
77 }
78
79 if (IsImageExist(thumbnailData.lcdKey, opts.networkId, opts.kvStore)) {
80 if (!RemoveDataFromKv(opts.kvStore, thumbnailData.lcdKey)) {
81 MEDIA_ERR_LOG("ThumbnailUtils::RemoveDataFromKv faild");
82 return false;
83 }
84 if (!CleanThumbnailInfo(opts, false, true)) {
85 return false;
86 }
87 }
88
89 return true;
90 }
91
DeleteDistributeLcdData(ThumbRdbOpt & opts,ThumbnailData & thumbnailData)92 bool ThumbnailUtils::DeleteDistributeLcdData(ThumbRdbOpt &opts, ThumbnailData &thumbnailData)
93 {
94 if (thumbnailData.lcdKey.empty()) {
95 MEDIA_ERR_LOG("lcd Key is empty");
96 return false;
97 }
98
99 if (IsImageExist(thumbnailData.lcdKey, opts.networkId, opts.kvStore)) {
100 if (!RemoveDataFromKv(opts.kvStore, thumbnailData.lcdKey)) {
101 MEDIA_ERR_LOG("ThumbnailUtils::RemoveDataFromKv faild");
102 return false;
103 }
104 if (!CleanDistributeLcdInfo(opts)) {
105 return false;
106 }
107 }
108
109 return true;
110 }
111 #endif
112
GetThumbnailSuffix(ThumbnailType type)113 static string GetThumbnailSuffix(ThumbnailType type)
114 {
115 string suffix;
116 switch (type) {
117 case ThumbnailType::YEAR:
118 suffix = THUMBNAIL_YEAR_SUFFIX;
119 break;
120 case ThumbnailType::MTH:
121 suffix = THUMBNAIL_MTH_SUFFIX;
122 break;
123 case ThumbnailType::THUMB:
124 suffix = THUMBNAIL_THUMB_SUFFIX;
125 break;
126 case ThumbnailType::LCD:
127 suffix = THUMBNAIL_LCD_SUFFIX;
128 break;
129 default:
130 return "";
131 }
132 return suffix;
133 }
134
DeleteThumbFile(ThumbnailData & data,ThumbnailType type)135 bool ThumbnailUtils::DeleteThumbFile(ThumbnailData &data, ThumbnailType type)
136 {
137 string fileName = GetThumbnailPath(data.path, GetThumbnailSuffix(type));
138 if (!MediaFileUtils::DeleteFile(fileName)) {
139 MEDIA_ERR_LOG("delete file faild %{public}d", errno);
140 return false;
141 }
142 return true;
143 }
144
LoadAudioFile(ThumbnailData & data,const bool isThumbnail,const Size & desiredSize)145 bool ThumbnailUtils::LoadAudioFile(ThumbnailData &data, const bool isThumbnail, const Size &desiredSize)
146 {
147 shared_ptr<AVMetadataHelper> avMetadataHelper = AVMetadataHelperFactory::CreateAVMetadataHelper();
148 string path = data.path;
149 int32_t err = SetSource(avMetadataHelper, path);
150 if (err != E_OK) {
151 MEDIA_ERR_LOG("Av meta data helper set source failed %{public}d", err);
152 return false;
153 }
154
155 auto audioPicMemory = avMetadataHelper->FetchArtPicture();
156 if (audioPicMemory == nullptr) {
157 MEDIA_ERR_LOG("FetchArtPicture failed!");
158 return false;
159 }
160
161 SourceOptions opts;
162 uint32_t errCode = 0;
163 unique_ptr<ImageSource> audioImageSource = ImageSource::CreateImageSource(audioPicMemory->GetBase(),
164 audioPicMemory->GetSize(), opts, errCode);
165 if (audioImageSource == nullptr) {
166 MEDIA_ERR_LOG("Failed to create image source! path %{private}s errCode %{public}d",
167 path.c_str(), errCode);
168 return false;
169 }
170
171 ImageInfo imageInfo;
172 errCode = audioImageSource->GetImageInfo(0, imageInfo);
173 if (errCode != E_OK) {
174 MEDIA_ERR_LOG("Failed to get image info, path: %{private}s err: %{public}d", path.c_str(), errCode);
175 return false;
176 }
177
178 DecodeOptions decOpts;
179 decOpts.desiredSize = ConvertDecodeSize(imageInfo.size, desiredSize, isThumbnail);
180 decOpts.desiredPixelFormat = PixelFormat::BGRA_8888;
181 data.source = audioImageSource->CreatePixelMap(decOpts, errCode);
182 if ((errCode != E_OK) || (data.source == nullptr)) {
183 MEDIA_ERR_LOG("Av meta data helper fetch frame at time failed");
184 return false;
185 }
186 return true;
187 }
188
LoadVideoFile(ThumbnailData & data,const bool isThumbnail,const Size & desiredSize)189 bool ThumbnailUtils::LoadVideoFile(ThumbnailData &data, const bool isThumbnail, const Size &desiredSize)
190 {
191 shared_ptr<AVMetadataHelper> avMetadataHelper = AVMetadataHelperFactory::CreateAVMetadataHelper();
192 string path = data.path;
193 int32_t err = SetSource(avMetadataHelper, path);
194 if (err != 0) {
195 MEDIA_ERR_LOG("Av meta data helper set source failed path %{private}s err %{public}d",
196 path.c_str(), err);
197 return false;
198 }
199 PixelMapParams param;
200 param.colorFormat = PixelFormat::RGBA_8888;
201 data.source = avMetadataHelper->FetchFrameAtTime(AV_FRAME_TIME, AVMetadataQueryOption::AV_META_QUERY_NEXT_SYNC,
202 param);
203 if (data.source == nullptr) {
204 MEDIA_ERR_LOG("Av meta data helper fetch frame at time failed");
205 return false;
206 }
207
208 auto resultMap = avMetadataHelper->ResolveMetadata();
209 string videoOrientation = resultMap.at(AV_KEY_VIDEO_ORIENTATION);
210 if (!videoOrientation.empty()) {
211 std::istringstream iss(videoOrientation);
212 iss >> data.degrees;
213 }
214 return true;
215 }
216
217 // gen pixelmap from data.souce, should ensure source is not null
GenTargetPixelmap(ThumbnailData & data,const Size & desiredSize)218 bool ThumbnailUtils::GenTargetPixelmap(ThumbnailData &data, const Size &desiredSize)
219 {
220 MediaLibraryTracer tracer;
221 tracer.Start("GenTargetPixelmap");
222 if (data.source == nullptr) {
223 return false;
224 }
225 float widthScale = (1.0f * desiredSize.width) / data.source->GetWidth();
226 float heightScale = (1.0f * desiredSize.height) / data.source->GetHeight();
227 data.source->scale(widthScale, heightScale);
228 return true;
229 }
230
LoadImageFile(ThumbnailData & data,const bool isThumbnail,const Size & desiredSize)231 bool ThumbnailUtils::LoadImageFile(ThumbnailData &data, const bool isThumbnail, const Size &desiredSize)
232 {
233 mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
234 mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
235
236 MediaLibraryTracer tracer;
237 tracer.Start("ImageSource::CreateImageSource");
238
239 uint32_t err = 0;
240 SourceOptions opts;
241 string path = data.path;
242 unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(path, opts, err);
243 if (err != E_OK) {
244 MEDIA_ERR_LOG("Failed to create image source, path: %{private}s err: %{public}d", path.c_str(), err);
245 return false;
246 }
247 tracer.Finish();
248
249 tracer.Start("imageSource->CreatePixelMap");
250 ImageInfo imageInfo;
251 err = imageSource->GetImageInfo(0, imageInfo);
252 if (err != E_OK) {
253 MEDIA_ERR_LOG("Failed to get image info, path: %{private}s err: %{public}d", path.c_str(), err);
254 return false;
255 }
256
257 DecodeOptions decodeOpts;
258 decodeOpts.desiredSize = ConvertDecodeSize(imageInfo.size, desiredSize, isThumbnail);
259 decodeOpts.desiredPixelFormat = PixelFormat::BGRA_8888;
260 data.source = imageSource->CreatePixelMap(decodeOpts, err);
261 if ((err != E_OK) || (data.source == nullptr)) {
262 MEDIA_ERR_LOG("Failed to create pixelmap path %{private}s err %{public}d",
263 path.c_str(), err);
264 return false;
265 }
266 tracer.Finish();
267
268 int intTempMeta;
269 err = imageSource->GetImagePropertyInt(0, MEDIA_DATA_IMAGE_ORIENTATION, intTempMeta);
270 if (err == E_OK) {
271 data.degrees = static_cast<float>(intTempMeta);
272 }
273 return true;
274 }
275
GetUdid()276 string ThumbnailUtils::GetUdid()
277 {
278 #ifdef DISTRIBUTED
279 static string innerUdid;
280
281 if (!innerUdid.empty()) {
282 return innerUdid;
283 }
284
285 auto &deviceManager = OHOS::DistributedHardware::DeviceManager::GetInstance();
286 OHOS::DistributedHardware::DmDeviceInfo deviceInfo;
287 auto ret = deviceManager.GetLocalDeviceInfo(BUNDLE_NAME, deviceInfo);
288 if (ret != ERR_OK) {
289 MEDIA_ERR_LOG("get local device info failed, ret %{public}d", ret);
290 return string();
291 }
292
293 ret = deviceManager.GetUdidByNetworkId(BUNDLE_NAME, deviceInfo.networkId, innerUdid);
294 if (ret != 0) {
295 MEDIA_ERR_LOG("GetDeviceUdid error networkId = %{private}s, ret %{public}d",
296 deviceInfo.networkId, ret);
297 return string();
298 }
299 return innerUdid;
300 #endif
301 return "";
302 }
303
CompressImage(shared_ptr<PixelMap> & pixelMap,vector<uint8_t> & data)304 bool ThumbnailUtils::CompressImage(shared_ptr<PixelMap> &pixelMap, vector<uint8_t> &data)
305 {
306 PackOption option = {
307 .format = THUMBNAIL_FORMAT,
308 .quality = THUMBNAIL_QUALITY,
309 .numberHint = NUMBER_HINT_1
310 };
311 data.resize(pixelMap->GetByteCount());
312
313 MediaLibraryTracer tracer;
314 tracer.Start("imagePacker.StartPacking");
315 ImagePacker imagePacker;
316 uint32_t err = imagePacker.StartPacking(data.data(), data.size(), option);
317 tracer.Finish();
318 if (err != E_OK) {
319 MEDIA_ERR_LOG("Failed to StartPacking %{public}d", err);
320 return false;
321 }
322
323 tracer.Start("imagePacker.AddImage");
324 err = imagePacker.AddImage(*pixelMap);
325 tracer.Finish();
326 if (err != E_OK) {
327 MEDIA_ERR_LOG("Failed to StartPacking %{public}d", err);
328 return false;
329 }
330
331 tracer.Start("imagePacker.FinalizePacking");
332 int64_t packedSize = 0;
333 err = imagePacker.FinalizePacking(packedSize);
334 if (err != E_OK) {
335 MEDIA_ERR_LOG("Failed to StartPacking %{public}d", err);
336 return false;
337 }
338
339 data.resize(packedSize);
340 return true;
341 }
342
SaveImage(const shared_ptr<SingleKvStore> & kvStore,const string & key,const vector<uint8_t> & image)343 Status ThumbnailUtils::SaveImage(const shared_ptr<SingleKvStore> &kvStore, const string &key,
344 const vector<uint8_t> &image)
345 {
346 MEDIA_DEBUG_LOG("ThumbnailUtils::SaveImage IN key [%{public}s]", key.c_str());
347 Status status = Status::ERROR;
348 if (kvStore == nullptr) {
349 MEDIA_ERR_LOG("KvStore is not init");
350 return status;
351 }
352
353 MediaLibraryTracer tracer;
354 tracer.Start("SaveImage kvStore->Put");
355 Value val(image);
356 status = kvStore->Put(key, val);
357 return status;
358 }
359
QueryThumbnailSet(ThumbRdbOpt & opts)360 shared_ptr<ResultSet> ThumbnailUtils::QueryThumbnailSet(ThumbRdbOpt &opts)
361 {
362 vector<string> column = {
363 MEDIA_DATA_DB_ID,
364 MEDIA_DATA_DB_FILE_PATH,
365 MEDIA_DATA_DB_MEDIA_TYPE,
366 };
367
368 vector<string> selectionArgs;
369 string strQueryCondition = MEDIA_DATA_DB_ID + " = " + opts.row;
370
371 RdbPredicates rdbPredicates(opts.table);
372 rdbPredicates.SetWhereClause(strQueryCondition);
373 rdbPredicates.SetWhereArgs(selectionArgs);
374 return opts.store->QueryByStep(rdbPredicates, column);
375 }
376
QueryThumbnailInfo(ThumbRdbOpt & opts,ThumbnailData & data,int & err)377 shared_ptr<ResultSet> ThumbnailUtils::QueryThumbnailInfo(ThumbRdbOpt &opts,
378 ThumbnailData &data, int &err)
379 {
380 MediaLibraryTracer tracer;
381 tracer.Start("QueryThumbnailInfo");
382 auto resultSet = QueryThumbnailSet(opts);
383 if (!CheckResultSetCount(resultSet, err)) {
384 return nullptr;
385 }
386
387 err = resultSet->GoToFirstRow();
388 if (err != E_OK) {
389 return nullptr;
390 }
391
392 ParseQueryResult(resultSet, data, err);
393 return resultSet;
394 }
395
QueryLcdCount(ThumbRdbOpt & opts,int & outLcdCount,int & err)396 bool ThumbnailUtils::QueryLcdCount(ThumbRdbOpt &opts, int &outLcdCount, int &err)
397 {
398 vector<string> column = {
399 MEDIA_DATA_DB_ID,
400 };
401 RdbPredicates rdbPredicates(opts.table);
402 rdbPredicates.NotEqualTo(MEDIA_DATA_DB_TIME_VISIT, "0");
403 rdbPredicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, to_string(MEDIA_TYPE_FILE));
404 rdbPredicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, to_string(MEDIA_TYPE_ALBUM));
405 auto resultSet = opts.store->QueryByStep(rdbPredicates, column);
406 if (resultSet == nullptr) {
407 return false;
408 }
409 int rowCount = 0;
410 err = resultSet->GetRowCount(rowCount);
411 resultSet.reset();
412 if (err != E_OK) {
413 MEDIA_ERR_LOG("Failed to get row count %{public}d", err);
414 return false;
415 }
416 MEDIA_DEBUG_LOG("rowCount is %{public}d", rowCount);
417 if (rowCount <= 0) {
418 MEDIA_INFO_LOG("No match! %{public}s", rdbPredicates.ToString().c_str());
419 rowCount = 0;
420 }
421
422 outLcdCount = rowCount;
423 return true;
424 }
425
QueryDistributeLcdCount(ThumbRdbOpt & opts,int & outLcdCount,int & err)426 bool ThumbnailUtils::QueryDistributeLcdCount(ThumbRdbOpt &opts, int &outLcdCount, int &err)
427 {
428 vector<string> column = {
429 REMOTE_THUMBNAIL_DB_ID,
430 };
431 RdbPredicates rdbPredicates(REMOTE_THUMBNAIL_TABLE);
432 rdbPredicates.EqualTo(REMOTE_THUMBNAIL_DB_UDID, opts.udid);
433 rdbPredicates.IsNotNull(MEDIA_DATA_DB_LCD);
434 auto resultSet = opts.store->QueryByStep(rdbPredicates, column);
435 if (resultSet == nullptr) {
436 return false;
437 }
438 int rowCount = 0;
439 err = resultSet->GetRowCount(rowCount);
440 resultSet.reset();
441 if (err != E_OK) {
442 MEDIA_ERR_LOG("Failed to get row count %{public}d", err);
443 return false;
444 }
445 MEDIA_INFO_LOG("rowCount is %{public}d", rowCount);
446 if (rowCount <= 0) {
447 MEDIA_INFO_LOG("No match! %{public}s", rdbPredicates.ToString().c_str());
448 rowCount = 0;
449 }
450 outLcdCount = rowCount;
451 return true;
452 }
453
QueryHasLcdFiles(ThumbRdbOpt & opts,vector<ThumbnailData> & infos,int & err)454 bool ThumbnailUtils::QueryHasLcdFiles(ThumbRdbOpt &opts, vector<ThumbnailData> &infos, int &err)
455 {
456 vector<string> column = {
457 MEDIA_DATA_DB_ID,
458 MEDIA_DATA_DB_FILE_PATH,
459 MEDIA_DATA_DB_THUMBNAIL,
460 MEDIA_DATA_DB_LCD,
461 MEDIA_DATA_DB_MEDIA_TYPE,
462 MEDIA_DATA_DB_DATE_MODIFIED
463 };
464 RdbPredicates rdbPredicates(opts.table);
465 rdbPredicates.IsNotNull(MEDIA_DATA_DB_LCD);
466 shared_ptr<ResultSet> resultSet = opts.store->QueryByStep(rdbPredicates, column);
467 if (!CheckResultSetCount(resultSet, err)) {
468 MEDIA_ERR_LOG("CheckResultSetCount failed %{public}d", err);
469 return false;
470 }
471
472 err = resultSet->GoToFirstRow();
473 if (err != E_OK) {
474 MEDIA_ERR_LOG("Failed GoToFirstRow %{public}d", err);
475 return false;
476 }
477
478 ThumbnailData data;
479 do {
480 ParseQueryResult(resultSet, data, err);
481 if (!data.path.empty()) {
482 infos.push_back(data);
483 }
484 } while (resultSet->GoToNextRow() == E_OK);
485 return true;
486 }
487
QueryHasThumbnailFiles(ThumbRdbOpt & opts,vector<ThumbnailData> & infos,int & err)488 bool ThumbnailUtils::QueryHasThumbnailFiles(ThumbRdbOpt &opts, vector<ThumbnailData> &infos, int &err)
489 {
490 vector<string> column = {
491 MEDIA_DATA_DB_ID,
492 MEDIA_DATA_DB_FILE_PATH,
493 MEDIA_DATA_DB_THUMBNAIL,
494 MEDIA_DATA_DB_LCD,
495 MEDIA_DATA_DB_MEDIA_TYPE,
496 MEDIA_DATA_DB_DATE_MODIFIED
497 };
498 RdbPredicates rdbPredicates(opts.table);
499 rdbPredicates.IsNotNull(MEDIA_DATA_DB_THUMBNAIL);
500 shared_ptr<ResultSet> resultSet = opts.store->QueryByStep(rdbPredicates, column);
501 if (!CheckResultSetCount(resultSet, err)) {
502 MEDIA_ERR_LOG("CheckResultSetCount failed %{public}d", err);
503 return false;
504 }
505
506 err = resultSet->GoToFirstRow();
507 if (err != E_OK) {
508 MEDIA_ERR_LOG("Failed GoToFirstRow %{public}d", err);
509 return false;
510 }
511
512 ThumbnailData data;
513 do {
514 ParseQueryResult(resultSet, data, err);
515 if (!data.path.empty()) {
516 infos.push_back(data);
517 }
518 } while (resultSet->GoToNextRow() == E_OK);
519 return true;
520 }
521
QueryAgingDistributeLcdInfos(ThumbRdbOpt & opts,int LcdLimit,vector<ThumbnailData> & infos,int & err)522 bool ThumbnailUtils::QueryAgingDistributeLcdInfos(ThumbRdbOpt &opts, int LcdLimit,
523 vector<ThumbnailData> &infos, int &err)
524 {
525 vector<string> column = {
526 REMOTE_THUMBNAIL_DB_FILE_ID,
527 MEDIA_DATA_DB_LCD
528 };
529 RdbPredicates rdbPredicates(REMOTE_THUMBNAIL_TABLE);
530 rdbPredicates.IsNotNull(MEDIA_DATA_DB_LCD);
531 rdbPredicates.EqualTo(REMOTE_THUMBNAIL_DB_UDID, opts.udid);
532
533 rdbPredicates.Limit(LcdLimit);
534 rdbPredicates.OrderByAsc(MEDIA_DATA_DB_TIME_VISIT);
535 shared_ptr<ResultSet> resultSet = opts.store->QueryByStep(rdbPredicates, column);
536 if (!CheckResultSetCount(resultSet, err)) {
537 MEDIA_ERR_LOG("CheckResultSetCount failed %{public}d", err);
538 return false;
539 }
540
541 err = resultSet->GoToFirstRow();
542 if (err != E_OK) {
543 MEDIA_ERR_LOG("Failed GoToFirstRow %{public}d", err);
544 return false;
545 }
546
547 ThumbnailData data;
548 do {
549 ParseQueryResult(resultSet, data, err);
550 if (!data.lcdKey.empty()) {
551 infos.push_back(data);
552 }
553 } while (resultSet->GoToNextRow() == E_OK);
554 return true;
555 }
556
QueryAgingLcdInfos(ThumbRdbOpt & opts,int LcdLimit,vector<ThumbnailData> & infos,int & err)557 bool ThumbnailUtils::QueryAgingLcdInfos(ThumbRdbOpt &opts, int LcdLimit,
558 vector<ThumbnailData> &infos, int &err)
559 {
560 vector<string> column = {
561 MEDIA_DATA_DB_ID,
562 MEDIA_DATA_DB_FILE_PATH,
563 MEDIA_DATA_DB_MEDIA_TYPE,
564 };
565 RdbPredicates rdbPredicates(opts.table);
566 rdbPredicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, to_string(MEDIA_TYPE_FILE));
567 rdbPredicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, to_string(MEDIA_TYPE_ALBUM));
568
569 rdbPredicates.Limit(LcdLimit);
570 rdbPredicates.OrderByAsc(MEDIA_DATA_DB_TIME_VISIT);
571 shared_ptr<ResultSet> resultSet = opts.store->QueryByStep(rdbPredicates, column);
572 if (!CheckResultSetCount(resultSet, err)) {
573 MEDIA_ERR_LOG("CheckResultSetCount failed %{public}d", err);
574 return false;
575 }
576
577 err = resultSet->GoToFirstRow();
578 if (err != E_OK) {
579 MEDIA_ERR_LOG("Failed GoToFirstRow %{public}d", err);
580 return false;
581 }
582
583 ThumbnailData data;
584 do {
585 ParseQueryResult(resultSet, data, err);
586 if (!data.path.empty()) {
587 infos.push_back(data);
588 }
589 } while (resultSet->GoToNextRow() == E_OK);
590 return true;
591 }
592
QueryNoLcdInfos(ThumbRdbOpt & opts,int LcdLimit,vector<ThumbnailData> & infos,int & err)593 bool ThumbnailUtils::QueryNoLcdInfos(ThumbRdbOpt &opts, int LcdLimit, vector<ThumbnailData> &infos, int &err)
594 {
595 vector<string> column = {
596 MEDIA_DATA_DB_ID,
597 MEDIA_DATA_DB_FILE_PATH,
598 MEDIA_DATA_DB_MEDIA_TYPE,
599 };
600 RdbPredicates rdbPredicates(opts.table);
601 rdbPredicates.EqualTo(MEDIA_DATA_DB_TIME_VISIT, "0");
602 rdbPredicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, to_string(MEDIA_TYPE_FILE));
603 rdbPredicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, to_string(MEDIA_TYPE_ALBUM));
604 rdbPredicates.EqualTo(MEDIA_DATA_DB_IS_TRASH, "0");
605 rdbPredicates.EqualTo(MEDIA_DATA_DB_TIME_PENDING, "0");
606
607 rdbPredicates.Limit(LcdLimit);
608 rdbPredicates.OrderByDesc(MEDIA_DATA_DB_DATE_ADDED);
609 shared_ptr<ResultSet> resultSet = opts.store->QueryByStep(rdbPredicates, column);
610 if (!CheckResultSetCount(resultSet, err)) {
611 MEDIA_ERR_LOG("CheckResultSetCount failed %{public}d", err);
612 return false;
613 }
614
615 err = resultSet->GoToFirstRow();
616 if (err != E_OK) {
617 MEDIA_ERR_LOG("Failed GoToFirstRow %{public}d", err);
618 return false;
619 }
620
621 ThumbnailData data;
622 do {
623 ParseQueryResult(resultSet, data, err);
624 if (!data.path.empty()) {
625 infos.push_back(data);
626 }
627 } while (resultSet->GoToNextRow() == E_OK);
628 return true;
629 }
630
QueryNoThumbnailInfos(ThumbRdbOpt & opts,vector<ThumbnailData> & infos,int & err)631 bool ThumbnailUtils::QueryNoThumbnailInfos(ThumbRdbOpt &opts, vector<ThumbnailData> &infos, int &err)
632 {
633 vector<string> column = {
634 MEDIA_DATA_DB_ID,
635 MEDIA_DATA_DB_FILE_PATH,
636 MEDIA_DATA_DB_MEDIA_TYPE,
637 };
638 RdbPredicates rdbPredicates(opts.table);
639 rdbPredicates.EqualTo(MEDIA_DATA_DB_TIME_VISIT, "0");
640 rdbPredicates.EqualTo(MEDIA_DATA_DB_IS_TRASH, "0");
641 rdbPredicates.EqualTo(MEDIA_DATA_DB_TIME_PENDING, "0");
642 rdbPredicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, to_string(MEDIA_TYPE_ALBUM));
643 rdbPredicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, to_string(MEDIA_TYPE_FILE));
644
645 rdbPredicates.Limit(THUMBNAIL_QUERY_MAX);
646 rdbPredicates.OrderByDesc(MEDIA_DATA_DB_DATE_ADDED);
647
648 shared_ptr<ResultSet> resultSet = opts.store->QueryByStep(rdbPredicates, column);
649 if (!CheckResultSetCount(resultSet, err)) {
650 MEDIA_ERR_LOG("CheckResultSetCount failed %{public}d", err);
651 if (err == E_EMPTY_VALUES_BUCKET) {
652 return true;
653 }
654 return false;
655 }
656
657 err = resultSet->GoToFirstRow();
658 if (err != E_OK) {
659 MEDIA_ERR_LOG("Failed GoToFirstRow %{public}d", err);
660 return false;
661 }
662
663 ThumbnailData data;
664 do {
665 ParseQueryResult(resultSet, data, err);
666 if (!data.path.empty()) {
667 infos.push_back(data);
668 }
669 } while (resultSet->GoToNextRow() == E_OK);
670 return true;
671 }
672
UpdateLcdInfo(ThumbRdbOpt & opts,ThumbnailData & data,int & err)673 bool ThumbnailUtils::UpdateLcdInfo(ThumbRdbOpt &opts, ThumbnailData &data, int &err)
674 {
675 ValuesBucket values;
676 int changedRows;
677
678 int64_t timeNow = UTCTimeMilliSeconds();
679 values.PutLong(MEDIA_DATA_DB_TIME_VISIT, timeNow);
680
681 MediaLibraryTracer tracer;
682 tracer.Start("UpdateLcdInfo opts.store->Update");
683 err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
684 vector<string> { opts.row });
685 if (err != NativeRdb::E_OK) {
686 MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
687 return false;
688 }
689 return true;
690 }
691
UpdateVisitTime(ThumbRdbOpt & opts,ThumbnailData & data,int & err)692 bool ThumbnailUtils::UpdateVisitTime(ThumbRdbOpt &opts, ThumbnailData &data, int &err)
693 {
694 if (!opts.networkId.empty()) {
695 return DoUpdateRemoteThumbnail(opts, data, err);
696 }
697
698 ValuesBucket values;
699 int changedRows;
700 int64_t timeNow = UTCTimeMilliSeconds();
701 values.PutLong(MEDIA_DATA_DB_TIME_VISIT, timeNow);
702 err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
703 vector<string> { opts.row });
704 if (err != NativeRdb::E_OK) {
705 MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
706 return false;
707 }
708 return true;
709 }
710
QueryDeviceThumbnailRecords(ThumbRdbOpt & opts,vector<ThumbnailData> & infos,int & err)711 bool ThumbnailUtils::QueryDeviceThumbnailRecords(ThumbRdbOpt &opts, vector<ThumbnailData> &infos,
712 int &err)
713 {
714 vector<string> column = {
715 REMOTE_THUMBNAIL_DB_FILE_ID,
716 MEDIA_DATA_DB_THUMBNAIL,
717 MEDIA_DATA_DB_LCD
718 };
719 RdbPredicates rdbPredicates(REMOTE_THUMBNAIL_TABLE);
720 rdbPredicates.EqualTo(REMOTE_THUMBNAIL_DB_UDID, opts.udid);
721 shared_ptr<ResultSet> resultSet = opts.store->QueryByStep(rdbPredicates, column);
722 if (!CheckResultSetCount(resultSet, err)) {
723 MEDIA_ERR_LOG("CheckResultSetCount failed %{public}d", err);
724 return false;
725 }
726
727 err = resultSet->GoToFirstRow();
728 if (err != E_OK) {
729 MEDIA_ERR_LOG("Failed GoToFirstRow %{public}d", err);
730 return false;
731 }
732
733 ThumbnailData data;
734 do {
735 ParseQueryResult(resultSet, data, err);
736 infos.push_back(data);
737 } while (resultSet->GoToNextRow() == E_OK);
738 return true;
739 }
740
GetRemoteThumbnailInfo(ThumbRdbOpt & opts,const string & id,const string & udid,int & err)741 bool ThumbnailUtils::GetRemoteThumbnailInfo(ThumbRdbOpt &opts, const string &id,
742 const string &udid, int &err)
743 {
744 vector<string> column = {
745 REMOTE_THUMBNAIL_DB_ID
746 };
747 RdbPredicates rdbPredicates(REMOTE_THUMBNAIL_TABLE);
748 rdbPredicates.EqualTo(REMOTE_THUMBNAIL_DB_FILE_ID, id);
749 rdbPredicates.EqualTo(REMOTE_THUMBNAIL_DB_UDID, udid);
750 shared_ptr<ResultSet> resultSet = opts.store->QueryByStep(rdbPredicates, column);
751 if (!CheckResultSetCount(resultSet, err)) {
752 MEDIA_ERR_LOG("CheckResultSetCount failed %{public}d", err);
753 return false;
754 }
755 return true;
756 }
757
GetUdidByNetworkId(ThumbRdbOpt & opts,const string & networkId,string & outUdid,int & err)758 bool ThumbnailUtils::GetUdidByNetworkId(ThumbRdbOpt &opts, const string &networkId,
759 string &outUdid, int &err)
760 {
761 vector<string> column = {
762 DEVICE_DB_ID,
763 DEVICE_DB_UDID
764 };
765 RdbPredicates rdbPredicates(DEVICE_TABLE);
766 rdbPredicates.EqualTo(DEVICE_DB_NETWORK_ID, networkId);
767 shared_ptr<ResultSet> resultSet = opts.store->QueryByStep(rdbPredicates, column);
768 if (!CheckResultSetCount(resultSet, err)) {
769 MEDIA_ERR_LOG("CheckResultSetCount failed %{public}d", err);
770 return false;
771 }
772
773 err = resultSet->GoToFirstRow();
774 if (err != E_OK) {
775 MEDIA_ERR_LOG("Failed GoToFirstRow %{public}d", err);
776 return false;
777 }
778 int index;
779 err = resultSet->GetColumnIndex(DEVICE_DB_UDID, index);
780 if (err == NativeRdb::E_OK) {
781 ParseStringResult(resultSet, index, outUdid, err);
782 } else {
783 MEDIA_ERR_LOG("Get column index error %{public}d", err);
784 }
785 return true;
786 }
787
QueryRemoteThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,int & err)788 bool ThumbnailUtils::QueryRemoteThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, int &err)
789 {
790 if (data.udid.empty() && !GetUdidByNetworkId(opts, opts.networkId, data.udid, err)) {
791 MEDIA_ERR_LOG("GetUdidByNetworkId failed! %{public}d", err);
792 return false;
793 }
794
795 vector<string> column = {
796 REMOTE_THUMBNAIL_DB_ID,
797 MEDIA_DATA_DB_THUMBNAIL,
798 MEDIA_DATA_DB_LCD
799 };
800 RdbPredicates rdbPredicates(REMOTE_THUMBNAIL_TABLE);
801 rdbPredicates.EqualTo(REMOTE_THUMBNAIL_DB_FILE_ID, data.id);
802 rdbPredicates.EqualTo(REMOTE_THUMBNAIL_DB_UDID, data.udid);
803 shared_ptr<ResultSet> resultSet = opts.store->QueryByStep(rdbPredicates, column);
804 if (!CheckResultSetCount(resultSet, err)) {
805 MEDIA_ERR_LOG("CheckResultSetCount failed %{public}d", err);
806 return false;
807 }
808
809 err = resultSet->GoToFirstRow();
810 if (err != E_OK) {
811 MEDIA_ERR_LOG("Failed GoToFirstRow %{public}d", err);
812 return false;
813 }
814
815 int index;
816 err = resultSet->GetColumnIndex(MEDIA_DATA_DB_LCD, index);
817 if (err == NativeRdb::E_OK) {
818 ParseStringResult(resultSet, index, data.lcdKey, err);
819 }
820
821 err = resultSet->GetColumnIndex(MEDIA_DATA_DB_THUMBNAIL, index);
822 if (err == NativeRdb::E_OK) {
823 ParseStringResult(resultSet, index, data.thumbnailKey, err);
824 }
825 return true;
826 }
827
IsKeyNotSame(const string & newKey,const string & oldKey)828 static inline bool IsKeyNotSame(const string &newKey, const string &oldKey)
829 {
830 return !newKey.empty() && !oldKey.empty() && (newKey != oldKey);
831 }
832
DoUpdateRemoteThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,int & err)833 bool ThumbnailUtils::DoUpdateRemoteThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, int &err)
834 {
835 if (opts.networkId.empty()) {
836 return false;
837 }
838 if (data.thumbnailKey.empty() && data.lcdKey.empty()) {
839 return false;
840 }
841 ThumbnailData tmpData = data;
842 auto isGot = ThumbnailUtils::QueryRemoteThumbnail(opts, tmpData, err);
843 if (isGot) {
844 if (IsKeyNotSame(data.thumbnailKey, tmpData.thumbnailKey)) {
845 if (!RemoveDataFromKv(opts.kvStore, tmpData.thumbnailKey)) {
846 return false;
847 }
848 }
849 if (IsKeyNotSame(data.lcdKey, tmpData.lcdKey)) {
850 if (!RemoveDataFromKv(opts.kvStore, tmpData.lcdKey)) {
851 return false;
852 }
853 }
854 }
855
856 data.udid = tmpData.udid;
857 if (isGot) {
858 return UpdateRemoteThumbnailInfo(opts, data, err);
859 } else {
860 return InsertRemoteThumbnailInfo(opts, data, err);
861 }
862 }
863
UpdateRemoteThumbnailInfo(ThumbRdbOpt & opts,ThumbnailData & data,int & err)864 bool ThumbnailUtils::UpdateRemoteThumbnailInfo(ThumbRdbOpt &opts, ThumbnailData &data, int &err)
865 {
866 RdbPredicates rdbPredicates(REMOTE_THUMBNAIL_TABLE);
867 rdbPredicates.EqualTo(REMOTE_THUMBNAIL_DB_FILE_ID, data.id);
868 rdbPredicates.EqualTo(REMOTE_THUMBNAIL_DB_UDID, data.udid);
869
870 ValuesBucket values;
871 if (!data.thumbnailKey.empty()) {
872 values.PutString(MEDIA_DATA_DB_THUMBNAIL, data.thumbnailKey);
873 }
874
875 if (!data.lcdKey.empty()) {
876 values.PutString(MEDIA_DATA_DB_LCD, data.lcdKey);
877 int64_t timeNow = UTCTimeMilliSeconds();
878 values.PutLong(MEDIA_DATA_DB_TIME_VISIT, timeNow);
879 }
880
881 int changedRows;
882 err = opts.store->Update(changedRows, values, rdbPredicates);
883 if (err != NativeRdb::E_OK) {
884 MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
885 return false;
886 }
887
888 return true;
889 }
890
InsertRemoteThumbnailInfo(ThumbRdbOpt & opts,ThumbnailData & data,int & err)891 bool ThumbnailUtils::InsertRemoteThumbnailInfo(ThumbRdbOpt &opts, ThumbnailData &data, int &err)
892 {
893 ValuesBucket values;
894 values.PutInt(REMOTE_THUMBNAIL_DB_FILE_ID, stoi(data.id));
895 values.PutString(REMOTE_THUMBNAIL_DB_UDID, data.udid);
896 if (!data.thumbnailKey.empty()) {
897 values.PutString(MEDIA_DATA_DB_THUMBNAIL, data.thumbnailKey);
898 }
899
900 if (!data.lcdKey.empty()) {
901 values.PutString(MEDIA_DATA_DB_LCD, data.lcdKey);
902 int64_t timeNow = UTCTimeMilliSeconds();
903 values.PutLong(MEDIA_DATA_DB_TIME_VISIT, timeNow);
904 }
905
906 int64_t outRowId = -1;
907 err = opts.store->Insert(outRowId, REMOTE_THUMBNAIL_TABLE, values);
908 if (err != NativeRdb::E_OK) {
909 MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
910 return false;
911 }
912 return true;
913 }
914
CleanThumbnailInfo(ThumbRdbOpt & opts,bool withThumb,bool withLcd)915 bool ThumbnailUtils::CleanThumbnailInfo(ThumbRdbOpt &opts, bool withThumb, bool withLcd)
916 {
917 ValuesBucket values;
918 if (withThumb) {
919 values.PutNull(MEDIA_DATA_DB_THUMBNAIL);
920 }
921 if (withLcd) {
922 values.PutNull(MEDIA_DATA_DB_LCD);
923 values.PutLong(MEDIA_DATA_DB_TIME_VISIT, 0);
924 values.PutInt(MEDIA_DATA_DB_DIRTY, static_cast<int32_t>(DirtyType::TYPE_SYNCED));
925 }
926 int changedRows;
927 auto err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
928 vector<string> { opts.row });
929 if (err != NativeRdb::E_OK) {
930 MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
931 return false;
932 }
933 return true;
934 }
935
CleanDistributeLcdInfo(ThumbRdbOpt & opts)936 bool ThumbnailUtils::CleanDistributeLcdInfo(ThumbRdbOpt &opts)
937 {
938 string udid;
939 int err;
940 if (!GetUdidByNetworkId(opts, opts.networkId, udid, err)) {
941 MEDIA_ERR_LOG("GetUdidByNetworkId failed! %{public}d", err);
942 return false;
943 }
944
945 ValuesBucket values;
946 values.PutNull(MEDIA_DATA_DB_LCD);
947 values.PutLong(MEDIA_DATA_DB_TIME_VISIT, 0);
948 int changedRows;
949 vector<string> whereArgs = { udid, opts.row };
950 string deleteCondition = REMOTE_THUMBNAIL_DB_UDID + " = ? AND " +
951 REMOTE_THUMBNAIL_DB_FILE_ID + " = ?";
952 auto ret = opts.store->Update(changedRows, REMOTE_THUMBNAIL_TABLE, values, deleteCondition, whereArgs);
953 if (ret != NativeRdb::E_OK) {
954 MEDIA_ERR_LOG("RdbStore Delete failed! %{public}d", ret);
955 return false;
956 }
957 return true;
958 }
959
DeleteDistributeThumbnailInfo(ThumbRdbOpt & opts)960 bool ThumbnailUtils::DeleteDistributeThumbnailInfo(ThumbRdbOpt &opts)
961 {
962 int changedRows;
963 vector<string> whereArgs = { opts.udid, opts.row };
964 string deleteCondition = REMOTE_THUMBNAIL_DB_UDID + " = ? AND " +
965 REMOTE_THUMBNAIL_DB_FILE_ID + " = ?";
966 auto err = opts.store->Delete(changedRows, REMOTE_THUMBNAIL_TABLE, deleteCondition, whereArgs);
967 if (err != NativeRdb::E_OK) {
968 MEDIA_ERR_LOG("RdbStore Delete failed! %{public}d", err);
969 return false;
970 }
971 return true;
972 }
973
ConvertDecodeSize(const Size & sourceSize,const Size & desiredSize,const bool isThumbnail)974 Size ThumbnailUtils::ConvertDecodeSize(const Size &sourceSize, const Size &desiredSize, const bool isThumbnail)
975 {
976 float desiredScale = static_cast<float>(desiredSize.height) / static_cast<float>(desiredSize.width);
977 float sourceScale = static_cast<float>(sourceSize.height) / static_cast<float>(sourceSize.width);
978 float scale = 1.0f;
979 if ((sourceScale - desiredScale > EPSILON) ^ isThumbnail) {
980 scale = (float)desiredSize.height / sourceSize.height;
981 } else {
982 scale = (float)desiredSize.width / sourceSize.width;
983 }
984 scale = scale < 1.0f ? scale : 1.0f;
985 Size decodeSize = {
986 static_cast<int32_t> (scale * sourceSize.width),
987 static_cast<int32_t> (scale * sourceSize.height),
988 };
989 return decodeSize;
990 }
991
LoadSourceImage(ThumbnailData & data,const Size & desiredSize,const bool isThumbnail)992 bool ThumbnailUtils::LoadSourceImage(ThumbnailData &data, const Size &desiredSize, const bool isThumbnail)
993 {
994 if (data.source != nullptr) {
995 return true;
996 }
997 MediaLibraryTracer tracer;
998 tracer.Start("LoadSourceImage");
999 if (data.mediaType == -1) {
1000 auto extension = MediaFileUtils::GetExtensionFromPath(data.path);
1001 auto mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extension);
1002 data.mediaType = MimeTypeUtils::GetMediaTypeFromMimeType(mimeType);
1003 }
1004
1005 bool ret = false;
1006 data.degrees = 0.0;
1007 if (data.mediaType == MEDIA_TYPE_VIDEO) {
1008 ret = LoadVideoFile(data, isThumbnail, desiredSize);
1009 } else if (data.mediaType == MEDIA_TYPE_AUDIO) {
1010 ret = LoadAudioFile(data, isThumbnail, desiredSize);
1011 } else {
1012 ret = LoadImageFile(data, isThumbnail, desiredSize);
1013 }
1014 if (!ret || (data.source == nullptr)) {
1015 return false;
1016 }
1017 tracer.Finish();
1018
1019 if (isThumbnail) {
1020 tracer.Start("CenterScale");
1021 PostProc postProc;
1022 if (!postProc.CenterScale(desiredSize, *data.source)) {
1023 MEDIA_ERR_LOG("thumbnail center crop failed [%{public}s]", data.id.c_str());
1024 return false;
1025 }
1026 }
1027 data.source->SetAlphaType(AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
1028 data.source->rotate(data.degrees);
1029 return true;
1030 }
1031
SaveFile(const string & fileName,uint8_t * output,int writeSize)1032 static int SaveFile(const string &fileName, uint8_t *output, int writeSize)
1033 {
1034 const mode_t fileMode = 0664;
1035 mode_t mask = umask(0);
1036 UniqueFd fd(open(fileName.c_str(), O_WRONLY | O_CREAT | O_TRUNC, fileMode));
1037 umask(mask);
1038 if (fd.Get() < 0) {
1039 if (errno == EEXIST) {
1040 UniqueFd fd(open(fileName.c_str(), O_WRONLY | O_TRUNC, fileMode));
1041 }
1042 if (fd.Get() < 0) {
1043 MEDIA_ERR_LOG("save failed! filePath %{private}s status %{public}d", fileName.c_str(), errno);
1044 return -errno;
1045 }
1046 }
1047 int ret = write(fd.Get(), output, writeSize);
1048 if (ret < 0) {
1049 return -errno;
1050 } else {
1051 return ret;
1052 }
1053 }
1054
TrySaveFile(ThumbnailData & data,ThumbnailType type)1055 int ThumbnailUtils::TrySaveFile(ThumbnailData &data, ThumbnailType type)
1056 {
1057 string suffix;
1058 uint8_t *output;
1059 int writeSize;
1060 switch (type) {
1061 case ThumbnailType::MTH:
1062 case ThumbnailType::YEAR:
1063 suffix = (type == ThumbnailType::MTH) ? THUMBNAIL_MTH_SUFFIX : THUMBNAIL_YEAR_SUFFIX;
1064 output = const_cast<uint8_t *>(data.source->GetPixels());
1065 writeSize = data.source->GetByteCount();
1066 break;
1067 case ThumbnailType::THUMB:
1068 suffix = THUMBNAIL_THUMB_SUFFIX;
1069 output = data.thumbnail.data();
1070 writeSize = data.thumbnail.size();
1071 break;
1072 case ThumbnailType::LCD:
1073 suffix = THUMBNAIL_LCD_SUFFIX;
1074 output = data.lcd.data();
1075 writeSize = data.lcd.size();
1076 break;
1077 default:
1078 return E_INVALID_ARGUMENTS;
1079 }
1080 if (writeSize <= 0) {
1081 return E_THUMBNAIL_LOCAL_CREATE_FAIL;
1082 }
1083 string fileName = GetThumbnailPath(data.path, suffix);
1084 string dir = MediaFileUtils::GetParentPath(fileName);
1085 if (!MediaFileUtils::CreateDirectory(dir)) {
1086 return -errno;
1087 }
1088
1089 int ret = SaveFile(fileName, output, writeSize);
1090 if (ret < 0) {
1091 DeleteThumbFile(data, type);
1092 return ret;
1093 } else if (ret != writeSize) {
1094 DeleteThumbFile(data, type);
1095 return E_NO_SPACE;
1096 }
1097 return E_OK;
1098 }
1099
SaveThumbnailData(ThumbnailData & data,const string & networkId,const shared_ptr<SingleKvStore> & kvStore)1100 Status ThumbnailUtils::SaveThumbnailData(ThumbnailData &data, const string &networkId,
1101 const shared_ptr<SingleKvStore> &kvStore)
1102 {
1103 Status status = SaveImage(kvStore, data.thumbnailKey, data.thumbnail);
1104 if (status != DistributedKv::Status::SUCCESS) {
1105 MEDIA_ERR_LOG("SaveImage failed! status %{public}d", status);
1106 }
1107
1108 return status;
1109 }
1110
SaveLcdData(ThumbnailData & data,const string & networkId,const shared_ptr<SingleKvStore> & kvStore)1111 Status ThumbnailUtils::SaveLcdData(ThumbnailData &data, const string &networkId,
1112 const shared_ptr<SingleKvStore> &kvStore)
1113 {
1114 Status status = SaveImage(kvStore, data.lcdKey, data.lcd);
1115 if (status != DistributedKv::Status::SUCCESS) {
1116 MEDIA_ERR_LOG("SaveLcdData SaveImage failed! status %{public}d", status);
1117 }
1118 return status;
1119 }
1120
SetSource(shared_ptr<AVMetadataHelper> avMetadataHelper,const string & path)1121 int32_t ThumbnailUtils::SetSource(shared_ptr<AVMetadataHelper> avMetadataHelper, const string &path)
1122 {
1123 if (avMetadataHelper == nullptr) {
1124 MEDIA_ERR_LOG("avMetadataHelper == nullptr");
1125 return E_ERR;
1126 }
1127 MEDIA_DEBUG_LOG("path = %{private}s", path.c_str());
1128 int32_t fd = open(path.c_str(), O_RDONLY);
1129 if (fd < 0) {
1130 MEDIA_ERR_LOG("Open file failed, err %{public}d", errno);
1131 return E_ERR;
1132 }
1133
1134 struct stat64 st;
1135 if (fstat64(fd, &st) != 0) {
1136 MEDIA_ERR_LOG("Get file state failed, err %{public}d", errno);
1137 (void)close(fd);
1138 return E_ERR;
1139 }
1140 int64_t length = static_cast<int64_t>(st.st_size);
1141 int32_t ret = avMetadataHelper->SetSource(fd, 0, length, AV_META_USAGE_PIXEL_MAP);
1142 if (ret != 0) {
1143 MEDIA_ERR_LOG("SetSource fail");
1144 (void)close(fd);
1145 return E_ERR;
1146 }
1147 (void)close(fd);
1148 return SUCCESS;
1149 }
1150
ResizeImage(const vector<uint8_t> & data,const Size & size,unique_ptr<PixelMap> & pixelMap)1151 bool ThumbnailUtils::ResizeImage(const vector<uint8_t> &data, const Size &size, unique_ptr<PixelMap> &pixelMap)
1152 {
1153 MediaLibraryTracer tracer;
1154 tracer.Start("ResizeImage");
1155 if (data.size() == 0) {
1156 MEDIA_ERR_LOG("Data is empty");
1157 return false;
1158 }
1159
1160 tracer.Start("ImageSource::CreateImageSource");
1161 uint32_t err = E_OK;
1162 SourceOptions opts;
1163 unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(data.data(),
1164 data.size(), opts, err);
1165 if (err != E_OK) {
1166 MEDIA_ERR_LOG("Failed to create image source %{public}d", err);
1167 return false;
1168 }
1169 tracer.Finish();
1170
1171 tracer.Start("imageSource->CreatePixelMap");
1172 DecodeOptions decodeOpts;
1173 decodeOpts.desiredSize.width = size.width;
1174 decodeOpts.desiredSize.height = size.height;
1175 decodeOpts.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
1176 pixelMap = imageSource->CreatePixelMap(decodeOpts, err);
1177 if (err != Media::SUCCESS) {
1178 MEDIA_ERR_LOG("Failed to create pixelmap %{public}d", err);
1179 return false;
1180 }
1181
1182 return true;
1183 }
1184
GetPixelMapFromResult(const shared_ptr<DataShare::DataShareResultSet> & resultSet,const Size & size,unique_ptr<PixelMap> & outPixelMap)1185 int ThumbnailUtils::GetPixelMapFromResult(const shared_ptr<DataShare::DataShareResultSet> &resultSet, const Size &size,
1186 unique_ptr<PixelMap> &outPixelMap)
1187 {
1188 MediaLibraryTracer tracer;
1189 tracer.Start("ThumbnailUtils::GetKv");
1190 int ret = resultSet->GoToFirstRow();
1191 if (ret != DataShare::E_OK) {
1192 MEDIA_ERR_LOG("GoToFirstRow error %{public}d", ret);
1193 return ret;
1194 }
1195
1196 vector<uint8_t> key;
1197 ret = resultSet->GetBlob(KEY_INDEX, key);
1198 if (ret != DataShare::E_OK) {
1199 MEDIA_ERR_LOG("GetBlob key error %{public}d", ret);
1200 return ret;
1201 }
1202
1203 vector<uint8_t> image;
1204 ret = resultSet->GetBlob(VALUE_INDEX, image);
1205 if (ret != DataShare::E_OK) {
1206 MEDIA_ERR_LOG("GetBlob image error %{public}d", ret);
1207 return ret;
1208 }
1209
1210 resultSet->Close();
1211 tracer.Finish();
1212
1213 MEDIA_DEBUG_LOG("key %{public}s key len %{public}d len %{public}d", string(key.begin(),
1214 key.end()).c_str(), static_cast<int>(key.size()), static_cast<int>(image.size()));
1215
1216 tracer.Start("ThumbnailUtils::ResizeImage");
1217 if (!ResizeImage(image, size, outPixelMap)) {
1218 MEDIA_ERR_LOG("ResizeImage error");
1219 return E_FAIL;
1220 }
1221
1222 return ret;
1223 }
1224
GetKvResultSet(const shared_ptr<SingleKvStore> & kvStore,const string & key,const string & networkId,shared_ptr<DataShare::ResultSetBridge> & outResultSet)1225 bool ThumbnailUtils::GetKvResultSet(const shared_ptr<SingleKvStore> &kvStore, const string &key,
1226 const string &networkId, shared_ptr<DataShare::ResultSetBridge> &outResultSet)
1227 {
1228 if (key.empty()) {
1229 MEDIA_ERR_LOG("key empty");
1230 return false;
1231 }
1232
1233 if (kvStore == nullptr) {
1234 MEDIA_ERR_LOG("KvStore is not init");
1235 return false;
1236 }
1237
1238 MediaLibraryTracer tracer;
1239 tracer.Start("GetKey kvStore->Get");
1240 shared_ptr<SingleKvStore> singleKv = kvStore;
1241 outResultSet = shared_ptr<DataShare::ResultSetBridge>(ThumbnailDataShareBridge::Create(singleKv, key));
1242 return true;
1243 }
1244
RemoveDataFromKv(const shared_ptr<SingleKvStore> & kvStore,const string & key)1245 bool ThumbnailUtils::RemoveDataFromKv(const shared_ptr<SingleKvStore> &kvStore, const string &key)
1246 {
1247 if (key.empty()) {
1248 MEDIA_ERR_LOG("RemoveLcdFromKv key empty");
1249 return false;
1250 }
1251
1252 if (kvStore == nullptr) {
1253 MEDIA_ERR_LOG("KvStore is not init");
1254 return false;
1255 }
1256
1257 MediaLibraryTracer tracer;
1258 tracer.Start("RemoveLcdFromKv kvStore->Get");
1259 auto status = kvStore->Delete(key);
1260 if (status != Status::SUCCESS) {
1261 MEDIA_ERR_LOG("Failed to get key [%{public}s] ret [%{public}d]", key.c_str(), status);
1262 return false;
1263 }
1264 return true;
1265 }
1266
1267 // notice: return value is whether thumb/lcd is deleted
DeleteOriginImage(ThumbRdbOpt & opts)1268 bool ThumbnailUtils::DeleteOriginImage(ThumbRdbOpt &opts)
1269 {
1270 ThumbnailData tmpData;
1271 tmpData.path = opts.path;
1272 bool isDelete = false;
1273 if (opts.path.empty()) {
1274 int err = 0;
1275 auto rdbSet = QueryThumbnailInfo(opts, tmpData, err);
1276 if (rdbSet == nullptr) {
1277 MEDIA_ERR_LOG("QueryThumbnailInfo Faild [ %{public}d ]", err);
1278 return isDelete;
1279 }
1280 }
1281 if (DeleteThumbFile(tmpData, ThumbnailType::YEAR)) {
1282 isDelete = true;
1283 }
1284 if (DeleteThumbFile(tmpData, ThumbnailType::MTH)) {
1285 isDelete = true;
1286 }
1287 if (DeleteThumbFile(tmpData, ThumbnailType::THUMB)) {
1288 isDelete = true;
1289 }
1290 if (DeleteThumbFile(tmpData, ThumbnailType::LCD)) {
1291 isDelete = true;
1292 }
1293 string fileName = GetThumbnailPath(tmpData.path, "");
1294 MediaFileUtils::DeleteFile(MediaFileUtils::GetParentPath(fileName));
1295 return isDelete;
1296 }
1297
1298 #ifdef DISTRIBUTED
IsImageExist(const string & key,const string & networkId,const shared_ptr<SingleKvStore> & kvStore)1299 bool ThumbnailUtils::IsImageExist(const string &key, const string &networkId, const shared_ptr<SingleKvStore> &kvStore)
1300 {
1301 if (key.empty()) {
1302 return false;
1303 }
1304
1305 if (kvStore == nullptr) {
1306 MEDIA_ERR_LOG("KvStore is not init");
1307 return false;
1308 }
1309
1310 bool ret = false;
1311 DataQuery query;
1312 query.InKeys({key});
1313 int count = 0;
1314 auto status = kvStore->GetCount(query, count);
1315 if (status == Status::SUCCESS && count > 0) {
1316 ret = true;
1317 }
1318
1319 if (!ret) {
1320 if (!networkId.empty()) {
1321 MediaLibraryTracer tracer;
1322 tracer.Start("SyncPullKvstore");
1323 vector<string> keys = { key };
1324 auto syncStatus = MediaLibrarySyncOperation::SyncPullKvstore(kvStore, keys, networkId);
1325 if (syncStatus == DistributedKv::Status::SUCCESS) {
1326 MEDIA_DEBUG_LOG("SyncPullKvstore SUCCESS");
1327 return true;
1328 } else {
1329 MEDIA_ERR_LOG("SyncPullKvstore failed! ret %{public}d", syncStatus);
1330 return false;
1331 }
1332 }
1333 }
1334 return ret;
1335 }
1336 #endif
1337
UTCTimeMilliSeconds()1338 int64_t ThumbnailUtils::UTCTimeMilliSeconds()
1339 {
1340 struct timespec t;
1341 constexpr int64_t SEC_TO_MSEC = 1e3;
1342 constexpr int64_t MSEC_TO_NSEC = 1e6;
1343 clock_gettime(CLOCK_REALTIME, &t);
1344 return t.tv_sec * SEC_TO_MSEC + t.tv_nsec / MSEC_TO_NSEC;
1345 }
1346
CheckResultSetCount(const shared_ptr<ResultSet> & resultSet,int & err)1347 bool ThumbnailUtils::CheckResultSetCount(const shared_ptr<ResultSet> &resultSet, int &err)
1348 {
1349 if (resultSet == nullptr) {
1350 return false;
1351 }
1352 int rowCount = 0;
1353 err = resultSet->GetRowCount(rowCount);
1354 if (err != E_OK) {
1355 MEDIA_ERR_LOG("Failed to get row count %{public}d", err);
1356 return false;
1357 }
1358
1359 if (rowCount <= 0) {
1360 MEDIA_ERR_LOG("CheckCount No match!");
1361 err = E_EMPTY_VALUES_BUCKET;
1362 return false;
1363 }
1364
1365 return true;
1366 }
1367
ParseStringResult(const shared_ptr<ResultSet> & resultSet,int index,string & data,int & err)1368 void ThumbnailUtils::ParseStringResult(const shared_ptr<ResultSet> &resultSet, int index, string &data, int &err)
1369 {
1370 bool isNull = true;
1371 err = resultSet->IsColumnNull(index, isNull);
1372 if (err != E_OK) {
1373 MEDIA_ERR_LOG("Failed to check column %{public}d null %{public}d", index, err);
1374 }
1375
1376 if (!isNull) {
1377 err = resultSet->GetString(index, data);
1378 if (err != E_OK) {
1379 MEDIA_ERR_LOG("Failed to get column %{public}d string %{public}d", index, err);
1380 }
1381 }
1382 }
1383
ParseQueryResult(const shared_ptr<ResultSet> & resultSet,ThumbnailData & data,int & err)1384 void ThumbnailUtils::ParseQueryResult(const shared_ptr<ResultSet> &resultSet, ThumbnailData &data, int &err)
1385 {
1386 int index;
1387 err = resultSet->GetColumnIndex(MEDIA_DATA_DB_ID, index);
1388 if (err == NativeRdb::E_OK) {
1389 ParseStringResult(resultSet, index, data.id, err);
1390 }
1391
1392 err = resultSet->GetColumnIndex(MEDIA_DATA_DB_FILE_PATH, index);
1393 if (err == NativeRdb::E_OK) {
1394 ParseStringResult(resultSet, index, data.path, err);
1395 }
1396
1397 err = resultSet->GetColumnIndex(MEDIA_DATA_DB_MEDIA_TYPE, index);
1398 if (err == NativeRdb::E_OK) {
1399 data.mediaType = MediaType::MEDIA_TYPE_ALL;
1400 err = resultSet->GetInt(index, data.mediaType);
1401 }
1402 }
1403 } // namespace Media
1404 } // namespace OHOS
1405