• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define MLOG_TAG "MediaLibraryCloneRestoreCVAnalysis"
17 
18 #include "backup_database_utils.h"
19 #include "backup_file_utils.h"
20 #include "clone_restore_cv_analysis.h"
21 #include "medialibrary_data_manager_utils.h"
22 #include "media_file_utils.h"
23 #include "upgrade_restore_task_report.h"
24 
25 namespace OHOS::Media {
26 const int32_t PAGE_SIZE = 200;
27 const int32_t MAX_GENERATE_TIMES = 100000;
28 const int32_t GENERATE_GAP = 10;
29 const std::vector<std::string> EFFECTLINE_ID = { "fileId", "prefileId" };
30 const std::vector<std::string> EFFECTLINE_URI = { "fileUri", "prefileUri" };
31 const std::string EFFECTLINE_TYPE_HITCHCOCK = "TYPE_HITCHCOCK";
32 const std::string EFFECTLINE_TYPE_UAV = "TYPE_UAV";
33 const std::string EFFECTLINE_TYPE_HILIGHT_SLOW = "TYPE_HILIGHT_SLOW";
34 const std::string EFFECTLINE_TYPE_HILIGHT_CLIP = "TYPE_HILIGHT_CLIP";
35 const std::string EFFECTLINE_TYPE_MASK1 = "TYPE_MASK1";
36 const std::string EFFECTLINE_TYPE_MASK2 = "TYPE_MASK2";
37 const std::string HIGHLIGHT_ASSET_URI_PREFIX = "file://media/highlight/video/";
38 const std::string HIGHLIGHT_ASSET_URI_SUFFIX = "?oper=highlight";
39 const std::string PHOTO_URI_PREFIX = "file://media/Photo/";
40 const std::string GARBLE_DST_PATH = "/storage/media/local/files";
41 
42 const std::unordered_map<std::string, std::unordered_set<std::string>> ALBUM_COLUMNS_MAP = {
43     { "tab_analysis_label",
44         {
45             "id",
46             "file_id",
47             "category_id",
48             "sub_label",
49             "prob",
50             "feature",
51             "sim_result",
52             "label_version",
53             "saliency_sub_prob",
54             "analysis_version",
55             "duplicate_checking"
56         }
57     },
58     { "tab_analysis_saliency_detect",
59         {
60             "id",
61             "file_id",
62             "saliency_x",
63             "saliency_y",
64             "saliency_version",
65             "analysis_version"
66         }
67     },
68     { "tab_analysis_recommendation",
69         {
70             "id",
71             "file_id",
72             "recommendation_id",
73             "recommendation_resolution",
74             "recommendation_scale_x",
75             "recommendation_scale_y",
76             "recommendation_scale_width",
77             "recommendation_scale_height",
78             "recommendation_version",
79             "scale_x",
80             "scale_y",
81             "scale_width",
82             "scale_height",
83             "analysis_version",
84             "movement_crop",
85             "movement_version"
86         }
87     }
88 };
89 
90 template<typename Key, typename Value>
GetValueFromMap(const std::unordered_map<Key,Value> & map,const Key & key,const Value & defaultValue=Value ())91 Value GetValueFromMap(const std::unordered_map<Key, Value> &map, const Key &key, const Value &defaultValue = Value())
92 {
93     auto it = map.find(key);
94     CHECK_AND_RETURN_RET(it != map.end(), defaultValue);
95     return it->second;
96 }
97 
Init(int32_t sceneCode,const std::string & taskId,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,std::shared_ptr<NativeRdb::RdbStore> mediaRdb,const std::string & backupRestoreDir)98 void CloneRestoreCVAnalysis::Init(int32_t sceneCode, const std::string &taskId,
99     std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
100     std::shared_ptr<NativeRdb::RdbStore> mediaRdb, const std::string &backupRestoreDir)
101 {
102     sceneCode_ = sceneCode;
103     taskId_ = taskId;
104     mediaLibraryRdb_ = mediaLibraryRdb;
105     mediaRdb_ = mediaRdb;
106     assetPath_ = backupRestoreDir + "/storage/media/local/files/highlight/video/";
107     garblePath_ = backupRestoreDir + GARBLE_DST_PATH;
108     failCnt_ = 0;
109 }
110 
RestoreAlbums(CloneRestoreHighlight & cloneHighlight)111 void CloneRestoreCVAnalysis::RestoreAlbums(CloneRestoreHighlight &cloneHighlight)
112 {
113     CHECK_AND_RETURN_LOG(mediaRdb_ != nullptr && mediaLibraryRdb_ != nullptr, "rdbStore is nullptr.");
114     CHECK_AND_RETURN_LOG(cloneHighlight.IsCloneHighlight(), "clone highlight flag is false.");
115 
116     MEDIA_INFO_LOG("restore highlight cv analysis album start.");
117     GetAssetMapInfos(cloneHighlight);
118     GetAssetAlbumInfos(cloneHighlight);
119     UpdateHighlightPlayInfos(cloneHighlight);
120     InsertIntoAssetMap();
121     InsertIntoSdMap();
122     GetAnalysisLabelInfos(cloneHighlight);
123     InsertIntoAnalysisLabel();
124     GetAnalysisSaliencyInfos(cloneHighlight);
125     InsertIntoAnalysisSaliency();
126     GetAnalysisRecommendationInfos(cloneHighlight);
127     InsertIntoAnalysisRecommendation();
128     ReportCloneRestoreCVAnalysisTask();
129 }
130 
GetAssetMapInfos(CloneRestoreHighlight & cloneHighlight)131 void CloneRestoreCVAnalysis::GetAssetMapInfos(CloneRestoreHighlight &cloneHighlight)
132 {
133     const std::string QUERY_SQL = "SELECT * FROM tab_analysis_asset_sd_map LIMIT ?, ?";
134     int32_t rowCount = 0;
135     int32_t offset = 0;
136     do {
137         std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
138         auto resultSet = BackupDatabaseUtils::QuerySql(mediaRdb_, QUERY_SQL, params);
139         if (resultSet == nullptr) {
140             MEDIA_ERR_LOG("resultSet is nullptr");
141             break;
142         }
143 
144         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
145             int32_t oldFileId = GetInt32Val("map_asset_source", resultSet);
146             int32_t oldAssetId = GetInt32Val("map_asset_destination", resultSet);
147             sdMapDatas_.emplace_back(std::make_pair(oldFileId, oldAssetId));
148             int32_t newFileId = cloneHighlight.GetNewHighlightPhotoId(oldFileId);
149             if (assetIdMap_.count(oldAssetId) == 0) {
150                 assetIdMap_[oldAssetId] = GetNewAssetId(newFileId);
151             }
152             fileIdMap_[oldFileId] = newFileId;
153         }
154         resultSet->GetRowCount(rowCount);
155         offset += PAGE_SIZE;
156         resultSet->Close();
157     } while (rowCount > 0);
158 }
159 
GetNewAssetId(int32_t assetId)160 int32_t CloneRestoreCVAnalysis::GetNewAssetId(int32_t assetId)
161 {
162     for (size_t time = 0; time < MAX_GENERATE_TIMES; time++) {
163         std::string dirPath = "/storage/media/local/files/highlight/video/" + std::to_string(assetId);
164         if (!MediaFileUtils::IsDirectory(dirPath)) {
165             CHECK_AND_RETURN_RET(!MediaFileUtils::CreateDirectory(dirPath), assetId);
166         }
167         assetId += GENERATE_GAP;
168     }
169     MEDIA_ERR_LOG("create dirPath failed");
170     return -1;
171 }
172 
GetAssetAlbumInfos(CloneRestoreHighlight & cloneHighlight)173 void CloneRestoreCVAnalysis::GetAssetAlbumInfos(CloneRestoreHighlight &cloneHighlight)
174 {
175     const std::string QUERY_SQL = "SELECT * FROM tab_analysis_album_asset_map LIMIT ?, ?";
176     int32_t rowCount = 0;
177     int32_t offset = 0;
178     do {
179         std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
180         auto resultSet = BackupDatabaseUtils::QuerySql(mediaRdb_, QUERY_SQL, params);
181         if (resultSet == nullptr) {
182             MEDIA_ERR_LOG("resultSet is nullptr");
183             break;
184         }
185 
186         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
187             int32_t oldAlbumId = GetInt32Val("map_album", resultSet);
188             int32_t oldAssetId = GetInt32Val("map_asset", resultSet);
189             assetMapDatas_.emplace_back(std::make_pair(oldAlbumId, oldAssetId));
190             if (albumIdMap_.count(oldAlbumId) > 0) {
191                 continue;
192             }
193             albumIdMap_[oldAlbumId] = cloneHighlight.GetNewHighlightAlbumId(oldAlbumId);
194         }
195         resultSet->GetRowCount(rowCount);
196         offset += PAGE_SIZE;
197         resultSet->Close();
198     } while (rowCount > 0);
199 }
200 
InsertIntoAssetMap()201 void CloneRestoreCVAnalysis::InsertIntoAssetMap()
202 {
203     std::vector<NativeRdb::ValuesBucket> values;
204     for (auto data : assetMapDatas_) {
205         NativeRdb::ValuesBucket value;
206         value.PutInt("map_album", albumIdMap_[data.first]);
207         value.PutInt("map_asset", assetIdMap_[data.second]);
208         values.emplace_back(value);
209     }
210     int64_t rowNum = 0;
211     int32_t errCode = BatchInsertWithRetry("tab_analysis_album_asset_map", values, rowNum);
212     if (errCode != E_OK || rowNum != static_cast<int64_t>(values.size())) {
213         int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
214         MEDIA_ERR_LOG("insert into assetMap failed, num:%{public}" PRId64, failNums);
215         ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
216             "insert into AssetMap fail. num:" + std::to_string(failNums));
217         failCnt_ += failNums;
218         UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
219     }
220 }
221 
InsertIntoSdMap()222 void CloneRestoreCVAnalysis::InsertIntoSdMap()
223 {
224     std::vector<NativeRdb::ValuesBucket> values;
225     for (auto data : sdMapDatas_) {
226         NativeRdb::ValuesBucket value;
227         value.PutInt("map_asset_source", fileIdMap_[data.first]);
228         value.PutInt("map_asset_destination", assetIdMap_[data.second]);
229         values.emplace_back(value);
230     }
231     int64_t rowNum = 0;
232     int32_t errCode = BatchInsertWithRetry("tab_analysis_asset_sd_map", values, rowNum);
233     if (errCode != E_OK || rowNum != static_cast<int64_t>(values.size())) {
234         int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
235         MEDIA_ERR_LOG("insert into sdMap failed, num:%{public}" PRId64, failNums);
236         ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
237             "insert into sdMap fail. num:" + std::to_string(failNums));
238         failCnt_ += failNums;
239         UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
240     }
241 }
242 
BatchInsertWithRetry(const std::string & tableName,const std::vector<NativeRdb::ValuesBucket> & values,int64_t & rowNum)243 int32_t CloneRestoreCVAnalysis::BatchInsertWithRetry(const std::string &tableName,
244     const std::vector<NativeRdb::ValuesBucket> &values, int64_t &rowNum)
245 {
246     CHECK_AND_RETURN_RET(!values.empty(), 0);
247     int32_t errCode = E_ERR;
248     TransactionOperations trans{ __func__ };
249     trans.SetBackupRdbStore(mediaLibraryRdb_);
250     std::function<int(void)> func = [&]()->int {
251         errCode = trans.BatchInsert(rowNum, tableName, values);
252         CHECK_AND_PRINT_LOG(errCode == E_OK,
253             "InsertSql failed, errCode: %{public}d, rowNum: %{public}" PRId64, errCode, rowNum);
254         return errCode;
255     };
256     errCode = trans.RetryTrans(func, true);
257     CHECK_AND_PRINT_LOG(errCode == E_OK, "BatchInsertWithRetry: tans finish fail!, ret:%{public}d", errCode);
258     return errCode;
259 }
260 
GetAnalysisLabelInfos(CloneRestoreHighlight & cloneHighlight)261 void CloneRestoreCVAnalysis::GetAnalysisLabelInfos(CloneRestoreHighlight &cloneHighlight)
262 {
263     int32_t rowCount = 0;
264     int32_t offset = 0;
265     do {
266         const std::string QUERY_SQL = "SELECT * FROM tab_analysis_label LIMIT " + std::to_string(offset) + ", " +
267             std::to_string(PAGE_SIZE);
268         auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, QUERY_SQL);
269         if (resultSet == nullptr) {
270             MEDIA_INFO_LOG("query resultSql is null.");
271             break;
272         }
273         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
274             AnalysisLabelInfo info;
275             GetLabelRowInfo(info, resultSet);
276             if (info.fileId.has_value()) {
277                 info.fileIdNew = cloneHighlight.GetNewHighlightPhotoId(info.fileId.value());
278             }
279             labelInfos_.emplace_back(info);
280         }
281         resultSet->GetRowCount(rowCount);
282         offset += PAGE_SIZE;
283         resultSet->Close();
284     } while (rowCount > 0);
285     MEDIA_INFO_LOG("query tab_analysis_label nums: %{public}zu", labelInfos_.size());
286 }
287 
GetLabelRowInfo(AnalysisLabelInfo & info,std::shared_ptr<NativeRdb::ResultSet> resultSet)288 void CloneRestoreCVAnalysis::GetLabelRowInfo(AnalysisLabelInfo &info, std::shared_ptr<NativeRdb::ResultSet> resultSet)
289 {
290     if (intersectionMap_.find("tab_analysis_label") == intersectionMap_.end()) {
291         intersectionMap_.insert(std::make_pair("tab_analysis_label", GetCommonColumns("tab_analysis_label")));
292     }
293     std::unordered_set<std::string>& intersection = intersectionMap_["tab_analysis_label"];
294     CloneRestoreHighlight::GetIfInIntersection("id", info.id, intersection, resultSet);
295     CloneRestoreHighlight::GetIfInIntersection("file_id", info.fileId, intersection, resultSet);
296     CloneRestoreHighlight::GetIfInIntersection("category_id", info.categoryId, intersection, resultSet);
297     CloneRestoreHighlight::GetIfInIntersection("sub_label", info.subLabel, intersection, resultSet);
298     CloneRestoreHighlight::GetIfInIntersection("prob", info.prob, intersection, resultSet);
299     CloneRestoreHighlight::GetIfInIntersection("feature", info.feature, intersection, resultSet);
300     CloneRestoreHighlight::GetIfInIntersection("sim_result", info.simResult, intersection, resultSet);
301     CloneRestoreHighlight::GetIfInIntersection("label_version", info.labelVersion, intersection, resultSet);
302     CloneRestoreHighlight::GetIfInIntersection("saliency_sub_prob", info.saliencySubprob, intersection, resultSet);
303     CloneRestoreHighlight::GetIfInIntersection("analysis_version", info.analysisVersion, intersection, resultSet);
304     CloneRestoreHighlight::GetIfInIntersection("duplicate_checking", info.duplicateChecking, intersection, resultSet);
305 }
306 
InsertIntoAnalysisLabel()307 void CloneRestoreCVAnalysis::InsertIntoAnalysisLabel()
308 {
309     size_t offset = 0;
310     do {
311         std::vector<NativeRdb::ValuesBucket> values;
312         for (size_t index = 0; index < PAGE_SIZE && index + offset < labelInfos_.size(); index++) {
313             NativeRdb::ValuesBucket value;
314             GetLabelInsertValue(value, labelInfos_[index + offset]);
315             values.emplace_back(value);
316         }
317         int64_t rowNum = 0;
318         int32_t errCode = BatchInsertWithRetry("tab_analysis_label", values, rowNum);
319         if (errCode != E_OK || rowNum != static_cast<int64_t>(values.size())) {
320             int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
321             MEDIA_ERR_LOG("insert into tab_analysis_label fail, num: %{public}" PRId64, failNums);
322             ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
323                 "insert into tab_analysis_label fail, num:" + std::to_string(failNums));
324             failCnt_ += failNums;
325             UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
326         }
327         offset += PAGE_SIZE;
328     } while (offset < labelInfos_.size());
329 }
330 
GetLabelInsertValue(NativeRdb::ValuesBucket & value,const AnalysisLabelInfo & info)331 void CloneRestoreCVAnalysis::GetLabelInsertValue(NativeRdb::ValuesBucket &value, const AnalysisLabelInfo &info)
332 {
333     std::unordered_set<std::string>& intersection = intersectionMap_["tab_analysis_label"];
334     CloneRestoreHighlight::PutIfInIntersection(value, "file_id", info.fileIdNew, intersection);
335     CloneRestoreHighlight::PutIfInIntersection(value, "category_id", info.categoryId, intersection);
336     CloneRestoreHighlight::PutIfInIntersection(value, "sub_label", info.subLabel, intersection);
337     CloneRestoreHighlight::PutIfInIntersection(value, "prob", info.prob, intersection);
338     CloneRestoreHighlight::PutIfInIntersection(value, "feature", info.feature, intersection);
339     CloneRestoreHighlight::PutIfInIntersection(value, "sim_result", info.simResult, intersection);
340     CloneRestoreHighlight::PutIfInIntersection(value, "label_version", info.labelVersion, intersection);
341     CloneRestoreHighlight::PutIfInIntersection(value, "saliency_sub_prob", info.saliencySubprob, intersection);
342     CloneRestoreHighlight::PutIfInIntersection(value, "analysis_version", info.analysisVersion, intersection);
343     CloneRestoreHighlight::PutIfInIntersection(value, "duplicate_checking", info.duplicateChecking, intersection);
344 }
345 
GetCommonColumns(const std::string & tableName)346 std::unordered_set<std::string> CloneRestoreCVAnalysis::GetCommonColumns(const std::string &tableName)
347 {
348     std::unordered_map<std::string, std::string> srcColumnInfoMap =
349         BackupDatabaseUtils::GetColumnInfoMap(mediaRdb_, tableName);
350     std::unordered_map<std::string, std::string> dstColumnInfoMap =
351         BackupDatabaseUtils::GetColumnInfoMap(mediaLibraryRdb_, tableName);
352     std::unordered_set<std::string> result;
353     auto comparedColumns = GetValueFromMap(ALBUM_COLUMNS_MAP, tableName);
354     for (auto it = dstColumnInfoMap.begin(); it != dstColumnInfoMap.end(); ++it) {
355         if (srcColumnInfoMap.find(it->first) != srcColumnInfoMap.end() && comparedColumns.count(it->first) > 0) {
356             result.insert(it->first);
357         }
358     }
359     return result;
360 }
361 
GetAnalysisSaliencyInfos(CloneRestoreHighlight & cloneHighlight)362 void CloneRestoreCVAnalysis::GetAnalysisSaliencyInfos(CloneRestoreHighlight &cloneHighlight)
363 {
364     int32_t rowCount = 0;
365     int32_t offset = 0;
366     do {
367         const std::string QUERY_SQL = "SELECT * FROM tab_analysis_saliency_detect LIMIT " + std::to_string(offset) +
368             ", " + std::to_string(PAGE_SIZE);
369         auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, QUERY_SQL);
370         if (resultSet == nullptr) {
371             MEDIA_INFO_LOG("query resultSql is null.");
372             break;
373         }
374         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
375             AnalysisSaliencyInfo info;
376             GetSaliencyRowInfo(info, resultSet);
377             if (info.fileId.has_value()) {
378                 info.fileIdNew = cloneHighlight.GetNewHighlightPhotoId(info.fileId.value());
379             }
380             saliencyInfos_.emplace_back(info);
381         }
382         resultSet->GetRowCount(rowCount);
383         offset += PAGE_SIZE;
384         resultSet->Close();
385     } while (rowCount > 0);
386     MEDIA_INFO_LOG("query tab_analysis_saliency_detect nums: %{public}zu", saliencyInfos_.size());
387 }
388 
GetSaliencyRowInfo(AnalysisSaliencyInfo & info,std::shared_ptr<NativeRdb::ResultSet> resultSet)389 void CloneRestoreCVAnalysis::GetSaliencyRowInfo(AnalysisSaliencyInfo &info,
390     std::shared_ptr<NativeRdb::ResultSet> resultSet)
391 {
392     if (intersectionMap_.find("tab_analysis_saliency_detect") == intersectionMap_.end()) {
393         intersectionMap_.insert(
394             std::make_pair("tab_analysis_saliency_detect", GetCommonColumns("tab_analysis_saliency_detect")));
395     }
396     std::unordered_set<std::string>& intersection = intersectionMap_["tab_analysis_saliency_detect"];
397     CloneRestoreHighlight::GetIfInIntersection("id", info.id, intersection, resultSet);
398     CloneRestoreHighlight::GetIfInIntersection("file_id", info.fileId, intersection, resultSet);
399     CloneRestoreHighlight::GetIfInIntersection("saliency_x", info.saliencyX, intersection, resultSet);
400     CloneRestoreHighlight::GetIfInIntersection("saliency_y", info.saliencyY, intersection, resultSet);
401     CloneRestoreHighlight::GetIfInIntersection("saliency_version", info.saliencyVersion, intersection, resultSet);
402     CloneRestoreHighlight::GetIfInIntersection("analysis_version", info.analysisVersion, intersection, resultSet);
403 }
404 
InsertIntoAnalysisSaliency()405 void CloneRestoreCVAnalysis::InsertIntoAnalysisSaliency()
406 {
407     size_t offset = 0;
408     do {
409         std::vector<NativeRdb::ValuesBucket> values;
410         for (size_t index = 0; index < PAGE_SIZE && index + offset < saliencyInfos_.size(); index++) {
411             NativeRdb::ValuesBucket value;
412             GetSaliencyInsertValue(value, saliencyInfos_[index + offset]);
413             values.emplace_back(value);
414         }
415         int64_t rowNum = 0;
416         int32_t errCode = BatchInsertWithRetry("tab_analysis_saliency_detect", values, rowNum);
417         if (errCode != E_OK || rowNum != static_cast<int64_t>(values.size())) {
418             int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
419             MEDIA_ERR_LOG("insert into tab_analysis_saliency_detect fail, num: %{public}" PRId64, failNums);
420             ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
421                 "insert into tab_analysis_saliency_detect fail, num:" + std::to_string(failNums));
422             failCnt_ += failNums;
423             UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
424         }
425         offset += PAGE_SIZE;
426     } while (offset < saliencyInfos_.size());
427 }
428 
GetSaliencyInsertValue(NativeRdb::ValuesBucket & value,const AnalysisSaliencyInfo & info)429 void CloneRestoreCVAnalysis::GetSaliencyInsertValue(NativeRdb::ValuesBucket &value, const AnalysisSaliencyInfo &info)
430 {
431     std::unordered_set<std::string>& intersection = intersectionMap_["tab_analysis_saliency_detect"];
432     CloneRestoreHighlight::PutIfInIntersection(value, "file_id", info.fileIdNew, intersection);
433     CloneRestoreHighlight::PutIfInIntersection(value, "saliency_x", info.saliencyX, intersection);
434     CloneRestoreHighlight::PutIfInIntersection(value, "saliency_y", info.saliencyY, intersection);
435     CloneRestoreHighlight::PutIfInIntersection(value, "saliency_version", info.saliencyVersion, intersection);
436     CloneRestoreHighlight::PutIfInIntersection(value, "analysis_version", info.analysisVersion, intersection);
437 }
438 
GetAnalysisRecommendationInfos(CloneRestoreHighlight & cloneHighlight)439 void CloneRestoreCVAnalysis::GetAnalysisRecommendationInfos(CloneRestoreHighlight &cloneHighlight)
440 {
441     int32_t rowCount = 0;
442     int32_t offset = 0;
443     do {
444         const std::string QUERY_SQL = "SELECT * FROM tab_analysis_recommendation LIMIT " + std::to_string(offset) +
445             ", " + std::to_string(PAGE_SIZE);
446         auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, QUERY_SQL);
447         if (resultSet == nullptr) {
448             MEDIA_INFO_LOG("query resultSql is null.");
449             break;
450         }
451         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
452             AnalysisRecommendationInfo info;
453             GetRecommendationRowInfo(info, resultSet);
454             if (info.fileId.has_value()) {
455                 info.fileIdNew = cloneHighlight.GetNewHighlightPhotoId(info.fileId.value());
456             }
457             recommendInfos_.emplace_back(info);
458         }
459         resultSet->GetRowCount(rowCount);
460         offset += PAGE_SIZE;
461         resultSet->Close();
462     } while (rowCount > 0);
463     MEDIA_INFO_LOG("query tab_analysis_recommendation nums: %{public}zu", recommendInfos_.size());
464 }
465 
GetRecommendationRowInfo(AnalysisRecommendationInfo & info,std::shared_ptr<NativeRdb::ResultSet> resultSet)466 void CloneRestoreCVAnalysis::GetRecommendationRowInfo(AnalysisRecommendationInfo &info,
467     std::shared_ptr<NativeRdb::ResultSet> resultSet)
468 {
469     if (intersectionMap_.find("tab_analysis_recommendation") == intersectionMap_.end()) {
470         intersectionMap_.insert(
471             std::make_pair("tab_analysis_recommendation", GetCommonColumns("tab_analysis_recommendation")));
472     }
473     std::unordered_set<std::string>& intersection = intersectionMap_["tab_analysis_recommendation"];
474     CloneRestoreHighlight::GetIfInIntersection("id", info.id, intersection, resultSet);
475     CloneRestoreHighlight::GetIfInIntersection("file_id", info.fileId, intersection, resultSet);
476     CloneRestoreHighlight::GetIfInIntersection("recommendation_id", info.rcmdId, intersection, resultSet);
477     CloneRestoreHighlight::GetIfInIntersection("recommendation_resolution", info.rcmdResolution, intersection,
478         resultSet);
479     CloneRestoreHighlight::GetIfInIntersection("recommendation_scale_x", info.rcmdScaleX, intersection, resultSet);
480     CloneRestoreHighlight::GetIfInIntersection("recommendation_scale_y", info.rcmdScaleY, intersection, resultSet);
481     CloneRestoreHighlight::GetIfInIntersection("recommendation_scale_width", info.rcmdScaleWidth, intersection,
482         resultSet);
483     CloneRestoreHighlight::GetIfInIntersection("recommendation_scale_height", info.rcmdScaleHeight, intersection,
484         resultSet);
485     CloneRestoreHighlight::GetIfInIntersection("recommendation_version", info.rcmdVersion, intersection, resultSet);
486     CloneRestoreHighlight::GetIfInIntersection("scale_x", info.scaleX, intersection, resultSet);
487     CloneRestoreHighlight::GetIfInIntersection("scale_y", info.scaleY, intersection, resultSet);
488     CloneRestoreHighlight::GetIfInIntersection("scale_width", info.scaleWidth, intersection, resultSet);
489     CloneRestoreHighlight::GetIfInIntersection("scale_height", info.scaleHeight, intersection, resultSet);
490     CloneRestoreHighlight::GetIfInIntersection("analysis_version", info.analysisVersion, intersection, resultSet);
491     CloneRestoreHighlight::GetIfInIntersection("movement_crop", info.movementCrop, intersection, resultSet);
492     CloneRestoreHighlight::GetIfInIntersection("movement_version", info.movementVersion, intersection, resultSet);
493 }
494 
InsertIntoAnalysisRecommendation()495 void CloneRestoreCVAnalysis::InsertIntoAnalysisRecommendation()
496 {
497     size_t offset = 0;
498     do {
499         std::vector<NativeRdb::ValuesBucket> values;
500         for (size_t index = 0; index < PAGE_SIZE && index + offset < recommendInfos_.size(); index++) {
501             NativeRdb::ValuesBucket value;
502             GetRecommendationInsertValue(value, recommendInfos_[index + offset]);
503             values.emplace_back(value);
504         }
505         int64_t rowNum = 0;
506         int32_t errCode = BatchInsertWithRetry("tab_analysis_recommendation", values, rowNum);
507         if (errCode != E_OK || rowNum != static_cast<int64_t>(values.size())) {
508             int64_t failNums = static_cast<int64_t>(values.size()) - rowNum;
509             MEDIA_ERR_LOG("insert into tab_analysis_recommendation fail, num: %{public}" PRId64, failNums);
510             ErrorInfo errorInfo(RestoreError::INSERT_FAILED, 0, std::to_string(errCode),
511                 "insert into tab_analysis_recommendation fail, num:" + std::to_string(failNums));
512             failCnt_ += failNums;
513             UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_).ReportError(errorInfo);
514         }
515         offset += PAGE_SIZE;
516     } while (offset < recommendInfos_.size());
517 }
518 
GetRecommendationInsertValue(NativeRdb::ValuesBucket & value,const AnalysisRecommendationInfo & info)519 void CloneRestoreCVAnalysis::GetRecommendationInsertValue(NativeRdb::ValuesBucket &value,
520     const AnalysisRecommendationInfo &info)
521 {
522     std::unordered_set<std::string>& intersection = intersectionMap_["tab_analysis_recommendation"];
523     CloneRestoreHighlight::PutIfInIntersection(value, "file_id", info.fileIdNew, intersection);
524     CloneRestoreHighlight::PutIfInIntersection(value, "recommendation_id", info.rcmdId, intersection);
525     CloneRestoreHighlight::PutIfInIntersection(value, "recommendation_resolution", info.rcmdResolution, intersection);
526     CloneRestoreHighlight::PutIfInIntersection(value, "recommendation_scale_x", info.rcmdScaleX, intersection);
527     CloneRestoreHighlight::PutIfInIntersection(value, "recommendation_scale_y", info.rcmdScaleY, intersection);
528     CloneRestoreHighlight::PutIfInIntersection(value, "recommendation_scale_width", info.rcmdScaleWidth, intersection);
529     CloneRestoreHighlight::PutIfInIntersection(value, "recommendation_scale_height", info.rcmdScaleHeight,
530         intersection);
531     CloneRestoreHighlight::PutIfInIntersection(value, "recommendation_version", info.rcmdVersion, intersection);
532     CloneRestoreHighlight::PutIfInIntersection(value, "scale_x", info.scaleX, intersection);
533     CloneRestoreHighlight::PutIfInIntersection(value, "scale_y", info.scaleY, intersection);
534     CloneRestoreHighlight::PutIfInIntersection(value, "scale_width", info.scaleWidth, intersection);
535     CloneRestoreHighlight::PutIfInIntersection(value, "scale_height", info.scaleHeight, intersection);
536     CloneRestoreHighlight::PutIfInIntersection(value, "analysis_version", info.analysisVersion, intersection);
537     CloneRestoreHighlight::PutIfInIntersection(value, "movement_crop", info.movementCrop, intersection);
538     CloneRestoreHighlight::PutIfInIntersection(value, "movement_version", info.movementVersion, intersection);
539 }
540 
ParsePlayInfo(const std::string & oldPlayInfo,CloneRestoreHighlight & cloneHighlight)541 std::string CloneRestoreCVAnalysis::ParsePlayInfo(const std::string &oldPlayInfo, CloneRestoreHighlight &cloneHighlight)
542 {
543     nlohmann::json newPlayInfo = nlohmann::json::parse(oldPlayInfo, nullptr, false);
544     CHECK_AND_RETURN_RET_LOG(!newPlayInfo.is_discarded(), "", "parse json string failed.");
545     if (newPlayInfo["effectline"].contains("effectline")) {
546         for (size_t effectlineIndex = 0; effectlineIndex < newPlayInfo["effectline"]["effectline"].size();
547             effectlineIndex++) {
548             ParseEffectline(newPlayInfo, effectlineIndex, cloneHighlight);
549         }
550     }
551 
552     if (newPlayInfo.contains("timeline")) {
553         for (size_t timelineIndex = 0; timelineIndex < newPlayInfo["timeline"].size(); timelineIndex++) {
554             std::string oldEffectVideoUri = newPlayInfo["timeline"][timelineIndex]["effectVideoUri"];
555             newPlayInfo["timeline"][timelineIndex]["effectVideoUri"] = GetValueFromMap(assetUriMap_, oldEffectVideoUri);
556 
557             std::string oldTransVideoUri = newPlayInfo["timeline"][timelineIndex]["transitionVideoUri"];
558             newPlayInfo["timeline"][timelineIndex]["transitionVideoUri"] =
559                 GetValueFromMap(assetUriMap_, oldTransVideoUri);
560 
561             std::vector<int32_t> newFileIds;
562             for (size_t idIndex = 0; idIndex < newPlayInfo["timeline"][timelineIndex]["fileId"].size(); idIndex++) {
563                 int32_t oldFileId = newPlayInfo["timeline"][timelineIndex]["fileId"][idIndex];
564                 newFileIds.emplace_back(cloneHighlight.GetNewHighlightPhotoId(oldFileId));
565                 newPlayInfo["timeline"][timelineIndex]["fileId"][idIndex] = newFileIds[idIndex];
566             }
567 
568             for (size_t uriIndex = 0; uriIndex < newPlayInfo["timeline"][timelineIndex]["fileUri"].size(); uriIndex++) {
569                 std::string newFileUri = cloneHighlight.GetNewHighlightPhotoUri(newFileIds[uriIndex]);
570                 newPlayInfo["timeline"][timelineIndex]["fileUri"][uriIndex] = newFileUri;
571             }
572         }
573     }
574     return newPlayInfo.dump();
575 }
576 
ParseEffectline(nlohmann::json & newPlayInfo,size_t effectlineIndex,CloneRestoreHighlight & cloneHighlight)577 void CloneRestoreCVAnalysis::ParseEffectline(nlohmann::json &newPlayInfo, size_t effectlineIndex,
578     CloneRestoreHighlight &cloneHighlight)
579 {
580     std::string oldEffectVideoUri = newPlayInfo["effectline"]["effectline"][effectlineIndex]["effectVideoUri"];
581     if (MediaFileUtils::StartsWith(oldEffectVideoUri, PHOTO_URI_PREFIX)) {
582         newPlayInfo["effectline"]["effectline"][effectlineIndex]["effectVideoUri"] =
583             GetNewPhotoUriByUri(oldEffectVideoUri, cloneHighlight);
584     } else if (MediaFileUtils::StartsWith(oldEffectVideoUri, HIGHLIGHT_ASSET_URI_PREFIX)) {
585         newPlayInfo["effectline"]["effectline"][effectlineIndex]["effectVideoUri"] =
586             GetNewEffectVideoUri(oldEffectVideoUri);
587     }
588 
589     if (newPlayInfo["effectline"]["effectline"][effectlineIndex]["effect"] == EFFECTLINE_TYPE_MASK2) {
590         std::string transVideoUri = GetNewTransitionVideoUri(
591             newPlayInfo["effectline"]["effectline"][effectlineIndex]["transitionVideoUri"], cloneHighlight);
592         newPlayInfo["effectline"]["effectline"][effectlineIndex]["transitionVideoUri"] = transVideoUri;
593 
594         if (effectlineIndex > 0 &&
595             newPlayInfo["effectline"]["effectline"][effectlineIndex - 1]["effect"] == EFFECTLINE_TYPE_MASK1) {
596             newPlayInfo["effectline"]["effectline"][effectlineIndex - 1]["transitionVideoUri"] = transVideoUri;
597         }
598     }
599 
600     for (size_t infoIndex = 0; infoIndex < EFFECTLINE_ID.size(); infoIndex++) {
601         std::vector<int32_t> newFileIds;
602         for (size_t idIndex = 0;
603             idIndex < newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_ID[infoIndex]].size();
604             idIndex++) {
605             int32_t oldFileId =
606                 newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_ID[infoIndex]][idIndex];
607             newFileIds.emplace_back(cloneHighlight.GetNewHighlightPhotoId(oldFileId));
608             newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_ID[infoIndex]][idIndex] =
609                 newFileIds[idIndex];
610         }
611 
612         for (size_t uriIndex = 0;
613             uriIndex < newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_URI[infoIndex]].size();
614             uriIndex++) {
615             if (uriIndex >= newFileIds.size()) {
616                 break;
617             }
618             std::string newFileUri = cloneHighlight.GetNewHighlightPhotoUri(newFileIds[uriIndex]);
619             newPlayInfo["effectline"]["effectline"][effectlineIndex][EFFECTLINE_URI[infoIndex]][uriIndex] = newFileUri;
620         }
621     }
622 }
623 
GetNewEffectVideoUri(const std::string & oldVideoUri)624 std::string CloneRestoreCVAnalysis::GetNewEffectVideoUri(const std::string &oldVideoUri)
625 {
626     CHECK_AND_RETURN_RET(oldVideoUri != "", "");
627     size_t rightIndex = oldVideoUri.rfind("/");
628     CHECK_AND_RETURN_RET(rightIndex != std::string::npos && rightIndex > 0, "");
629     size_t leftIndex = oldVideoUri.rfind("/", rightIndex - 1);
630     CHECK_AND_RETURN_RET(leftIndex != std::string::npos && rightIndex > leftIndex + 1, "");
631     int32_t oldAssetId = std::atoi((oldVideoUri.substr(leftIndex + 1, rightIndex - leftIndex - 1)).c_str());
632     int32_t newAssetId = assetIdMap_[oldAssetId];
633 
634     size_t suffixLeftIndex = oldVideoUri.find("_", rightIndex);
635     CHECK_AND_RETURN_RET(suffixLeftIndex != std::string::npos, "");
636     size_t suffixRightIndex = oldVideoUri.find("?", suffixLeftIndex);
637     CHECK_AND_RETURN_RET(suffixRightIndex != std::string::npos && suffixRightIndex > suffixLeftIndex, "");
638     std::string suffix = oldVideoUri.substr(suffixLeftIndex, suffixRightIndex - suffixLeftIndex);
639     std::string newVideoUri = HIGHLIGHT_ASSET_URI_PREFIX + std::to_string(newAssetId)
640         + "/" + std::to_string(newAssetId) + suffix + HIGHLIGHT_ASSET_URI_SUFFIX;
641 
642     assetUriMap_.insert(std::make_pair(oldVideoUri, newVideoUri));
643     std::string dstPath = "/storage/media/local/files/highlight/video/" + std::to_string(newAssetId) + "/" +
644         std::to_string(newAssetId) + suffix;
645     std::string srcPath = assetPath_ + std::to_string(oldAssetId) + "/" + std::to_string(oldAssetId) + suffix;
646     MoveAnalysisAssets(srcPath, dstPath);
647     return newVideoUri;
648 }
649 
GetNewTransitionVideoUri(const std::string & oldVideoUri,CloneRestoreHighlight & cloneHighlight)650 std::string CloneRestoreCVAnalysis::GetNewTransitionVideoUri(const std::string &oldVideoUri,
651     CloneRestoreHighlight &cloneHighlight)
652 {
653     CHECK_AND_RETURN_RET(oldVideoUri != "", "");
654     size_t rightIndex = oldVideoUri.rfind("/");
655     CHECK_AND_RETURN_RET(rightIndex != std::string::npos && rightIndex > 0, "");
656     size_t leftIndex = oldVideoUri.rfind("/", rightIndex - 1);
657     CHECK_AND_RETURN_RET(leftIndex != std::string::npos && rightIndex > leftIndex + 1, "");
658     int32_t oldAssetId = std::atoi((oldVideoUri.substr(leftIndex + 1, rightIndex - leftIndex - 1)).c_str());
659     int32_t newAssetId = assetIdMap_[oldAssetId];
660 
661     size_t secondLeftIndex = oldVideoUri.find("_", rightIndex);
662     CHECK_AND_RETURN_RET(secondLeftIndex != std::string::npos, "");
663     size_t secondRightIndex = oldVideoUri.find("_", secondLeftIndex + 1);
664     CHECK_AND_RETURN_RET(secondRightIndex != std::string::npos && secondRightIndex > secondLeftIndex + 1, "");
665     int32_t oldNextAssetId = std::atoi((oldVideoUri.substr(secondLeftIndex + 1,
666         secondRightIndex - secondLeftIndex - 1)).c_str());
667     int32_t newNextPhotoId = cloneHighlight.GetNewHighlightPhotoId(oldNextAssetId);
668 
669     size_t suffixRightIndex = oldVideoUri.find("?", secondRightIndex);
670     CHECK_AND_RETURN_RET(suffixRightIndex != std::string::npos && suffixRightIndex > secondRightIndex, "");
671     std::string suffix = oldVideoUri.substr(secondRightIndex, suffixRightIndex - secondRightIndex);
672 
673     std::string newVideoUri = HIGHLIGHT_ASSET_URI_PREFIX + std::to_string(newAssetId) + "/" +
674         std::to_string(newAssetId) + "_" + std::to_string(newNextPhotoId) + suffix + HIGHLIGHT_ASSET_URI_SUFFIX;
675     assetUriMap_.insert(std::make_pair(oldVideoUri, newVideoUri));
676 
677     std::string dstPath = "/storage/media/local/files/highlight/video/" + std::to_string(newAssetId) + "/" +
678         std::to_string(newAssetId) + suffix;
679     std::string srcPath = assetPath_ + std::to_string(oldAssetId) + "/" + std::to_string(oldAssetId) + suffix;
680     MoveAnalysisAssets(srcPath, dstPath);
681     return newVideoUri;
682 }
683 
GetNewPhotoUriByUri(const std::string & oldUri,CloneRestoreHighlight & cloneHighlight)684 std::string CloneRestoreCVAnalysis::GetNewPhotoUriByUri(const std::string &oldUri,
685     CloneRestoreHighlight &cloneHighlight)
686 {
687     CHECK_AND_RETURN_RET(oldUri != "", "");
688     size_t rightIndex = oldUri.rfind("/");
689     CHECK_AND_RETURN_RET(rightIndex != std::string::npos && rightIndex > 0, "");
690     rightIndex = oldUri.rfind("/", rightIndex - 1);
691     CHECK_AND_RETURN_RET(rightIndex != std::string::npos && rightIndex > 0, "");
692     size_t leftIndex = oldUri.rfind("/", rightIndex - 1);
693     CHECK_AND_RETURN_RET(leftIndex != std::string::npos && rightIndex > leftIndex + 1, "");
694 
695     int32_t oldPhotoId = std::atoi((oldUri.substr(leftIndex + 1, rightIndex - leftIndex - 1)).c_str());
696     int32_t newPhotoId = cloneHighlight.GetNewHighlightPhotoId(oldPhotoId);
697     std::string newUri = cloneHighlight.GetNewHighlightPhotoUri(newPhotoId);
698     assetUriMap_.insert(std::make_pair(oldUri, newUri));
699     return newUri;
700 }
701 
MoveAnalysisAssets(const std::string & srcPath,const std::string & dstPath)702 void CloneRestoreCVAnalysis::MoveAnalysisAssets(const std::string &srcPath, const std::string &dstPath)
703 {
704     int32_t errCode = BackupFileUtils::MoveFile(srcPath.c_str(), dstPath.c_str(), sceneCode_);
705     if (errCode != E_OK) {
706         MEDIA_ERR_LOG("move file failed, srcPath:%{public}s, dstPath:%{public}s, errcode:%{public}d",
707             BackupFileUtils::GarbleFilePath(srcPath, sceneCode_, garblePath_).c_str(),
708             BackupFileUtils::GarbleFilePath(dstPath, sceneCode_, GARBLE_DST_PATH).c_str(), errCode);
709     }
710 }
711 
UpdateHighlightPlayInfos(CloneRestoreHighlight & cloneHighlight)712 void CloneRestoreCVAnalysis::UpdateHighlightPlayInfos(CloneRestoreHighlight &cloneHighlight)
713 {
714     int32_t rowCount = 0;
715     int32_t offset = 0;
716     do {
717         const std::string QUERY_SQL = "SELECT album_id, play_info_id, play_info FROM tab_highlight_play_info LIMIT "
718             + std::to_string(offset) + ", " + std::to_string(PAGE_SIZE);
719         auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, QUERY_SQL);
720         CHECK_AND_RETURN_INFO_LOG(resultSet != nullptr, "query resultSql is null.");
721 
722         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
723             std::optional<int32_t> oldAlbumId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "album_id");
724             if (!oldAlbumId.has_value()) {
725                 continue;
726             }
727             std::optional<int32_t> playId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, "play_info_id");
728             std::optional<std::string> oldPlayInfo =
729                 BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, "play_info");
730             std::string newPlayInfo = "null";
731             if (oldPlayInfo.has_value()) {
732                 newPlayInfo = ParsePlayInfo(oldPlayInfo.value(), cloneHighlight);
733             }
734             int32_t albumId = cloneHighlight.GetNewHighlightAlbumId(oldAlbumId.value());
735             std::string updatePlayInfoSql = "UPDATE tab_highlight_play_info SET play_info = ? "
736                 " WHERE album_id = ? ";
737             int32_t ret = E_ERR;
738             if (playId.has_value()) {
739                 std::string playInfoId = std::to_string(playId.value());
740                 updatePlayInfoSql += "AND play_info_id = ?";
741                 ret = BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, updatePlayInfoSql,
742                     { newPlayInfo, albumId, playInfoId });
743             } else {
744                 updatePlayInfoSql += "AND play_info_id ISNULL";
745                 ret = BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, updatePlayInfoSql,
746                     { newPlayInfo, albumId });
747             }
748             CHECK_AND_PRINT_LOG(ret == E_OK, "executeSql err, errCode: %{public}d", ret);
749         }
750         resultSet->GetRowCount(rowCount);
751         offset += PAGE_SIZE;
752         resultSet->Close();
753     } while (rowCount > 0);
754 }
755 
ReportCloneRestoreCVAnalysisTask()756 void CloneRestoreCVAnalysis::ReportCloneRestoreCVAnalysisTask()
757 {
758     const int32_t ERR_STATUS = 1;
759     MEDIA_INFO_LOG("Highlight restore failCnt_: %{public}" PRId64, failCnt_);
760     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
761         .Report("Highlight restore", std::to_string(ERR_STATUS), "failCnt_: " + std::to_string(failCnt_));
762 }
763 } // namespace OHOS::Media