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