/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Tizen.System; namespace Tizen.Content.MediaContent { /// /// Provides commands to manage the media information and query related items in the database. /// /// 4 public class MediaInfoCommand : MediaCommand { /// /// Initializes a new instance of the class with the specified . /// /// The that the commands run on. /// is null. /// has already been disposed. /// 4 public MediaInfoCommand(MediaDatabase database) : base(database) { } /// /// Retrieves the number of the bookmarks added to the media. /// /// The media ID to count the bookmarks added to the media. /// The number of the bookmarks. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 public int CountBookmark(string mediaId) { return CountBookmark(mediaId, null); } /// /// Retrieves the number of the bookmarks added to the media with the . /// /// The media ID to count the bookmarks added to the media. /// The criteria to use to filter. This value can be null. /// The number of the bookmarks. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 public int CountBookmark(string mediaId, CountArguments arguments) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); return CommandHelper.Count(Interop.MediaInfo.GetBookmarkCount, mediaId, arguments); } /// /// Retrieves the bookmarks added to the media. /// /// The media ID to select the bookmarks added to the media. /// The containing the results. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 public MediaDataReader SelectBookmark(string mediaId) { return SelectBookmark(mediaId, null); } /// /// Retrieves the bookmarks added to the media with the . /// /// The media ID to select the bookmarks added to the media. /// The criteria to use to filter. This value can be null. /// The containing the results. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 public MediaDataReader SelectBookmark(string mediaId, SelectArguments filter) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); return CommandHelper.SelectMembers(mediaId, filter, Interop.MediaInfo.ForeachBookmarks, Bookmark.FromHandle); } /// /// Retrieves the number of the face information added to or detected from the media. /// /// The media ID to count face information added to the media. /// The number of the face information. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 public int CountFaceInfo(string mediaId) { return CountFaceInfo(mediaId, null); } /// /// Retrieves the number of the face information added to or detected from the media with filter. /// /// The media ID to count the face information added to the media. /// The criteria to use to filter. This value can be null. /// The number of the face information. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 [Obsolete("Deprecated since API11; Will be removed in API13.")] public int CountFaceInfo(string mediaId, CountArguments arguments) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); return CommandHelper.Count(Interop.MediaInfo.GetFaceCount, mediaId, arguments); } /// /// Retrieves the face information added to or detected from the media. /// /// The media ID to select face information added to the media. /// The containing the results. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 [Obsolete("Deprecated since API11; Will be removed in API13.")] public MediaDataReader SelectFaceInfo(string mediaId) { return SelectFaceInfo(mediaId, null); } /// /// Retrieves the face information added to or detected from the media with the . /// /// The media ID to select the face information added to the media. /// The criteria to use to filter. This value can be null. /// The containing the results. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 [Obsolete("Deprecated since API11; Will be removed in API13.")] public MediaDataReader SelectFaceInfo(string mediaId, SelectArguments arguments) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); return CommandHelper.SelectMembers(mediaId, arguments, Interop.MediaInfo.ForeachFaces, FaceInfo.FromHandle); } /// /// Retrieves the number of tags that the media has. /// /// The number of tags. /// The media ID to count tags added to the media. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 public int CountTag(string mediaId) { return CountTag(mediaId, null); } /// /// Retrieves the number of tags that the media has with the . /// /// The media ID to count tags added to the media. /// The criteria to use to filter. This value can be null. /// The number of tags. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 public int CountTag(string mediaId, CountArguments arguments) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); return CommandHelper.Count(Interop.MediaInfo.GetTagCount, mediaId, arguments); } /// /// Retrieves the tags that the media has. /// /// The media ID to select tags added to the media. /// The containing the results. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 public MediaDataReader SelectTag(string mediaId) { return SelectTag(mediaId, null); } /// /// Retrieves the tags that the media has with the . /// /// The media ID to select tags added to the media. /// The criteria to use to filter. This value can be null. /// The containing the results. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 public MediaDataReader SelectTag(string mediaId, SelectArguments filter) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); return CommandHelper.SelectMembers(mediaId, filter, Interop.MediaInfo.ForeachTags, Tag.FromHandle); } /// /// Retrieves the number of the media information. /// /// The number of the media information. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// 4 public int CountMedia() { return CountMedia(null); } /// /// Retrieves the number of the media information with the . /// /// The criteria to use to filter. This value can be null. /// The number of media information. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// 4 public int CountMedia(CountArguments arguments) { ValidateDatabase(); return CommandHelper.Count(Interop.MediaInfo.GetMediaCount, arguments); } /// /// Retrieves the media. /// /// The media ID to retrieve. /// The instance if the matched record was found in the database, otherwise null. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// 4 public MediaInfo SelectMedia(string mediaId) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); Interop.MediaInfo.GetMediaFromDB(mediaId, out var handle).Ignore(MediaContentError.InvalidParameter). ThrowIfError("Failed to query"); try { return MediaInfo.FromHandle(handle); } finally { handle.Dispose(); } } /// /// Retrieves the number of values grouped by the specified column with the . /// /// The column key. /// The number of groups. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is invalid. /// 4 public int CountGroupBy(MediaInfoColumnKey columnKey) { return CountGroupBy(columnKey, null); } /// /// Retrieves the number of values grouped by the specified column with the . /// /// The column key. /// The criteria to use to filter. This value can be null. /// The number of groups. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is invalid. /// 4 public int CountGroupBy(MediaInfoColumnKey columnKey, CountArguments arguments) { ValidateDatabase(); ValidationUtil.ValidateEnum(typeof(MediaInfoColumnKey), columnKey, nameof(columnKey)); using (var filter = QueryArguments.ToNativeHandle(arguments)) { Interop.Group.GetGroupCount(filter, columnKey, out var count).ThrowIfError("Failed to query count"); return count; } } /// /// Retrieves the group values of the specified column. /// /// The column key. /// The containing the results. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is invalid. /// 4 public MediaDataReader SelectGroupBy(MediaInfoColumnKey columnKey) { return SelectGroupBy(columnKey, null); } /// /// Retrieves the group values of the specified column with the . /// /// The column key. /// The criteria to use to filter. This value can be null. /// The containing the results. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is invalid. /// 4 public MediaDataReader SelectGroupBy(MediaInfoColumnKey columnKey, SelectArguments arguments) { ValidateDatabase(); ValidationUtil.ValidateEnum(typeof(MediaInfoColumnKey), columnKey, nameof(columnKey)); List list = new List(); using (var filter = QueryArguments.ToNativeHandle(arguments)) { Interop.Group.ForeachGroup(filter, columnKey, (name, _) => { list.Add(name); return true; }).ThrowIfError("Failed to query"); return new MediaDataReader(list); } } /// /// Retrieves all the media. /// /// The containing the results. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// 4 public MediaDataReader SelectMedia() { return SelectMedia(arguments: null); } /// /// Retrieves the media with the . /// /// The criteria to use to filter. This value can be null. /// The containing the results. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// 4 public MediaDataReader SelectMedia(SelectArguments arguments) { ValidateDatabase(); return new MediaDataReader(QueryMedia(arguments)); } private static List QueryMedia(SelectArguments arguments) { using (var filter = QueryArguments.ToNativeHandle(arguments)) { List list = new List(); Exception caught = null; Interop.MediaInfo.ForeachMedia(filter, (handle, _) => { try { list.Add(MediaInfo.FromHandle(handle)); return true; } catch (Exception e) { caught = e; return false; } }); if (caught != null) { throw caught; } return list; } } /// /// Retrieves all matched ebook paths with given . /// /// http://tizen.org/privilege/mediastorage /// http://tizen.org/privilege/externalstorage /// The keyword to search. /// A list of ebook paths which contain . /// is null. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// The caller has no required privilege. /// 9 public MediaDataReader SelectEbookPath(string keyword) { ValidateDatabase(); IntPtr path = IntPtr.Zero; uint length = 0; ValidationUtil.ValidateNotNullOrEmpty(keyword, nameof(keyword)); try { Interop.BookInfo.GetPathByKeyword(keyword, out path, out length). ThrowIfError("Failed to get path by keyword"); var list = new List(); var current = path; for (int i = 0; i < length; i++) { list.Add(Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(current))); current = (IntPtr)((long)current + Marshal.SizeOf(typeof(IntPtr))); } return new MediaDataReader(list); } finally { var current = path; for (int i = 0; i < length; i++) { Interop.Libc.Free(Marshal.ReadIntPtr(current)); current = (IntPtr)((long)current + Marshal.SizeOf(typeof(IntPtr))); } } } /// /// Deletes the media from the database. /// /// http://tizen.org/privilege/content.write /// The media ID to delete. /// true if the matched record was found and deleted, otherwise false. /// /// The or the can be used instead.
/// Since API level 6, if the file related with the in DB still exists in file system before calling this method, /// will be thrown to keep consistency in DB. ///
/// /// The is disconnected.
/// -or-
/// The file related with the in DB still exists in file system. (Since API level 6) ///
/// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// The caller has no required privilege. /// 4 public bool Delete(string mediaId) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); if (CommandHelper.Count( Interop.MediaInfo.GetMediaCount, $"{MediaInfoColumns.Id}='{mediaId}'") == 0) { return false; } Interop.MediaInfo.GetMediaFromDB(mediaId, out var handle). ThrowIfError("Failed to delete MediaInfo."); var path = InteropHelper.GetString(handle, Interop.MediaInfo.GetFilePath); // If we don't check file existence before calling `ScanFile` method, // The inconsistency between DB and file system could be occurred. if (File.Exists(path)) { throw new InvalidOperationException("File still exists in file system. Remove it first."); } // Native 'delete' function was deprecated, so we need to use 'scan file' function instead of it. Database.ScanFile(path); return true; } /// /// Adds the media to the database. /// /// The file path to add. /// The instance that contains the record information in the database. /// /// If the media already exists in the database, it returns the existing information.
///
/// The or the can be used instead.
///
/// If you want to access internal storage, you should add privilege http://tizen.org/privilege/mediastorage.
/// If you want to access external storage, you should add privilege http://tizen.org/privilege/externalstorage.
///
/// If http://tizen.org/feature/content.scanning.others feature is not supported and the specified file is other-type, /// will be thrown. ///
/// http://tizen.org/privilege/content.write /// http://tizen.org/privilege/mediastorage /// http://tizen.org/privilege/externalstorage /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// /// is a zero-length string, contains only white space.
/// -or-
/// contains a hidden path that starts with '.'.
/// -or-
/// contains a directory containing the ".scan_ignore" file. ///
/// does not exists. /// The caller has no required privilege. /// The required feature is not supported. /// 4 public MediaInfo Add(string path) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(path, nameof(path)); if (File.Exists(path) == false) { throw new FileNotFoundException("destination is not valid path.", path); } if (File.GetAttributes(path).HasFlag(FileAttributes.Hidden)) { throw new ArgumentException($"{nameof(path)} contains a hidden path.", nameof(path)); } Interop.MediaInfoHandle handle = null; try { Interop.MediaInfo.Insert(path, out handle).ThrowIfError("Failed to insert"); return MediaInfo.FromHandle(handle); } finally { if (handle != null) { handle.Dispose(); } } } private static void ValidatePaths(IEnumerable paths) { if (paths == null) { throw new ArgumentNullException(nameof(paths)); } if (paths.Count() > 300) { throw new ArgumentException("Too many paths to add."); } foreach (var path in paths) { if (path == null) { throw new ArgumentException($"{nameof(paths)} contains null.", nameof(paths)); } if (File.Exists(path) == false) { throw new FileNotFoundException($"{nameof(paths)} contains a path that does not exist. Path={path}.", path); } } } /// /// Adds media files into the media database. /// /// /// The paths that already exist in the database will be ignored.
/// At most 300 items can be added at once.
///
/// If you want to access internal storage, you should add privilege http://tizen.org/privilege/mediastorage.
/// If you want to access external storage, you should add privilege http://tizen.org/privilege/externalstorage.
///
/// If http://tizen.org/feature/content.scanning.others feature is not supported and the specified file is other-type, /// will be thrown. ///
/// http://tizen.org/privilege/content.write /// http://tizen.org/privilege/mediastorage /// http://tizen.org/privilege/externalstorage /// The paths of the media files to add. /// A task that represents the asynchronous add operation. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// /// contains null.
/// -or-
/// contains the invalid path.
/// -or-
/// The number of is 300 or more items. ///
/// contains a path that does not exist. /// The caller has no required privilege. /// The required feature is not supported. /// 4 public async Task AddAsync(IEnumerable paths) { ValidateDatabase(); ValidatePaths(paths); var pathArray = paths.ToArray(); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); Interop.MediaInfo.InsertCompletedCallback callback = (error, _) => { if (error == MediaContentError.None) { tcs.TrySetResult(true); } else { tcs.TrySetException(error.AsException("Failed to add")); } }; using (ObjectKeeper.Get(callback)) { Interop.MediaInfo.BatchInsert(pathArray, pathArray.Length, callback).ThrowIfError("Failed to add"); await tcs.Task; } } /// /// Updates the media with the favorite value. /// /// http://tizen.org/privilege/content.write /// The media ID to update. /// The value indicating whether the media is favorite. /// true if the matched record was found and updated, otherwise false. /// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// is null. /// is a zero-length string, contains only white space. /// The caller has no required privilege. /// 4 public bool UpdateFavorite(string mediaId, bool value) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); if (CommandHelper.Count( Interop.MediaInfo.GetMediaCount, $"{MediaInfoColumns.Id}='{mediaId}'") == 0) { return false; } Interop.MediaInfo.GetMediaFromDB(mediaId, out var handle).ThrowIfError("Failed to update"); if (handle.IsInvalid) { return false; } try { Interop.MediaInfo.SetFavorite(handle, value).ThrowIfError("Failed to update"); Interop.MediaInfo.UpdateToDB(handle).ThrowIfError("Failed to update"); return true; } finally { handle.Dispose(); } } /// /// Updates the path of the media to the specified destination path in the database. /// /// http://tizen.org/privilege/content.write /// http://tizen.org/privilege/mediastorage /// http://tizen.org/privilege/externalstorage /// The media ID to move. /// The path that the media has been moved to. /// true if the matched record was found and updated, otherwise false. /// /// Usually, it is used after the media file is moved to the another path.
///
/// If you want to access internal storage, you should add privilege http://tizen.org/privilege/mediastorage.
/// If you want to access external storage, you should add privilege http://tizen.org/privilege/externalstorage. ///
/// The is disconnected. /// The has already been disposed. /// An error occurred while executing the command. /// /// is null.
/// -or-
/// is null. ///
/// /// is a zero-length string, contains only white space.
/// -or-
/// is a zero-length string, contains only white space.
/// -or-
/// contains a hidden directory that starts with '.'.
/// -or-
/// contains a directory containing the ".scan_ignore" file. ///
/// does not exists. /// The caller has no required privilege. /// 4 public bool Move(string mediaId, string newPath) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); ValidationUtil.ValidateNotNullOrEmpty(newPath, nameof(newPath)); if (File.Exists(newPath) == false) { throw new FileNotFoundException("destination is not valid path.", newPath); } if (File.GetAttributes(newPath).HasFlag(FileAttributes.Hidden)) { throw new ArgumentException($"{nameof(newPath)} contains a hidden path.", nameof(newPath)); } //TODO can be improved if MoveToDB supports result value. Interop.MediaInfo.GetMediaFromDB(mediaId, out var handle). Ignore(MediaContentError.InvalidParameter).ThrowIfError("Failed to move"); if (handle.IsInvalid) { return false; } try { Interop.MediaInfo.MoveToDB(handle, newPath).ThrowIfError("Failed to move"); } finally { handle.Dispose(); } return true; } #region CreateThumbnailAsync /// /// Creates the thumbnail image for the given media. /// If the thumbnail already exists for the given media, the existing path will be returned. /// /// http://tizen.org/privilege/content.write /// The media ID to create the thumbnail. /// A task that represents the asynchronous operation. The task result contains the thumbnail path. /// /// The is disconnected.
/// -or-
/// An internal error occurred while executing. ///
/// The has already been disposed. /// An error occurred while executing the command. /// is null. /// does not exist in the database. /// /// is a zero-length string, contains only white space. /// /// The file of the media does not exists; moved or deleted. /// /// The thumbnail is not available for the given media.
/// -or-
/// The media is in the external USB storage. ///
/// 4 [Obsolete("Deprecated since API10; Will be removed in API12. Please use CreateThumbnail instead.")] public Task CreateThumbnailAsync(string mediaId) { return CreateThumbnailAsync(mediaId, CancellationToken.None); } /// /// Creates the thumbnail image for the given media. /// If the thumbnail already exists for the given media, the existing path will be returned. /// /// http://tizen.org/privilege/content.write /// The media ID to create the thumbnail. /// The token to cancel the operation. /// A task that represents the asynchronous operation. The task result contains the thumbnail path. /// /// The is disconnected.
/// -or-
/// An internal error occurred while executing. ///
/// The has already been disposed. /// An error occurred while executing the command. /// is null. /// does not exist in the database. /// /// is a zero-length string, contains only white space. /// /// The file of the media does not exists; moved or deleted. /// /// The thumbnail is not available for the given media.
/// -or-
/// The media is in the external USB storage. ///
/// 4 [Obsolete("Deprecated since API10; Will be removed in API12. Please use CreateThumbnail instead.")] public Task CreateThumbnailAsync(string mediaId, CancellationToken cancellationToken) { ValidateDatabase(); return cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : CreateThumbnailAsyncCore(mediaId, cancellationToken); } private async Task CreateThumbnailAsyncCore(string mediaId, CancellationToken cancellationToken) { ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); var tcs = new TaskCompletionSource(); using (var handle = ValidateFile(mediaId)) { string thumbnailPath = null; MediaContentError ret = MediaContentError.None; Task thumbTask = null; if (cancellationToken.CanBeCanceled) { cancellationToken.Register(() => { if (tcs.Task.IsCompleted) { return; } tcs.TrySetCanceled(); }); } thumbTask = Task.Factory.StartNew( () => { ret = Interop.MediaInfo.GenerateThumbnail(handle); if (ret != MediaContentError.None) { tcs.TrySetException(ret.AsException("Failed to create thumbnail")); } else { thumbnailPath = InteropHelper.GetString(handle, Interop.MediaInfo.GetThumbnailPath, true); tcs.TrySetResult(thumbnailPath); } }, cancellationToken, TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning, TaskScheduler.Default); return await tcs.Task; } } #endregion /// /// Creates the thumbnail image for the given media. /// If the thumbnail already exists for the given media, the existing path will be returned. /// /// http://tizen.org/privilege/content.write /// http://tizen.org/privilege/mediastorage /// http://tizen.org/privilege/externalstorage /// The ID of the media for which the thumbnail will be created. /// A created thumbnail path. /// /// The is disconnected.
/// -or-
/// An internal error occurred while executing. ///
/// The has already been disposed. /// An error occurred while executing the command. /// is null. /// does not exist in the database. /// /// is a zero-length string, contains only white space. /// /// The file of the media does not exists; moved or deleted. /// /// The thumbnail is not available for the given media.
/// -or-
/// The media is in the external USB storage. ///
/// The caller has no required privilege. /// 10 public string CreateThumbnail(string mediaId) { ValidateDatabase(); ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); using (var handle = ValidateFile(mediaId)) { Interop.MediaInfo.GenerateThumbnail(handle).ThrowIfError("Failed to create thumbnail"); return InteropHelper.GetString(handle, Interop.MediaInfo.GetThumbnailPath, true); } } private Interop.MediaInfoHandle ValidateFile(string mediaId) { Interop.MediaInfo.GetMediaFromDB(mediaId, out var handle).ThrowIfError("Failed to create thumbnail"); if (handle.IsInvalid) { throw new RecordNotFoundException("Media does not exist."); } try { var path = InteropHelper.GetString(handle, Interop.MediaInfo.GetFilePath); if (String.IsNullOrEmpty(path) || File.Exists(path) == false) { throw new FileNotFoundException($"The media file does not exist. Path={path}.", path); } foreach (var extendedInternal in StorageManager.Storages.Where(s => s.StorageType == StorageArea.ExtendedInternal)) { if (path.Contains(extendedInternal.RootDirectory)) { throw new UnsupportedContentException("The media is in external usb storage."); } } } catch (Exception ex) { handle.Dispose(); throw ex; } return handle; } #region DetectFaceAsync /// /// Detects faces from the given media. /// If the thumbnail already exists for the given media, the existing path will be returned. /// /// http://tizen.org/privilege/content.write /// http://tizen.org/feature/vision.face_recognition /// The media ID to create the thumbnail. /// A task that represents the asynchronous add operation. The task result contains the number of faces detected. /// /// The is disconnected.
/// -or-
/// An internal error occurred while executing. ///
/// The has already been disposed. /// An error occurred while executing the command. /// is null. /// does not exist in the database. /// /// is a zero-length string, contains only white space. /// /// The file of the media does not exists; moved or deleted. /// Face detection is not available for the given media. /// The required feature is not supported. /// The caller has no required privilege. /// 4 [Obsolete("Deprecated since API11; Will be removed in API13.")] public Task DetectFaceAsync(string mediaId) { return DetectFaceAsync(mediaId, CancellationToken.None); } /// /// Creates the thumbnail image for the given media. /// If the thumbnail already exists for the given media, the existing path will be returned. /// /// /// Media in the external storage is not supported, with the exception of MMC. /// Only JPEG, PNG, BMP images are supported. /// /// http://tizen.org/privilege/content.write /// http://tizen.org/feature/vision.face_recognition /// The media ID to create the thumbnail. /// The token to cancel the operation. /// A task that represents the asynchronous operation. The task result contains the number of faces detected. /// /// The is disconnected.
/// -or-
/// An internal error occurred while executing. ///
/// The has already been disposed. /// An error occurred while executing the command. /// is null. /// does not exist in the database. /// /// is a zero-length string, contains only white space. /// /// The file of the media does not exists; moved or deleted. /// /// Face detection is not available for the given media.
/// -or-
/// The media is in the external USB storage. ///
/// The required feature is not supported. /// 4 [Obsolete("Deprecated since API11; Will be removed in API13.")] public Task DetectFaceAsync(string mediaId, CancellationToken cancellationToken) { if (Features.IsSupported(Features.FaceRecognition) == false) { throw new NotSupportedException($"The feature({Features.FaceRecognition}) is not supported."); } ValidateDatabase(); return cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : DetectFaceAsyncCore(mediaId, cancellationToken); } private static async Task DetectFaceAsyncCore(string mediaId, CancellationToken cancellationToken) { ValidationUtil.ValidateNotNullOrEmpty(mediaId, nameof(mediaId)); var tcs = new TaskCompletionSource(); Interop.MediaInfo.GetMediaFromDB(mediaId, out var handle).ThrowIfError("Failed to detect faces"); if (handle.IsInvalid) { throw new RecordNotFoundException("Media does not exist."); } using (handle) { if (InteropHelper.GetValue(handle, Interop.MediaInfo.GetMediaType) != MediaType.Image) { throw new UnsupportedContentException("Only image is supported."); } // Native P/Invoke function also check below case, but it returns invalid operation error. // So we check it here to throw more proper exception. string mimeType = InteropHelper.GetString(handle, Interop.MediaInfo.GetMimeType); if (!mimeType.Equals("image/jpeg") && !mimeType.Equals("image/png") && !mimeType.Equals("image/bmp")) { throw new UnsupportedContentException($"{mimeType} is not supported. Only JPEG, PNG, BMP is supported."); } var path = InteropHelper.GetString(handle, Interop.MediaInfo.GetFilePath); if (File.Exists(path) == false) { throw new FileNotFoundException($"The media file does not exist. Path={path}.", path); } using (RegisterCancelFaceDetection(cancellationToken, tcs, handle)) using (var cbKeeper = ObjectKeeper.Get(GetFaceDetectionCallback(tcs))) { var ret = Interop.MediaInfo.StartFaceDetection(handle, cbKeeper.Target); if (ret == MediaContentError.InvalidParameter) { throw new UnsupportedContentException("The media is in external usb storage."); } ret.ThrowIfError("Failed to detect faces"); return await tcs.Task; } } } private static Interop.MediaInfo.FaceDetectionCompletedCallback GetFaceDetectionCallback( TaskCompletionSource tcs) { return (error, count, _) => { if (error != MediaContentError.None) { tcs.TrySetException(error.AsException("Failed to detect faces")); } else { tcs.TrySetResult(count); } }; } private static IDisposable RegisterCancelFaceDetection(CancellationToken cancellationToken, TaskCompletionSource tcs, Interop.MediaInfoHandle handle) { if (cancellationToken.CanBeCanceled == false) { return null; } return cancellationToken.Register(() => { if (tcs.Task.IsCompleted) { return; } Interop.MediaInfo.CancelFaceDetection(handle).ThrowIfError("Failed to cancel"); tcs.TrySetCanceled(); }); } #endregion } }