• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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