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