1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define MLOG_TAG "PictureDataOperations"
17 
18 #include "picture_data_operations.h"
19 #include "file_utils.h"
20 #include "media_log.h"
21 #include "parameter.h"
22 #include "parameters.h"
23 
24 using namespace std;
25 namespace OHOS {
26 namespace Media {
27 int32_t PictureDataOperations::taskSize = 0;
28 const int32_t SAVE_PICTURE_TIMEOUT_SEC = 20;
29 
PictureDataOperations()30 PictureDataOperations::PictureDataOperations()
31 {
32     max_capibilty = stoi(system::GetParameter("const.multimedia.max_picture_capbility", "3")); // MAX_PICTURE_CAPBILITY
33 }
34 
~PictureDataOperations()35 PictureDataOperations::~PictureDataOperations()
36 {
37     lowQualityPictureMap_.clear();
38     highQualityPictureMap_.clear();
39     highQualityPictureImageId.clear();
40 }
41 
CleanPictureMapData(std::map<std::string,sptr<PicturePair>> & pictureMap,PictureType pictureType)42 void PictureDataOperations::CleanPictureMapData(std::map<std::string, sptr<PicturePair>>& pictureMap,
43     PictureType pictureType)
44 {
45     auto iter = pictureMap.begin();
46     while (iter != pictureMap.end()) {
47         time_t now = time(nullptr);
48         bool isNeedDeletePicture = ((iter->second)->expireTime_ < now) && ((iter->second)->isCleanImmediately_);
49         if (isNeedDeletePicture || ((iter->second)->expireTime_ + SAVE_PICTURE_TIMEOUT_SEC) < now) {
50             if (pictureType == LOW_QUALITY_PICTURE) {
51                 FileUtils::SavePicture(iter->first, (iter->second)->picture_, false, true);
52             }
53             MEDIA_INFO_LOG("enter CleanDateByPictureMap %{public}s enter", (iter->first).c_str());
54             iter->second = nullptr;
55             iter = pictureMap.erase(iter);
56         } else {
57             iter++;
58         }
59     }
60 }
61 
CleanDateForPeriodical()62 void PictureDataOperations::CleanDateForPeriodical()
63 {
64     lock_guard<mutex> lock(pictureMapMutex_);
65     enum PictureType pictureType;
66     for (pictureType = LOW_QUALITY_PICTURE; pictureType <= HIGH_QUALITY_PICTURE;
67         pictureType = (PictureType)(pictureType + 1)) {
68         switch (pictureType) {
69             case LOW_QUALITY_PICTURE:
70                 CleanPictureMapData(lowQualityPictureMap_, pictureType);
71                 break;
72             case HIGH_QUALITY_PICTURE:
73                 CleanPictureMapData(highQualityPictureMap_, pictureType);
74                 break;
75             default:
76                 break;
77         }
78     }
79 }
80 
InsertPictureData(const std::string & imageId,sptr<PicturePair> & picturePair,PictureType pictureType)81 void PictureDataOperations::InsertPictureData(const std::string& imageId, sptr<PicturePair>& picturePair,
82     PictureType pictureType)
83 {
84     MEDIA_INFO_LOG("enter InsertPictureData %{public}s enter", imageId.c_str());
85     switch (pictureType) {
86         case LOW_QUALITY_PICTURE:{
87             lock_guard<mutex>  lock(pictureMapMutex_);
88             auto iter = lowQualityPictureMap_.find(imageId);
89             if (iter != lowQualityPictureMap_.end()) {
90                 iter->second = nullptr;
91                 lowQualityPictureMap_.erase(iter);
92             }
93             lowQualityPictureMap_[imageId] = picturePair;
94             }
95             break;
96         case HIGH_QUALITY_PICTURE:
97             if (highQualityPictureMap_.find(imageId) ==  highQualityPictureMap_.end()) {
98                 highQualityPictureImageId.push_back(imageId);
99             }
100             CleanHighQualityPictureDataInternal(imageId, picturePair, highQualityPictureImageId);
101             break;
102         default:
103             break;
104     }
105 
106     MEDIA_DEBUG_LOG("end InsertPictureData");
107 }
108 
CleanHighQualityPictureDataInternal(const std::string & imageId,sptr<PicturePair> & picturePair,std::list<std::string> & pictureImageIdList)109 void PictureDataOperations::CleanHighQualityPictureDataInternal(const std::string& imageId,
110     sptr<PicturePair>& picturePair,
111     std::list<std::string>& pictureImageIdList)
112 {
113     MEDIA_DEBUG_LOG("enter %{public}zu", highQualityPictureMap_.size());
114     lock_guard<mutex>  lock(pictureMapMutex_);
115     // 清理低质量图
116     auto iterPicture = lowQualityPictureMap_.find(imageId);
117     if (iterPicture != lowQualityPictureMap_.end()) {
118         iterPicture->second = nullptr;
119         lowQualityPictureMap_.erase(iterPicture);
120     }
121     // 存储高质量图
122     iterPicture = highQualityPictureMap_.find(imageId);
123     if (iterPicture != highQualityPictureMap_.end()) {
124         iterPicture->second = nullptr;
125         highQualityPictureMap_.erase(iterPicture);
126     }
127     highQualityPictureMap_[imageId] = picturePair;
128 
129     // 删除至最大值,高质量不用落盘
130     for (auto iter = pictureImageIdList.begin(); iter != pictureImageIdList.end();) {
131         if ((int)(highQualityPictureMap_.size()) <= max_capibilty) {
132             return;
133         }
134         std::string imageId = *iter;
135         std::map<std::string, sptr<PicturePair>>::iterator iterPicture = highQualityPictureMap_.find(imageId);
136         if (iterPicture != highQualityPictureMap_.end() && (iterPicture->second)->isCleanImmediately_) {
137             iterPicture->second = nullptr;
138             highQualityPictureMap_.erase(iterPicture);
139             iter = pictureImageIdList.erase(iter);
140         } else {
141             iter++;
142         }
143     }
144     MEDIA_DEBUG_LOG("end");
145 }
146 
GetDataWithImageId(const std::string & imageId,bool & isHighQualityPicture,bool isCleanImmediately)147 std::shared_ptr<Media::Picture> PictureDataOperations::GetDataWithImageId(const std::string& imageId,
148     bool &isHighQualityPicture, bool isCleanImmediately)
149 {
150     MEDIA_DEBUG_LOG("enter %{public}s enter", imageId.c_str());
151     enum PictureType pictureType;
152     std::shared_ptr<Media::Picture> picture;
153     isHighQualityPicture = false;
154     for (pictureType = HIGH_QUALITY_PICTURE; pictureType >= LOW_QUALITY_PICTURE;
155         pictureType = (PictureType)(pictureType - 1)) {
156         picture = GetDataWithImageIdAndPictureType(imageId, pictureType, isCleanImmediately);
157         if (picture != nullptr && picture->GetMainPixel() != nullptr) {
158             MEDIA_DEBUG_LOG("GetDataWithImageId is not null ");
159             isHighQualityPicture = (pictureType == HIGH_QUALITY_PICTURE);
160             return picture;
161         } else {
162             MEDIA_DEBUG_LOG("GetDataWithImageId is not found ");
163         }
164     }
165     return picture;
166 }
167 
168 
SavePictureWithImageId(const std::string & imageId)169 void PictureDataOperations::SavePictureWithImageId(const std::string& imageId)
170 {
171     MEDIA_DEBUG_LOG("enter ");
172     enum PictureType pictureType;
173     bool isSuccess = false;
174     for (pictureType = HIGH_QUALITY_PICTURE; pictureType >= LOW_QUALITY_PICTURE;
175         pictureType = (PictureType)(pictureType - 1)) {
176         switch (pictureType) {
177             case LOW_QUALITY_PICTURE:
178                 isSuccess = SavePicture(imageId, lowQualityPictureMap_, true);
179                 break;
180             case HIGH_QUALITY_PICTURE:
181                 isSuccess = SavePicture(imageId, highQualityPictureMap_, false);
182                 break;
183             default:
184                 break;
185         }
186     }
187     if (isSuccess) { // 高质量提前返回
188         return;
189     }
190     MEDIA_DEBUG_LOG("end ");
191 }
192 
GetDataWithImageIdAndPictureType(const std::string & imageId,PictureType pictureType,bool isCleanImmediately)193 std::shared_ptr<Media::Picture> PictureDataOperations::GetDataWithImageIdAndPictureType(const std::string& imageId,
194     PictureType pictureType, bool isCleanImmediately)
195 {
196     MEDIA_DEBUG_LOG("enter ");
197     lock_guard<mutex>  lock(pictureMapMutex_);
198     std::map<std::string, sptr<PicturePair>>::iterator iter;
199     std::shared_ptr<Media::Picture> picture;
200     switch (pictureType) {
201         case LOW_QUALITY_PICTURE:
202             iter = lowQualityPictureMap_.find(imageId);
203             if (iter != lowQualityPictureMap_.end()) {
204                 (iter->second)->isCleanImmediately_ = isCleanImmediately;
205                 picture = (iter->second)->picture_;
206             }
207             break;
208         case HIGH_QUALITY_PICTURE:
209             iter = highQualityPictureMap_.find(imageId);
210             if (iter != highQualityPictureMap_.end()) {
211                 (iter->second)->isCleanImmediately_ = isCleanImmediately;
212                 picture = (iter->second)->picture_;
213             }
214             break;
215         default:
216             break;
217     }
218     return picture;
219 }
220 
IsExsitDataForPictureType(PictureType pictureType)221 bool PictureDataOperations::IsExsitDataForPictureType(PictureType pictureType)
222 {
223     MEDIA_DEBUG_LOG("enter ");
224     lock_guard<mutex> lock(pictureMapMutex_);
225     bool isExsit = false;
226     switch (pictureType) {
227         case LOW_QUALITY_PICTURE:
228             isExsit = lowQualityPictureMap_.size() >= 1;
229             break;
230         case HIGH_QUALITY_PICTURE:
231             isExsit = highQualityPictureMap_.size() >= 1;
232             break;
233         default:
234             break;
235     }
236     return isExsit;
237 }
238 
IsExsitDataForPictureType(const std::string & imageId,PictureType pictureType)239 bool PictureDataOperations::IsExsitDataForPictureType(const std::string& imageId, PictureType pictureType)
240 {
241     MEDIA_DEBUG_LOG("enter ");
242     lock_guard<mutex> lock(pictureMapMutex_);
243     bool isExsit = false;
244     switch (pictureType) {
245         case LOW_QUALITY_PICTURE:
246             isExsit = lowQualityPictureMap_.size() >= 0 &&
247                 lowQualityPictureMap_.find(imageId) != lowQualityPictureMap_.end();
248             break;
249         case HIGH_QUALITY_PICTURE:
250             isExsit = highQualityPictureMap_.size() > 0 &&
251                 highQualityPictureMap_.find(imageId) != highQualityPictureMap_.end();
252             break;
253         default:
254             break;
255     }
256     return isExsit;
257 }
258 
259 // 落盘低质量图,包括低质量裸图/低质量
SaveLowQualityPicture(const std::string & imageId)260 void PictureDataOperations::SaveLowQualityPicture(const std::string& imageId)
261 {
262     MEDIA_DEBUG_LOG("enter ");
263     enum PictureType pictureType;
264     bool isSuccess = SavePicture(imageId, lowQualityPictureMap_, true);
265 }
266 
267 // 落盘低质量图,包括低质量裸图
SavePicture(const std::string & imageId,std::map<std::string,sptr<PicturePair>> & pictureMap,bool isLowQualityPicture)268 bool PictureDataOperations::SavePicture(const std::string& imageId,
269     std::map<std::string, sptr<PicturePair>>& pictureMap, bool isLowQualityPicture)
270 {
271     MEDIA_DEBUG_LOG("enter photoId: %{public}s", imageId.c_str());
272     lock_guard<mutex> lock(pictureMapMutex_);
273     bool isSuccess = false;
274     if (pictureMap.size() == 0) {
275         return false;
276     }
277     std::map<std::string, sptr<PicturePair>>::iterator iter;
278     if (imageId == "default") {
279         iter = pictureMap.begin();
280     } else {
281         iter = pictureMap.find(imageId);
282     }
283     if (iter != pictureMap.end()) {
284         FileUtils::SavePicture(iter->first, (iter->second)->picture_, false, isLowQualityPicture);
285         MEDIA_INFO_LOG("SavePicture, photoId: %{public}s", imageId.c_str());
286         // 落盘后清除缓存数据
287         pictureMap.erase(iter);
288         isSuccess = true;
289     }
290     return isSuccess;
291 }
292 
SavePictureExecutor(AsyncTaskData * data)293 void PictureDataOperations::SavePictureExecutor(AsyncTaskData *data)
294 {
295     auto *taskData = static_cast<SavePictureData *>(data);
296     auto picturePair = taskData->picturePair_;
297 
298     MEDIA_DEBUG_LOG("SavePictureExecutor %{public}d ", taskSize);
299     FileUtils::SavePicture(picturePair->photoId_, picturePair->picture_, false, true);
300     picturePair->isCleanImmediately_ = true;
301     taskSize --;
302 }
303 
AddSavePictureTask(sptr<PicturePair> & picturePair)304 int32_t PictureDataOperations::AddSavePictureTask(sptr<PicturePair>& picturePair)
305 {
306     auto asyncWorker = MediaLibraryAsyncWorker::GetInstance();
307     if (asyncWorker == nullptr) {
308         MEDIA_DEBUG_LOG("Failed to get async worker instance!");
309         return -1;
310     }
311 
312     auto *taskData = new (std::nothrow) SavePictureData(picturePair);
313     if (taskData == nullptr) {
314         MEDIA_ERR_LOG("Failed to alloc async data for downloading cloud files!");
315         return -1;
316     }
317 
318     auto asyncTask = std::make_shared<MediaLibraryAsyncTask>(SavePictureExecutor, taskData);
319     asyncWorker->AddTask(asyncTask, true);
320     taskSize ++;
321     return 0;
322 }
323 
GetPendingTaskSize()324 int32_t PictureDataOperations::GetPendingTaskSize()
325 {
326     lock_guard<mutex> lock(pictureMapMutex_);
327     return lowQualityPictureMap_.size() + highQualityPictureMap_.size();
328 }
329 
DeleteDataWithImageId(const std::string & imageId,PictureType pictureType)330 void PictureDataOperations::DeleteDataWithImageId(const std::string& imageId, PictureType pictureType)
331 {
332     MEDIA_DEBUG_LOG("enter ");
333     lock_guard<mutex> lock(pictureMapMutex_);
334     MEDIA_INFO_LOG("DeleteDataWithImageId start: %{public}s", imageId.c_str());
335     std::map<std::string, sptr<PicturePair>>::iterator iter;
336     switch (pictureType) {
337         case LOW_QUALITY_PICTURE:
338             iter = lowQualityPictureMap_.find(imageId);
339             if (iter != lowQualityPictureMap_.end()) {
340                 (iter->second)->picture_ = nullptr;
341                 lowQualityPictureMap_.erase(iter);
342             }
343             break;
344         case HIGH_QUALITY_PICTURE:
345             iter = highQualityPictureMap_.find(imageId);
346             if (iter != highQualityPictureMap_.end()) {
347                 (iter->second)->picture_ = nullptr;
348                 highQualityPictureMap_.erase(iter);
349             }
350             break;
351         default:
352             break;
353     }
354     MEDIA_DEBUG_LOG("DeleteDataWithImageId end: %{public}s", imageId.c_str());
355 }
356 
FinishAccessingPicture(const std::string & imageId,PictureType pictureType)357 void PictureDataOperations::FinishAccessingPicture(const std::string& imageId, PictureType pictureType)
358 {
359     lock_guard<mutex> lock(pictureMapMutex_);
360     MEDIA_INFO_LOG("FinishAccessingPicture start: %{public}s", imageId.c_str());
361     std::map<std::string, sptr<PicturePair>>::iterator iter;
362     switch (pictureType) {
363         case LOW_QUALITY_PICTURE:
364             iter = lowQualityPictureMap_.find(imageId);
365             if (iter != lowQualityPictureMap_.end()) {
366                 (iter->second)->isCleanImmediately_ = true;
367             }
368             break;
369         case HIGH_QUALITY_PICTURE:
370             iter = highQualityPictureMap_.find(imageId);
371             if (iter != highQualityPictureMap_.end()) {
372                 (iter->second)->isCleanImmediately_ = true;
373             }
374             break;
375         default:
376             break;
377     }
378     MEDIA_DEBUG_LOG("FinishAccessingPicture end: %{public}s", imageId.c_str());
379 }
380 } // namespace Media
381 } // namespace OHOS