[MetadataEditor/MetadataExtractor/ThumbnailExtractor] Apply C# coding rule
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia / 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.Runtime.InteropServices;
19
20 namespace Tizen.Multimedia
21 {
22     static internal class MetadataExtractorLog
23     {
24         internal const string Tag = "Tizen.Multimedia.MetadataExtractor";
25     }
26
27     /// <summary>
28     /// Provides a set of functions to get the metadata from a media file.
29     /// </summary>
30     public class MetadataExtractor : IDisposable
31     {
32         private bool _disposed = false;
33         private IntPtr _handle = IntPtr.Zero;
34         private IntPtr _buffer = IntPtr.Zero;
35
36         private void Create(Func<MetadataExtractorError> initFunc)
37         {
38             MetadataExtractorRetValidator.ThrowIfError(
39                 Interop.MetadataExtractor.Create(out _handle), "Failed to create metadata");
40
41             try
42             {
43                 MetadataExtractorRetValidator.ThrowIfError(initFunc(), "Failed to init");
44
45                 _metadata = new Lazy<Metadata>(() => new Metadata(Handle));
46             }
47             catch
48             {
49                 Release();
50                 throw;
51             }
52         }
53
54         /// <summary>
55         /// Initialize a new instance of the MetadataExtractor class with the specified path.
56         /// </summary>
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)
61         {
62             if (path == null)
63             {
64                 throw new ArgumentNullException(nameof(path));
65             }
66
67             Create(() => Interop.MetadataExtractor.SetPath(_handle, path));
68         }
69
70         /// <summary>
71         /// Initialize a new instance of the MetadataExtractor class with the specified buffer.
72         /// </summary>
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)
77         {
78             if (buffer == null)
79             {
80                 throw new ArgumentNullException(nameof(buffer));
81             }
82
83             if (buffer.Length == 0)
84             {
85                 throw new ArgumentException("buffer length is zero.", nameof(buffer));
86             }
87
88             _buffer = Marshal.AllocHGlobal(buffer.Length);
89             Marshal.Copy(buffer, 0, _buffer, buffer.Length);
90
91             Create(() => Interop.MetadataExtractor.SetBuffer(_handle, _buffer, buffer.Length));
92         }
93
94         private IntPtr Handle
95         {
96             get
97             {
98                 if (_disposed)
99                 {
100                     throw new ObjectDisposedException(nameof(MetadataExtractor));
101                 }
102
103                 return _handle;
104             }
105         }
106
107         private Lazy<Metadata> _metadata;
108
109         /// <summary>
110         /// Retrieves the <see cref="Metadata"/>.
111         /// </summary>
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()
116         {
117             if (_disposed)
118             {
119                 throw new ObjectDisposedException(nameof(MetadataExtractor));
120             }
121
122             return _metadata.Value;
123         }
124
125         /// <summary>
126         /// Gets the artwork image in the source.
127         /// </summary>
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()
132         {
133             IntPtr data = IntPtr.Zero;
134             IntPtr mimeType = IntPtr.Zero;
135
136             try
137             {
138                 int size = 0;
139
140                 var ret = Interop.MetadataExtractor.GetArtwork(Handle, out data, out size, out mimeType);
141                 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
142
143                 if (size > 0)
144                 {
145                     var buf = new byte[size];
146                     Marshal.Copy(data, buf, 0, size);
147
148                     return new Artwork(buf, Marshal.PtrToStringAnsi(mimeType));
149                 }
150
151                 return null;
152             }
153             finally
154             {
155                 Interop.Libc.Free(data);
156                 Interop.Libc.Free(mimeType);
157             }
158         }
159
160         /// <summary>
161         /// Gets the sync lyrics of the source.
162         /// </summary>
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)
168         {
169             IntPtr lyrics = IntPtr.Zero;
170
171             try
172             {
173                 uint timestamp = 0;
174
175                 var ret = Interop.MetadataExtractor.GetSynclyrics(Handle, index, out timestamp, out lyrics);
176                 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get sync lyrics");
177
178                 if (lyrics == IntPtr.Zero)
179                 {
180                     return null;
181                 }
182
183                 return new SyncLyrics(Marshal.PtrToStringAnsi(lyrics), timestamp);
184             }
185             finally
186             {
187                 Interop.Libc.Free(lyrics);
188             }
189         }
190
191         /// <summary>
192         /// Gets the frame of a video media.
193         /// </summary>
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()
198         {
199             IntPtr data = IntPtr.Zero;
200
201             try
202             {
203                 int size = 0;
204
205                 var ret = Interop.MetadataExtractor.GetFrame(Handle, out data, out size);
206                 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
207
208                 if (size == 0)
209                 {
210                     return null;
211                 }
212
213                 var buf = new byte[size];
214                 Marshal.Copy(data, buf, 0, size);
215
216                 return buf;
217             }
218             finally
219             {
220                 Interop.Libc.Free(data);
221             }
222         }
223
224         /// <summary>
225         /// Gets the frame of a video media.
226         /// </summary>
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)
234         {
235             IntPtr data = IntPtr.Zero;
236
237             try
238             {
239                 int size = 0;
240
241                 var ret = Interop.MetadataExtractor.GetFrameAtTime(Handle, timeStamp, accurate, out data, out size);
242                 MetadataExtractorRetValidator.ThrowIfError(ret, "Failed to get value");
243
244                 if (size == 0)
245                 {
246                     return null;
247                 }
248
249                 var buf = new byte[size];
250                 Marshal.Copy(data, buf, 0, size);
251
252                 return buf;
253             }
254             finally
255             {
256                 Interop.Libc.Free(data);
257             }
258         }
259
260         /// <summary>
261         /// Metadata Extractor destructor
262         /// </summary>
263         ~MetadataExtractor()
264         {
265             Dispose(false);
266         }
267
268         protected virtual void Dispose(bool disposing)
269         {
270             if (!_disposed)
271             {
272                 Release();
273                 _disposed = true;
274             }
275         }
276
277         private void Release()
278         {
279             if (_buffer != IntPtr.Zero)
280             {
281                 Marshal.FreeHGlobal(_buffer);
282             }
283
284             if (_handle != IntPtr.Zero)
285             {
286                 var ret = Interop.MetadataExtractor.Destroy(_handle);
287                 Log.Error(MetadataExtractorLog.Tag, $"DestroyHandle failed : {ret}.");
288
289                 _handle = IntPtr.Zero;
290             }
291         }
292
293         public void Dispose()
294         {
295             Dispose(true);
296             GC.SuppressFinalize(this);
297         }
298     }
299 }