1 /*
2 * Copyright (C) 2021 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 #include "media_library.h"
17
18 #include <cerrno>
19 #include <dirent.h>
20 #include <ftw.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <unordered_set>
24
25 #include "media_lib_service_const.h"
26 #include "media_library_utils.h"
27 #include "media_log.h"
28
29 using namespace std;
30
31 namespace OHOS {
32 namespace Media {
33 #define CHK_NULL_RETURN(ptr) \
34 do { \
35 if ((ptr) == nullptr) { \
36 return MEDIA_SCAN_FAIL; \
37 } \
38 } while (0)
39
40 #define CHK_NULL_RETURN_ERROR(ptr, ret) \
41 do { \
42 if ((ptr) == nullptr) { \
43 return ret; \
44 } \
45 } while (0)
46
MediaLibrary()47 MediaLibrary::MediaLibrary() {}
48
49 MediaLibrary::~MediaLibrary() = default;
50
GetMediaLibraryInstance()51 unique_ptr<MediaLibrary> MediaLibrary::GetMediaLibraryInstance()
52 {
53 return make_unique<MediaLibrary>();
54 }
55
GetNameFromUri(const string & uri)56 string GetNameFromUri(const string &uri)
57 {
58 string fileName = DEFAULT_MEDIA_NAME;
59
60 size_t slashIndex = uri.rfind(SLASH_CHAR);
61 if (slashIndex != string::npos) {
62 if (uri.size() > slashIndex) {
63 fileName = uri.substr(slashIndex + 1, uri.length() - slashIndex);
64 }
65 }
66
67 return fileName;
68 }
69
UpdateMediaData(const string & assetUri,const struct stat & statInfo)70 unique_ptr<MediaAsset> UpdateMediaData(const string &assetUri, const struct stat &statInfo)
71 {
72 if (assetUri.empty()) {
73 MEDIA_ERR_LOG("Uri is empty!");
74 return nullptr;
75 }
76
77 unique_ptr<MediaAsset> mediaAsset = make_unique<MediaAsset>();
78 mediaAsset->uri_ = assetUri;
79 mediaAsset->name_ = GetNameFromUri(assetUri);
80 mediaAsset->mediaType_ = MEDIA_TYPE_FILE;
81 mediaAsset->size_ = statInfo.st_size;
82 mediaAsset->dateModified_ = statInfo.st_mtime * MILLISECONDS;
83 mediaAsset->dateAdded_ = statInfo.st_ctime * MILLISECONDS;
84
85 return mediaAsset;
86 }
87
UpdateAudioData(const string & assetUri,const struct stat & statInfo)88 unique_ptr<AudioAsset> UpdateAudioData(const string &assetUri, const struct stat &statInfo)
89 {
90 if (assetUri.empty()) {
91 MEDIA_ERR_LOG("Uri is empty!");
92 return nullptr;
93 }
94
95 unique_ptr<AudioAsset> audioAsset = make_unique<AudioAsset>();
96 audioAsset->uri_ = assetUri;
97 audioAsset->name_ = GetNameFromUri(assetUri);
98 audioAsset->mediaType_ = MEDIA_TYPE_AUDIO;
99 audioAsset->size_ = statInfo.st_size;
100 audioAsset->dateModified_ = statInfo.st_mtime * MILLISECONDS;
101 audioAsset->dateAdded_ = statInfo.st_ctime * MILLISECONDS;
102
103 return audioAsset;
104 }
105
UpdateVideoData(const string & assetUri,const struct stat & statInfo)106 unique_ptr<VideoAsset> UpdateVideoData(const string &assetUri, const struct stat &statInfo)
107 {
108 if (assetUri.empty()) {
109 MEDIA_ERR_LOG("Uri is empty!");
110 return nullptr;
111 }
112
113 unique_ptr<VideoAsset> videoAsset = make_unique<VideoAsset>();
114 videoAsset->uri_ = assetUri;
115 videoAsset->name_ = GetNameFromUri(assetUri);
116 videoAsset->mediaType_ = MEDIA_TYPE_VIDEO;
117 videoAsset->size_ = statInfo.st_size;
118 videoAsset->dateModified_ = statInfo.st_mtime * MILLISECONDS;
119 videoAsset->dateAdded_ = statInfo.st_ctime * MILLISECONDS;
120
121 return videoAsset;
122 }
123
UpdateImageData(const string & assetUri,const struct stat & statInfo)124 unique_ptr<ImageAsset> UpdateImageData(const string &assetUri, const struct stat &statInfo)
125 {
126 if (assetUri.empty()) {
127 MEDIA_ERR_LOG("Uri is empty!");
128 return nullptr;
129 }
130
131 unique_ptr<ImageAsset> imageAsset = make_unique<ImageAsset>();
132 imageAsset->uri_ = assetUri;
133 imageAsset->name_ = GetNameFromUri(assetUri);
134 imageAsset->mediaType_ = MEDIA_TYPE_IMAGE;
135 imageAsset->size_ = statInfo.st_size;
136 imageAsset->dateModified_ = statInfo.st_mtime * MILLISECONDS;
137 imageAsset->dateAdded_ = statInfo.st_ctime * MILLISECONDS;
138
139 return imageAsset;
140 }
141
ScanMediaAssetInfo(MediaType mediaType,const string & path,const struct stat & statInfo)142 void ScanMediaAssetInfo(MediaType mediaType, const string &path, const struct stat &statInfo)
143 {
144 switch (mediaType) {
145 case MEDIA_TYPE_AUDIO: {
146 if (MediaLibraryUtils::requestedMediaType == MEDIA_TYPE_AUDIO) {
147 unique_ptr<AudioAsset> audioAsset = UpdateAudioData(path, statInfo);
148 if (audioAsset != nullptr) {
149 vector<unique_ptr<AudioAsset>> &audioAssetList
150 = MediaLibraryUtils::GetAudioAssetsInternal();
151 audioAsset->id_ = (int32_t)audioAssetList.size();
152 audioAssetList.push_back(std::move(audioAsset));
153 }
154 }
155 break;
156 }
157 case MEDIA_TYPE_VIDEO: {
158 if (MediaLibraryUtils::requestedMediaType == MEDIA_TYPE_VIDEO) {
159 unique_ptr<VideoAsset> videoAsset = UpdateVideoData(path, statInfo);
160 if (videoAsset != nullptr) {
161 vector<unique_ptr<VideoAsset>> &videoAssetList
162 = MediaLibraryUtils::GetVideoAssetsInternal();
163 videoAsset->id_ = (int32_t)videoAssetList.size();
164 videoAssetList.push_back(std::move(videoAsset));
165 }
166 }
167 break;
168 }
169 case MEDIA_TYPE_IMAGE: {
170 if (MediaLibraryUtils::requestedMediaType == MEDIA_TYPE_IMAGE) {
171 unique_ptr<ImageAsset> imageAsset = UpdateImageData(path, statInfo);
172 if (imageAsset != nullptr) {
173 vector<unique_ptr<ImageAsset>> &imageAssetList
174 = MediaLibraryUtils::GetImageAssetsInternal();
175 imageAsset->id_ = (int32_t)imageAssetList.size();
176 imageAssetList.push_back(std::move(imageAsset));
177 }
178 }
179 break;
180 }
181 default:
182 MEDIA_ERR_LOG("ScanMediaAssetInfo :Unknown media type");
183 break;
184 }
185
186 return;
187 }
188
ScanCallback(const char * path,const struct stat * statInfo,int32_t typeFlag,struct FTW * ftwInfo)189 int32_t ScanCallback(const char *path, const struct stat *statInfo, int32_t typeFlag, struct FTW *ftwInfo)
190 {
191 if ((path == nullptr) || (statInfo == nullptr)) {
192 MEDIA_ERR_LOG("Invalid arguments!");
193 return 0;
194 }
195
196 if (typeFlag == FTW_F) {
197 MediaType mediaType = MediaAsset::GetMediaType(path);
198
199 // Add all files in media assets vector
200 if (MediaLibraryUtils::requestedMediaType == MEDIA_TYPE_MEDIA) {
201 unique_ptr<MediaAsset> mediaAsset = UpdateMediaData(path, *statInfo);
202 if (mediaAsset != nullptr) {
203 vector<unique_ptr<MediaAsset>> &mediaAssetList
204 = MediaLibraryUtils::GetMediaAssetsInternal();
205 mediaAsset->id_ = (int32_t)mediaAssetList.size();
206 mediaAsset->mediaType_ = mediaType;
207 mediaAssetList.push_back(std::move(mediaAsset));
208 }
209 }
210 ScanMediaAssetInfo(mediaType, string(path), *statInfo);
211 }
212
213 return 0;
214 }
215
ClearAssets()216 void ClearAssets()
217 {
218 vector<unique_ptr<ImageAsset>> &imageAssets
219 = MediaLibraryUtils::GetImageAssetsInternal();
220 imageAssets.clear();
221
222 vector<unique_ptr<VideoAsset>> &videoAssets
223 = MediaLibraryUtils::GetVideoAssetsInternal();
224 videoAssets.clear();
225
226 vector<unique_ptr<AudioAsset>> &audioAssets
227 = MediaLibraryUtils::GetAudioAssetsInternal();
228 audioAssets.clear();
229
230 vector<unique_ptr<MediaAsset>> &mediaAssets
231 = MediaLibraryUtils::GetMediaAssetsInternal();
232 mediaAssets.clear();
233 }
234
ScanDir(const string & scanDir)235 int32_t ScanDir(const string &scanDir)
236 {
237 int32_t ret = MEDIA_SCAN_SUCCESS;
238 // By default use /storage/media/local/files as scan directory
239 string scanUri = ROOT_MEDIA_DIR;
240
241 if (!scanDir.empty()) {
242 scanUri = ROOT_MEDIA_DIR + scanDir;
243 }
244
245 // Clear all asset vectors before scanning
246 ClearAssets();
247
248 ret = nftw(scanUri.c_str(), ScanCallback, OPEN_FDS, FTW_PHYS);
249 if (ret < 0) {
250 ret = MEDIA_SCAN_FAIL;
251 }
252
253 return ret;
254 }
255
GetSubDirectories(string rootDir)256 vector<string> GetSubDirectories(string rootDir)
257 {
258 DIR *dirPath = nullptr;
259 struct dirent *ent = nullptr;
260 vector<string> dirList;
261 string scanDir = ROOT_MEDIA_DIR;
262
263 if (!rootDir.empty()) {
264 scanDir = ROOT_MEDIA_DIR + rootDir;
265 }
266
267 if ((dirPath = opendir(scanDir.c_str())) != nullptr) {
268 while ((ent = readdir(dirPath)) != nullptr) {
269 if (ent->d_type == DT_DIR) {
270 string currentDir(".");
271 string parentDir("..");
272 if ((currentDir.compare(ent->d_name) != 0)
273 && (parentDir.compare(ent->d_name) != 0)) {
274 string tmpDirPath = scanDir + SLASH_CHAR + ent->d_name;
275 dirList.push_back(tmpDirPath);
276 }
277 }
278 }
279 closedir(dirPath);
280 }
281
282 return dirList;
283 }
284
ScanAlbums(const unique_ptr<AlbumAsset> & albumAsset,string albumDir,int32_t requestedMediaType)285 int32_t ScanAlbums(const unique_ptr<AlbumAsset> &albumAsset, string albumDir, int32_t requestedMediaType)
286 {
287 int32_t ret = MEDIA_SCAN_FAIL;
288
289 if (albumDir.empty()) {
290 return ret;
291 }
292
293 DIR *dirPath = nullptr;
294 struct dirent *ent = nullptr;
295 if ((dirPath = opendir(albumDir.c_str())) != nullptr) {
296 size_t slashIndex = albumDir.rfind(SLASH_CHAR);
297 if (slashIndex != string::npos) {
298 if (albumDir.size() > slashIndex) {
299 albumAsset->SetAlbumName(albumDir.substr(slashIndex + 1, albumDir.length() - slashIndex));
300 }
301 }
302
303 while ((ent = readdir(dirPath)) != nullptr) {
304 if (ent->d_type == DT_REG) {
305 string fileUri = albumDir + SLASH_CHAR + ent->d_name;
306 struct stat statInfo {};
307 if (stat(fileUri.c_str(), &statInfo) != 0) {
308 MEDIA_ERR_LOG("No stat info");
309 continue;
310 }
311
312 MediaType mediaType = MediaAsset::GetMediaType(fileUri);
313 if ((mediaType == MEDIA_TYPE_IMAGE) &&
314 (requestedMediaType == MEDIA_TYPE_IMAGE)) {
315 unique_ptr<ImageAsset> imageAsset = UpdateImageData(fileUri, statInfo);
316 imageAsset->id_ = (int32_t)albumAsset->imageAssetList_.size();
317 albumAsset->imageAssetList_.push_back(std::move(imageAsset));
318 } else if ((mediaType == MEDIA_TYPE_VIDEO) &&
319 (requestedMediaType == MEDIA_TYPE_VIDEO)) {
320 unique_ptr<VideoAsset> videoAsset = UpdateVideoData(fileUri, statInfo);
321 videoAsset->id_ = (int32_t)albumAsset->videoAssetList_.size();
322 albumAsset->videoAssetList_.push_back(std::move(videoAsset));
323 }
324 }
325 }
326 closedir(dirPath);
327 ret = MEDIA_SCAN_SUCCESS;
328 }
329
330 return ret;
331 }
332
333 template<typename T>
SortMediaAssetsByDateAdded(vector<unique_ptr<T>> & mediaAssetList)334 void SortMediaAssetsByDateAdded(vector<unique_ptr<T>> &mediaAssetList)
335 {
336 sort(mediaAssetList.begin(), mediaAssetList.end(),
337 [](const unique_ptr<T> &mediaAsset1, const unique_ptr<T> &mediaAsset2) {
338 return (mediaAsset1->dateAdded_ > mediaAsset2->dateAdded_);
339 });
340 }
341
GetMediaAssets(string selection,vector<string> selectionArgs)342 vector<unique_ptr<MediaAsset>> MediaLibrary::GetMediaAssets(string selection,
343 vector<string> selectionArgs)
344 {
345 MediaLibraryUtils::requestedMediaType = MEDIA_TYPE_MEDIA;
346 vector<unique_ptr<MediaAsset>> mediaAssets;
347
348 pthread_mutex_lock(&(MediaLibraryUtils::mutexLock));
349
350 if (ScanDir(selection) == MEDIA_SCAN_SUCCESS) {
351 vector<unique_ptr<MediaAsset>> &mediaAssetsInternal
352 = MediaLibraryUtils::GetMediaAssetsInternal();
353 for (size_t i = 0; i < mediaAssetsInternal.size(); i++) {
354 mediaAssets.push_back(std::move(mediaAssetsInternal[i]));
355 }
356 mediaAssetsInternal.clear();
357
358 // Sort the Media Asset Vector based on Created Date
359 SortMediaAssetsByDateAdded<MediaAsset>(mediaAssets);
360 }
361 pthread_mutex_unlock(&(MediaLibraryUtils::mutexLock));
362
363 return mediaAssets;
364 }
365
IsAlbumEmpty(const string albumPath)366 bool IsAlbumEmpty(const string albumPath)
367 {
368 bool errCode = false;
369 DIR *dirPath = opendir(albumPath.c_str());
370 if (dirPath != nullptr) {
371 struct dirent *ent = nullptr;
372 while ((ent = readdir(dirPath)) != nullptr) {
373 // strcmp returns 0 if both strings are same.
374 // The if condition will be true only if ent->d_name is neither . nor ..
375 if ((strcmp(ent->d_name, ".") != 0) && (strcmp(ent->d_name, "..") != 0)) {
376 MEDIA_ERR_LOG("Album is not empty");
377 errCode = false;
378 break;
379 }
380 errCode = true;
381 }
382 closedir(dirPath);
383 }
384
385 return errCode;
386 }
387
GetAlbumAssets(string selection,vector<string> selectionArgs,int32_t requestedMediaType)388 vector<unique_ptr<AlbumAsset>> MediaLibrary::GetAlbumAssets(string selection,
389 vector<string> selectionArgs,
390 int32_t requestedMediaType)
391 {
392 vector<unique_ptr<AlbumAsset>> albumAssets;
393 vector<string> albumSubDirList = GetSubDirectories(selection);
394
395 for (size_t i = 0; i < albumSubDirList.size(); i++) {
396 unique_ptr<AlbumAsset> albumAsset = make_unique<AlbumAsset>();
397
398 if ((requestedMediaType == MEDIA_TYPE_IMAGE) && IsAlbumEmpty(albumSubDirList[i])) {
399 size_t slashIndex = albumSubDirList[i].rfind(SLASH_CHAR);
400 if ((slashIndex != string::npos) && (albumSubDirList[i].size() > slashIndex)) {
401 albumAsset->SetAlbumName(albumSubDirList[i].substr(slashIndex + 1,
402 albumSubDirList[i].length() - slashIndex));
403 }
404 albumAssets.push_back(std::move(albumAsset));
405 continue;
406 }
407
408 if (ScanAlbums(albumAsset, albumSubDirList[i], requestedMediaType) == MEDIA_SCAN_SUCCESS) {
409 if (((requestedMediaType == MEDIA_TYPE_IMAGE) && (albumAsset->imageAssetList_.size() == 0)) ||
410 ((requestedMediaType == MEDIA_TYPE_VIDEO) && (albumAsset->videoAssetList_.size() == 0))) {
411 continue;
412 }
413 // Sort Album's Image Asset List
414 SortMediaAssetsByDateAdded<ImageAsset>(albumAsset->imageAssetList_);
415
416 // Sort Album's Video Asset List
417 SortMediaAssetsByDateAdded<VideoAsset>(albumAsset->videoAssetList_);
418 albumAssets.push_back(std::move(albumAsset));
419 } else {
420 MEDIA_ERR_LOG("MediaLibrary: Scan albums failed, return empty");
421 break;
422 }
423 }
424
425 return albumAssets;
426 }
427
GetAudioAssets(string selection,vector<string> selectionArgs)428 vector<unique_ptr<AudioAsset>> MediaLibrary::GetAudioAssets(string selection,
429 vector<string> selectionArgs)
430 {
431 MediaLibraryUtils::requestedMediaType = MEDIA_TYPE_AUDIO;
432 vector<unique_ptr<AudioAsset>> audioAssets;
433
434 pthread_mutex_lock(&(MediaLibraryUtils::mutexLock));
435
436 if (ScanDir(selection) == MEDIA_SCAN_SUCCESS) {
437 vector<unique_ptr<AudioAsset>> &audioAssetsInternal
438 = MediaLibraryUtils::GetAudioAssetsInternal();
439 for (size_t i = 0; i < audioAssetsInternal.size(); i++) {
440 audioAssets.push_back(std::move(audioAssetsInternal[i]));
441 }
442 audioAssetsInternal.clear();
443
444 // Sort the Audio Asset Vector based on Created Date
445 SortMediaAssetsByDateAdded<AudioAsset>(audioAssets);
446 }
447 pthread_mutex_unlock(&(MediaLibraryUtils::mutexLock));
448
449 return audioAssets;
450 }
451
GetVideoAssets(string selection,vector<string> selectionArgs)452 vector<unique_ptr<VideoAsset>> MediaLibrary::GetVideoAssets(string selection,
453 vector<string> selectionArgs)
454 {
455 MediaLibraryUtils::requestedMediaType = MEDIA_TYPE_VIDEO;
456 vector<unique_ptr<VideoAsset>> videoAssets;
457
458 pthread_mutex_lock(&(MediaLibraryUtils::mutexLock));
459
460 if (ScanDir(selection) == MEDIA_SCAN_SUCCESS) {
461 vector<unique_ptr<VideoAsset>> &videoAssetsInternal
462 = MediaLibraryUtils::GetVideoAssetsInternal();
463 for (size_t i = 0; i < videoAssetsInternal.size(); i++) {
464 videoAssets.push_back(std::move(videoAssetsInternal[i]));
465 }
466 videoAssetsInternal.clear();
467
468 // Sort the Video Asset Vector based on Created Date
469 SortMediaAssetsByDateAdded<VideoAsset>(videoAssets);
470 }
471 pthread_mutex_unlock(&(MediaLibraryUtils::mutexLock));
472
473 return videoAssets;
474 }
475
GetImageAssets(string selection,vector<string> selectionArgs)476 vector<unique_ptr<ImageAsset>> MediaLibrary::GetImageAssets(string selection,
477 vector<string> selectionArgs)
478 {
479 MediaLibraryUtils::requestedMediaType = MEDIA_TYPE_IMAGE;
480 vector<unique_ptr<ImageAsset>> imageAssets;
481
482 pthread_mutex_lock(&(MediaLibraryUtils::mutexLock));
483
484 if (ScanDir(selection) == MEDIA_SCAN_SUCCESS) {
485 vector<unique_ptr<ImageAsset>> &imageAssetsInternal
486 = MediaLibraryUtils::GetImageAssetsInternal();
487 for (size_t i = 0; i < imageAssetsInternal.size(); i++) {
488 imageAssets.push_back(std::move(imageAssetsInternal[i]));
489 }
490 imageAssetsInternal.clear();
491
492 // Sort the Image Asset Vector based on Created Date
493 SortMediaAssetsByDateAdded<ImageAsset>(imageAssets);
494 }
495 pthread_mutex_unlock(&(MediaLibraryUtils::mutexLock));
496
497 return imageAssets;
498 }
499
CreateMediaAsset(AssetType assetType,const MediaAsset & crtMediaAsset)500 bool MediaLibrary::CreateMediaAsset(AssetType assetType, const MediaAsset& crtMediaAsset)
501 {
502 MediaAsset *mediaAsset = (MediaAsset *)&crtMediaAsset;
503
504 return mediaAsset->CreateMediaAsset(assetType);
505 }
506
DeleteMediaAsset(AssetType assetType,const MediaAsset & delMediaAsset)507 bool MediaLibrary::DeleteMediaAsset(AssetType assetType, const MediaAsset& delMediaAsset)
508 {
509 MediaAsset *mediaAsset = (MediaAsset *)&delMediaAsset;
510
511 return mediaAsset->DeleteMediaAsset();
512 }
513
ModifyMediaAsset(AssetType assetType,const MediaAsset & srcMediaAsset,const MediaAsset & dstAsset)514 bool MediaLibrary::ModifyMediaAsset(AssetType assetType, const MediaAsset& srcMediaAsset,
515 const MediaAsset &dstAsset)
516 {
517 MediaAsset *dstMediaAsset = (MediaAsset *)&dstAsset;
518
519 return dstMediaAsset->ModifyMediaAsset(srcMediaAsset);
520 }
521
CopyMediaAsset(AssetType assetType,const MediaAsset & srcMediaAsset,const MediaAsset & dstAsset)522 bool MediaLibrary::CopyMediaAsset(AssetType assetType, const MediaAsset& srcMediaAsset,
523 const MediaAsset& dstAsset)
524 {
525 MediaAsset *dstMediaAsset = (MediaAsset *)&dstAsset;
526
527 return dstMediaAsset->CopyMediaAsset(srcMediaAsset);
528 }
529
CreateMediaAlbumAsset(AssetType assetType,const AlbumAsset & albmAsset)530 bool MediaLibrary::CreateMediaAlbumAsset(AssetType assetType, const AlbumAsset& albmAsset)
531 {
532 AlbumAsset *albumAsset = (AlbumAsset *)&albmAsset;
533 albumAsset->SetAlbumPath(ROOT_MEDIA_DIR + SLASH_CHAR + albumAsset->GetAlbumName());
534
535 return albumAsset->CreateAlbumAsset();
536 }
537
DeleteMediaAlbumAsset(AssetType assetType,const AlbumAsset & albmAsset,const string & albumUri)538 bool MediaLibrary::DeleteMediaAlbumAsset(AssetType assetType, const AlbumAsset& albmAsset, const string &albumUri)
539 {
540 AlbumAsset *albumAsset = (AlbumAsset *)&albmAsset;
541
542 return albumAsset->DeleteAlbumAsset(albumUri);
543 }
544
ModifyMediaAlbumAsset(AssetType assetType,const AlbumAsset & srcAlbumAsset,const AlbumAsset & dstAlbAsset,const string & albumUri)545 bool MediaLibrary::ModifyMediaAlbumAsset(AssetType assetType, const AlbumAsset& srcAlbumAsset,
546 const AlbumAsset &dstAlbAsset, const string &albumUri)
547 {
548 AlbumAsset *dstAlbumAsset = (AlbumAsset *)&dstAlbAsset;
549
550 return dstAlbumAsset->ModifyAlbumAsset(albumUri);
551 }
552 } // namespace Media
553 } // namespace OHOS
554