/* * 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 { static internal class MetadataExtractorLog { internal const string Tag = "Tizen.Multimedia.MetadataExtractor"; } /// /// Provides a means to get the metadata from a media file. /// public class MetadataExtractor : IDisposable { private bool _disposed = false; private IntPtr _handle = IntPtr.Zero; private IntPtr _buffer = IntPtr.Zero; private void Create(Func initFunc) { MetadataExtractorRetValidator.ThrowIfError( Interop.MetadataExtractor.Create(out _handle), "Failed to create metadata"); try { MetadataExtractorRetValidator.ThrowIfError(initFunc(), "Failed to init"); _metadata = new Lazy(() => new Metadata(Handle)); } catch { Release(); throw; } } /// /// Initializes a new instance of the MetadataExtractor class with the specified path. /// /// 3 /// The path for the file to extract the metadata. /// is null. /// does not exist. public MetadataExtractor(string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } Create(() => Interop.MetadataExtractor.SetPath(_handle, path)); } /// /// Initializes a new instance of the MetadataExtractor class with the specified buffer. /// /// 3 /// The buffer to extract the metadata. /// is null. /// The length of is zero. public MetadataExtractor(byte[] buffer) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (buffer.Length == 0) { throw new ArgumentException("buffer length is zero.", nameof(buffer)); } _buffer = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, _buffer, buffer.Length); try { Create(() => Interop.MetadataExtractor.SetBuffer(_handle, _buffer, buffer.Length)); } catch (Exception) { Marshal.FreeHGlobal(_buffer); throw; } } private IntPtr Handle { get { if (_disposed) { throw new ObjectDisposedException(nameof(MetadataExtractor)); } return _handle; } } private Lazy _metadata; /// /// Retrieves the . /// /// 3 /// The for the given source. /// An internal process error occurs. /// The has been already disposed of. public Metadata GetMetadata() { if (_disposed) { throw new ObjectDisposedException(nameof(MetadataExtractor)); } return _metadata.Value; } /// /// Gets the artwork image in the source. /// /// 3 /// The if it exists, otherwise null. /// An internal process error occurs. /// The has been already disposed of. public Artwork GetArtwork() { IntPtr data = IntPtr.Zero; IntPtr mimeType = IntPtr.Zero; try { int size = 0; var ret = Interop.MetadataExtractor.GetArtwork(Handle, out data, out size, out mimeType); MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value"); if (size > 0) { var buf = new byte[size]; Marshal.Copy(data, buf, 0, size); return new Artwork(buf, Marshal.PtrToStringAnsi(mimeType)); } return null; } finally { Interop.Libc.Free(data); Interop.Libc.Free(mimeType); } } /// /// Gets the sync lyrics of the source. /// /// 3 /// The index of lyrics to retrieve. /// The object if is valid, otherwise null. /// An internal process error occurs. /// The has been already disposed of. public SyncLyrics GetSyncLyrics(int index) { IntPtr lyrics = IntPtr.Zero; try { uint timestamp = 0; var ret = Interop.MetadataExtractor.GetSynclyrics(Handle, index, out timestamp, out lyrics); MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get sync lyrics"); if (lyrics == IntPtr.Zero) { return null; } return new SyncLyrics(Marshal.PtrToStringAnsi(lyrics), timestamp); } finally { Interop.Libc.Free(lyrics); } } /// /// Gets the frame of a video media. /// /// 3 /// The raw thumbnail data in RGB888 if it exists, otherwise null. /// An internal process error occurs. /// The has been already disposed of. public byte[] GetVideoThumbnail() { IntPtr data = IntPtr.Zero; try { int size = 0; var ret = Interop.MetadataExtractor.GetFrame(Handle, out data, out size); MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value"); if (size == 0) { return null; } var buf = new byte[size]; Marshal.Copy(data, buf, 0, size); return buf; } finally { Interop.Libc.Free(data); } } /// /// Gets the frame of a video media. /// /// 3 /// The timestamp in milliseconds. /// true to get an accurate frame for the given timestamp, /// otherwise false to get the nearest i-frame of the video rapidly. /// The raw frame data in RGB888 if a frame at specified time exists, otherwise null. /// An internal error occurs. /// The has been already disposed of. public byte[] GetFrameAt(uint timeStamp, bool accurate) { IntPtr data = IntPtr.Zero; try { int size = 0; var ret = Interop.MetadataExtractor.GetFrameAtTime(Handle, timeStamp, accurate, out data, out size); MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value"); if (size == 0) { return null; } var buf = new byte[size]; Marshal.Copy(data, buf, 0, size); return buf; } finally { Interop.Libc.Free(data); } } ~MetadataExtractor() { Dispose(false); } protected virtual void Dispose(bool disposing) { if (!_disposed) { Release(); _disposed = true; } } private void Release() { if (_buffer != IntPtr.Zero) { Marshal.FreeHGlobal(_buffer); } if (_handle != IntPtr.Zero) { var ret = Interop.MetadataExtractor.Destroy(_handle); Log.Error(MetadataExtractorLog.Tag, $"DestroyHandle failed : {ret}."); _handle = IntPtr.Zero; } } /// /// Releases all resources used by the object. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }