Setting since_tizen 3/4 on Tizen.NET API
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Metadata / MetadataExtractor / MetadataExtractor.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 using System;
18 using System.IO;
19 using System.Runtime.InteropServices;
20
21 namespace Tizen.Multimedia
22 {
23     /// <summary>
24     /// Provides a means to get the metadata from a media file.
25     /// </summary>
26     /// <since_tizen> 3 </since_tizen>
27     public class MetadataExtractor : IDisposable
28     {
29         private bool _disposed = false;
30         private IntPtr _handle = IntPtr.Zero;
31         private IntPtr _buffer = IntPtr.Zero;
32
33         private void Create(Func<MetadataExtractorError> initFunc)
34         {
35             MetadataExtractorRetValidator.ThrowIfError(
36                 Interop.MetadataExtractor.Create(out _handle), "Failed to create metadata");
37
38             try
39             {
40                 MetadataExtractorRetValidator.ThrowIfError(initFunc(), "Failed to init");
41
42                 _metadata = new Lazy<Metadata>(() => new Metadata(this));
43             }
44             catch
45             {
46                 Release();
47                 throw;
48             }
49         }
50
51         /// <summary>
52         /// Initializes a new instance of the MetadataExtractor class with the specified path.
53         /// </summary>
54         /// <since_tizen> 3 </since_tizen>
55         /// <param name="path">The path for the file to extract the metadata.</param>
56         /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
57         /// <exception cref="FileNotFoundException"><paramref name="path"/> does not exist.</exception>
58         public MetadataExtractor(string path)
59         {
60             if (path == null)
61             {
62                 throw new ArgumentNullException(nameof(path));
63             }
64
65             Create(() => Interop.MetadataExtractor.SetPath(_handle, path));
66         }
67
68         /// <summary>
69         /// Initializes a new instance of the MetadataExtractor class with the specified buffer.
70         /// </summary>
71         /// <since_tizen> 3 </since_tizen>
72         /// <param name="buffer">The buffer to extract the metadata.</param>
73         /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception>
74         /// <exception cref="ArgumentException">The length of <paramref name="buffer"/> is zero.</exception>
75         public MetadataExtractor(byte[] buffer)
76         {
77             if (buffer == null)
78             {
79                 throw new ArgumentNullException(nameof(buffer));
80             }
81
82             if (buffer.Length == 0)
83             {
84                 throw new ArgumentException("buffer length is zero.", nameof(buffer));
85             }
86
87             _buffer = Marshal.AllocHGlobal(buffer.Length);
88             Marshal.Copy(buffer, 0, _buffer, buffer.Length);
89
90             try
91             {
92                 Create(() => Interop.MetadataExtractor.SetBuffer(_handle, _buffer, buffer.Length));
93             }
94             catch (Exception)
95             {
96                 Marshal.FreeHGlobal(_buffer);
97                 throw;
98             }
99         }
100
101         internal IntPtr Handle
102         {
103             get
104             {
105                 if (_disposed)
106                 {
107                     throw new ObjectDisposedException(nameof(MetadataExtractor));
108                 }
109
110                 return _handle;
111             }
112         }
113
114         private Lazy<Metadata> _metadata;
115
116         /// <summary>
117         /// Retrieves the <see cref="Metadata"/>.
118         /// </summary>
119         /// <since_tizen> 3 </since_tizen>
120         /// <returns>The <see cref="Metadata"/> for the given source.</returns>
121         /// <exception cref="InvalidOperationException">An internal process error occurs.</exception>
122         /// <exception cref="ObjectDisposedException">The <see cref="MetadataExtractor"/> has been already disposed of.</exception>
123         public Metadata GetMetadata()
124         {
125             if (_disposed)
126             {
127                 throw new ObjectDisposedException(nameof(MetadataExtractor));
128             }
129
130             return _metadata.Value;
131         }
132
133         /// <summary>
134         /// Gets the artwork image in the source.
135         /// </summary>
136         /// <since_tizen> 3 </since_tizen>
137         /// <returns>The <see cref="Artwork"/> if it exists, otherwise null.</returns>
138         /// <exception cref="InvalidOperationException">An internal process error occurs.</exception>
139         /// <exception cref="ObjectDisposedException">The <see cref="MetadataExtractor"/> has been already disposed of.</exception>
140         public Artwork GetArtwork()
141         {
142             IntPtr data = IntPtr.Zero;
143             IntPtr mimeType = IntPtr.Zero;
144
145             try
146             {
147                 int size = 0;
148
149                 var ret = Interop.MetadataExtractor.GetArtwork(Handle, out data, out size, out mimeType);
150                 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
151
152                 if (size > 0)
153                 {
154                     var buf = new byte[size];
155                     Marshal.Copy(data, buf, 0, size);
156
157                     return new Artwork(buf, Marshal.PtrToStringAnsi(mimeType));
158                 }
159
160                 return null;
161             }
162             finally
163             {
164                 Interop.Libc.Free(data);
165                 Interop.Libc.Free(mimeType);
166             }
167         }
168
169         /// <summary>
170         /// Gets the sync lyrics of the source.
171         /// </summary>
172         /// <since_tizen> 3 </since_tizen>
173         /// <param name="index">The index of lyrics to retrieve.</param>
174         /// <returns>The <see cref="SyncLyrics"/> object if <paramref name="index"/> is valid, otherwise null.</returns>
175         /// <exception cref="InvalidOperationException">An internal process error occurs.</exception>
176         /// <exception cref="ObjectDisposedException">The <see cref="MetadataExtractor"/> has been already disposed of.</exception>
177         public SyncLyrics GetSyncLyrics(int index)
178         {
179             IntPtr lyrics = IntPtr.Zero;
180
181             try
182             {
183                 uint timestamp = 0;
184
185                 var ret = Interop.MetadataExtractor.GetSynclyrics(Handle, index, out timestamp, out lyrics);
186                 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get sync lyrics");
187
188                 if (lyrics == IntPtr.Zero)
189                 {
190                     return null;
191                 }
192
193                 return new SyncLyrics(Marshal.PtrToStringAnsi(lyrics), timestamp);
194             }
195             finally
196             {
197                 Interop.Libc.Free(lyrics);
198             }
199         }
200
201         /// <summary>
202         /// Gets the frame of a video media.
203         /// </summary>
204         /// <since_tizen> 3 </since_tizen>
205         /// <returns>The raw thumbnail data in RGB888 if it exists, otherwise null.</returns>
206         /// <exception cref="InvalidOperationException">An internal process error occurs.</exception>
207         /// <exception cref="ObjectDisposedException">The <see cref="MetadataExtractor"/> has been already disposed of.</exception>
208         public byte[] GetVideoThumbnail()
209         {
210             IntPtr data = IntPtr.Zero;
211
212             try
213             {
214                 int size = 0;
215
216                 var ret = Interop.MetadataExtractor.GetFrame(Handle, out data, out size);
217                 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
218
219                 if (size == 0)
220                 {
221                     return null;
222                 }
223
224                 var buf = new byte[size];
225                 Marshal.Copy(data, buf, 0, size);
226
227                 return buf;
228             }
229             finally
230             {
231                 Interop.Libc.Free(data);
232             }
233         }
234
235         /// <summary>
236         /// Gets the frame of a video media.
237         /// </summary>
238         /// <since_tizen> 3 </since_tizen>
239         /// <param name="timeStamp">The timestamp in milliseconds.</param>
240         /// <param name="accurate">true to get an accurate frame for the given timestamp,
241         ///     otherwise false to get the nearest i-frame of the video rapidly.</param>
242         /// <returns>The raw frame data in RGB888 if a frame at specified time exists, otherwise null.</returns>
243         /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
244         /// <exception cref="ObjectDisposedException">The <see cref="MetadataExtractor"/> has been already disposed of.</exception>
245         public byte[] GetFrameAt(uint timeStamp, bool accurate)
246         {
247             IntPtr data = IntPtr.Zero;
248
249             try
250             {
251                 int size = 0;
252
253                 var ret = Interop.MetadataExtractor.GetFrameAtTime(Handle, timeStamp, accurate, out data, out size);
254                 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
255
256                 if (size == 0)
257                 {
258                     return null;
259                 }
260
261                 var buf = new byte[size];
262                 Marshal.Copy(data, buf, 0, size);
263
264                 return buf;
265             }
266             finally
267             {
268                 Interop.Libc.Free(data);
269             }
270         }
271
272         /// <summary>
273         /// Finalizes an instance of the MetadataExtractor class.
274         /// </summary>
275         ~MetadataExtractor()
276         {
277             Dispose(false);
278         }
279
280         /// <summary>
281         /// Releases the resources used by the <see cref="MetadataExtractor"/> object.
282         /// </summary>
283         /// <param name="disposing">
284         /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
285         /// </param>
286         /// <since_tizen> 3 </since_tizen>
287         protected virtual void Dispose(bool disposing)
288         {
289             if (!_disposed)
290             {
291                 Release();
292                 _disposed = true;
293             }
294         }
295
296         private void Release()
297         {
298             if (_buffer != IntPtr.Zero)
299             {
300                 Marshal.FreeHGlobal(_buffer);
301                 _buffer = IntPtr.Zero;
302             }
303
304             if (_handle != IntPtr.Zero)
305             {
306                 var ret = Interop.MetadataExtractor.Destroy(_handle);
307                 if (ret != MetadataExtractorError.None)
308                 {
309                     Log.Error(typeof(MetadataExtractor).FullName, $"DestroyHandle failed : {ret}.");
310                 }
311
312                 _handle = IntPtr.Zero;
313             }
314         }
315
316         /// <summary>
317         /// Releases all resources used by the <see cref="MetadataExtractor"/> object.
318         /// </summary>
319         /// <since_tizen> 3 </since_tizen>
320         public void Dispose()
321         {
322             Dispose(true);
323             GC.SuppressFinalize(this);
324         }
325     }
326 }