2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Runtime.InteropServices;
20 namespace Tizen.Multimedia
22 static internal class MetadataExtractorLog
24 internal const string Tag = "Tizen.Multimedia.MetadataExtractor";
28 /// Provides a set of functions to get the metadata from a media file.
30 public class MetadataExtractor : IDisposable
32 private bool _disposed = false;
33 private IntPtr _handle = IntPtr.Zero;
34 private IntPtr _buffer = IntPtr.Zero;
36 private void Create(Func<MetadataExtractorError> initFunc)
38 MetadataExtractorRetValidator.ThrowIfError(
39 Interop.MetadataExtractor.Create(out _handle), "Failed to create metadata");
43 MetadataExtractorRetValidator.ThrowIfError(initFunc(), "Failed to init");
45 _metadata = new Lazy<Metadata>(() => new Metadata(Handle));
55 /// Initialize a new instance of the MetadataExtractor class with the specified path.
57 /// <param name="path">The path for the file to extract metadata.</param>
58 /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
59 /// <exception cref="FileNotFoundException"><paramref name="path"/> is not exist.</exception>
60 public MetadataExtractor(string path)
64 throw new ArgumentNullException(nameof(path));
67 Create(() => Interop.MetadataExtractor.SetPath(_handle, path));
71 /// Initialize a new instance of the MetadataExtractor class with the specified buffer.
73 /// <param name="buffer">The buffer to extract metadata.</param>
74 /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception>
75 /// <exception cref="ArgumentException">The length of <paramref name="buffer"/> is zero.</exception>
76 public MetadataExtractor(byte[] buffer)
80 throw new ArgumentNullException(nameof(buffer));
83 if (buffer.Length == 0)
85 throw new ArgumentException("buffer length is zero.", nameof(buffer));
88 _buffer = Marshal.AllocHGlobal(buffer.Length);
89 Marshal.Copy(buffer, 0, _buffer, buffer.Length);
91 Create(() => Interop.MetadataExtractor.SetBuffer(_handle, _buffer, buffer.Length));
100 throw new ObjectDisposedException(nameof(MetadataExtractor));
107 private Lazy<Metadata> _metadata;
110 /// Retrieves the <see cref="Metadata"/>.
112 /// <returns>A <see cref="Metadata"/> for the give source.</returns>
113 /// <exception cref="InvalidOperationException">Internal process error is occurred.</exception>
114 /// <exception cref="ObjectDisposedException">The <see cref="MetadataExtractor"/> has been already disposed of.</exception>
115 public Metadata GetMetadata()
119 throw new ObjectDisposedException(nameof(MetadataExtractor));
122 return _metadata.Value;
126 /// Gets the artwork image in the source.
128 /// <returns>A <see cref="Artwork"/> if it exists, otherwise null.</returns>
129 /// <exception cref="InvalidOperationException">Internal process error is occurred.</exception>
130 /// <exception cref="ObjectDisposedException">The <see cref="MetadataExtractor"/> has been already disposed of.</exception>
131 public Artwork GetArtwork()
133 IntPtr data = IntPtr.Zero;
134 IntPtr mimeType = IntPtr.Zero;
140 var ret = Interop.MetadataExtractor.GetArtwork(Handle, out data, out size, out mimeType);
141 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
145 var buf = new byte[size];
146 Marshal.Copy(data, buf, 0, size);
148 return new Artwork(buf, Marshal.PtrToStringAnsi(mimeType));
155 Interop.Libc.Free(data);
156 Interop.Libc.Free(mimeType);
161 /// Gets the sync lyrics of the source.
163 /// <param name="index">The index of lyrics to retrieve.</param>
164 /// <returns>A <see cref="SyncLyrics"/> object if <paramref name="index"/> is valid, otherwise null.</returns>
165 /// <exception cref="InvalidOperationException">Internal process error is occurred.</exception>
166 /// <exception cref="ObjectDisposedException">The <see cref="MetadataExtractor"/> has been already disposed of.</exception>
167 public SyncLyrics GetSyncLyrics(int index)
169 IntPtr lyrics = IntPtr.Zero;
175 var ret = Interop.MetadataExtractor.GetSynclyrics(Handle, index, out timestamp, out lyrics);
176 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get sync lyrics");
178 if (lyrics == IntPtr.Zero)
183 return new SyncLyrics(Marshal.PtrToStringAnsi(lyrics), timestamp);
187 Interop.Libc.Free(lyrics);
192 /// Gets the frame of a video media.
194 /// <returns>The raw thumbnail data in RGB888 if it exists, otherwise null.</returns>
195 /// <exception cref="InvalidOperationException">Internal process error is occurred.</exception>
196 /// <exception cref="ObjectDisposedException">The <see cref="MetadataExtractor"/> has been already disposed of.</exception>
197 public byte[] GetVideoThumbnail()
199 IntPtr data = IntPtr.Zero;
205 var ret = Interop.MetadataExtractor.GetFrame(Handle, out data, out size);
206 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
213 var buf = new byte[size];
214 Marshal.Copy(data, buf, 0, size);
220 Interop.Libc.Free(data);
225 /// Gets the frame of a video media.
227 /// <param name="timeStamp">The timestamp in milliseconds.</param>
228 /// <param name="accurate">true to get an accurate frame for the given timestamp,
229 /// otherwise false to get the nearest i-frame of the video rapidly.</param>
230 /// <returns>The raw frame data in RGB888 if a frame at specified time exists, otherwise null.</returns>
231 /// <exception cref="InvalidOperationException"> When internal process error is occured</exception>
232 /// <exception cref="ObjectDisposedException">The <see cref="MetadataExtractor"/> has been already disposed of.</exception>
233 public byte[] GetFrameAt(uint timeStamp, bool accurate)
235 IntPtr data = IntPtr.Zero;
241 var ret = Interop.MetadataExtractor.GetFrameAtTime(Handle, timeStamp, accurate, out data, out size);
242 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
249 var buf = new byte[size];
250 Marshal.Copy(data, buf, 0, size);
256 Interop.Libc.Free(data);
261 /// Metadata Extractor destructor
268 protected virtual void Dispose(bool disposing)
277 private void Release()
279 if (_buffer != IntPtr.Zero)
281 Marshal.FreeHGlobal(_buffer);
284 if (_handle != IntPtr.Zero)
286 var ret = Interop.MetadataExtractor.Destroy(_handle);
287 Log.Error(MetadataExtractorLog.Tag, $"DestroyHandle failed : {ret}.");
289 _handle = IntPtr.Zero;
293 public void Dispose()
296 GC.SuppressFinalize(this);