/* * 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.IO; using System.Runtime.InteropServices; namespace Tizen.Multimedia { /// /// Provides a means to edit the metadata of the media file. /// /// /// If you want to access only an internal storage, /// you should add privilege http://tizen.org/privilege/mediastorage.
/// Or if you want to access only an external storage, /// you should add privilege http://tizen.org/privilege/externalstorage. ///
/// 3 public class MetadataEditor : IDisposable { private bool _disposed = false; private IntPtr _handle = IntPtr.Zero; private bool _isFileReadOnly; private IntPtr Handle { get { if (_handle == IntPtr.Zero) { throw new ObjectDisposedException(nameof(MetadataEditor)); } return _handle; } } /// /// Initializes a new instance of the class with the specified path. /// /// 3 /// The path of the media file to edit the metadata. /// is null. /// is a zero-length string, contains only white space. /// The file is not supported. /// The file does not exist. /// The caller does not have required privilege to access the file. public MetadataEditor(string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException($"{nameof(path)} is a zero-length string.", nameof(path)); } Interop.MetadataEditor.Create(out _handle).ThrowIfError("Failed to create metadata"); try { Interop.MetadataEditor.SetPath(Handle, path).ThrowIfError("Failed to set path"); _isFileReadOnly = File.GetAttributes(path).HasFlag(FileAttributes.ReadOnly); } catch (Exception) { Interop.MetadataEditor.Destroy(_handle); throw; } } private string GetParam(MetadataEditorAttr attr) { IntPtr val = IntPtr.Zero; try { Interop.MetadataEditor.GetMetadata(Handle, attr, out val) .ThrowIfError("Failed to get metadata"); return Marshal.PtrToStringAnsi(val); } finally { Interop.Libc.Free(val); } } private void SetParam(MetadataEditorAttr attr, string value) { if (_isFileReadOnly) { throw new InvalidOperationException("The media file is read-only."); } Interop.MetadataEditor.SetMetadata(Handle, attr, value).ThrowIfError("Failed to set value"); } /// /// Gets or sets the artist of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string Artist { get { return GetParam(MetadataEditorAttr.Artist); } set { SetParam(MetadataEditorAttr.Artist, value); } } /// /// Gets or sets the title of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string Title { get { return GetParam(MetadataEditorAttr.Title); } set { SetParam(MetadataEditorAttr.Title, value); } } /// /// Gets or sets the album name of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string Album { get { return GetParam(MetadataEditorAttr.Album); } set { SetParam(MetadataEditorAttr.Album, value); } } /// /// Gets or sets the genre of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string Genre { get { return GetParam(MetadataEditorAttr.Genre); } set { SetParam(MetadataEditorAttr.Genre, value); } } /// /// Gets or sets the author of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string Author { get { return GetParam(MetadataEditorAttr.Author); } set { SetParam(MetadataEditorAttr.Author, value); } } /// /// Gets or sets the copyright of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string Copyright { get { return GetParam(MetadataEditorAttr.Copyright); } set { SetParam(MetadataEditorAttr.Copyright, value); } } /// /// Gets or sets the date of media. /// /// 3 /// /// If the media contains the ID3 tag, this refers to the recorded date. /// If the media is a mp4 format, this refers to the year, and the value to set will be converted into integer. /// /// The file is read-only. /// The has already been disposed of. public string Date { get { return GetParam(MetadataEditorAttr.Date); } set { SetParam(MetadataEditorAttr.Date, value); } } /// /// Gets or sets the description of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string Description { get { return GetParam(MetadataEditorAttr.Description); } set { SetParam(MetadataEditorAttr.Description, value); } } /// /// Gets or sets the comment of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string Comment { get { return GetParam(MetadataEditorAttr.Comment); } set { SetParam(MetadataEditorAttr.Comment, value); } } /// /// Gets or sets the track number of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string TrackNumber { get { return GetParam(MetadataEditorAttr.TrackNumber); } set { SetParam(MetadataEditorAttr.TrackNumber, value); } } /// /// Gets the count of album arts of media. /// /// 3 /// The has already been disposed of. public int PictureCount { get => int.TryParse(GetParam(MetadataEditorAttr.PictureCount), out var value) ? value : 0; } /// /// Gets or sets the conductor of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string Conductor { get { return GetParam(MetadataEditorAttr.Conductor); } set { SetParam(MetadataEditorAttr.Conductor, value); } } /// /// Gets or sets the unsynchronized lyrics of media. /// /// 3 /// The file is read-only. /// The has already been disposed of. public string UnsyncLyrics { get { return GetParam(MetadataEditorAttr.UnsyncLyrics); } set { SetParam(MetadataEditorAttr.UnsyncLyrics, value); } } /// /// Writes the modified metadata to the media file. /// /// /// An internal error occurs.
/// -or-
/// The file is read-only. ///
/// The has already been disposed of. /// 3 public void Commit() { if (_isFileReadOnly) { throw new InvalidOperationException("The media file is read-only."); } Interop.MetadataEditor.UpdateMetadata(Handle).ThrowIfError("Failed to update file"); } /// /// Gets the artwork image in the media file. /// /// 3 /// The index of the picture to import. /// The artwork included in the media file. /// An internal error occurs. /// /// is less than zero.
/// -or-
/// is greater than or equal to . ///
/// The has already been disposed of. public Artwork GetPicture(int index) { if (index < 0) { throw new ArgumentOutOfRangeException(nameof(index), index, "Index should not be less than zero."); } if (index >= PictureCount) { throw new ArgumentOutOfRangeException(nameof(index), index, "Index should not be greater thor or equal to PictureCount."); } IntPtr data = IntPtr.Zero; IntPtr mimeType = IntPtr.Zero; try { Interop.MetadataEditor.GetPicture(Handle, index, out data, out var size, out mimeType). ThrowIfError("Failed to get the value"); if (size > 0) { byte[] tmpBuf = new byte[size]; Marshal.Copy(data, tmpBuf, 0, size); return new Artwork(tmpBuf, Marshal.PtrToStringAnsi(mimeType)); } return null; } finally { if (data != IntPtr.Zero) { Interop.Libc.Free(data); } if (mimeType != IntPtr.Zero) { Interop.Libc.Free(mimeType); } } } /// /// Appends the picture to the media file. /// /// 3 /// The path of the picture for adding to the metadata. /// /// An internal error occurs.
/// -or-
/// The media file is read-only. ///
/// is null. /// The file does not exist. /// The caller does not have required privilege to access the file. /// The has already been disposed of. /// The specified file is not supported. public void AddPicture(string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (File.Exists(path) == false) { throw new FileNotFoundException("File does not exist.", path); } if (_isFileReadOnly) { throw new InvalidOperationException("The media file is read-only."); } Interop.MetadataEditor.AddPicture(Handle, path). ThrowIfError("Failed to append picture"); } /// /// Removes the picture from the media file. /// /// 3 /// The index of the picture to remove. /// /// An internal error occurs.
/// -or-
/// The media file is read-only. ///
/// /// is less than zero.
/// -or-
/// is greater than or equal to . ///
/// The has already been disposed of. public void RemovePicture(int index) { if (index < 0) { throw new ArgumentOutOfRangeException("Index should be larger than 0 [" + index + "]"); } if (index >= PictureCount) { throw new ArgumentOutOfRangeException(nameof(index), index, "Index should not be greater thor or equal to PictureCount."); } if (_isFileReadOnly) { throw new InvalidOperationException("The media file is read-only."); } Interop.MetadataEditor.RemovePicture(Handle, index).ThrowIfError("Failed to remove picture"); } /// /// Finalizes an instance of the MetadataEditor class. /// ~MetadataEditor() { Dispose(false); } /// /// Releases the resources used by the object. /// /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. /// /// 3 protected virtual void Dispose(bool disposing) { if (!_disposed) { if (_handle != IntPtr.Zero) { Interop.MetadataEditor.Destroy(_handle); _handle = IntPtr.Zero; } _disposed = true; } } /// /// Releases all resources used by the object. /// /// 3 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }