2 * Copyright (c) 2018 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.
19 using System.Runtime.InteropServices;
20 using System.Threading;
21 using System.Threading.Tasks;
22 using Handle = Interop.ThumbnailExtractorHandle;
23 using Native = Interop.ThumbnailExtractor;
25 namespace Tizen.Multimedia.Util
28 /// Provides the ability to extract the thumbnail from media files.
30 /// <since_tizen> 4 </since_tizen>
31 public static class ThumbnailExtractor
33 private static Handle CreateHandle()
35 Native.Create(out var handle).ThrowIfError("Failed to extract.");
41 /// Extracts the thumbnail for the given media with the specified path.
43 /// <since_tizen> 4 </since_tizen>
44 /// <returns>A task that represents the asynchronous extracting operation.</returns>
45 /// <remarks>The size of the thumbnail will be the default size (320x240).</remarks>
46 /// <param name="path">The path of the media file to extract the thumbnail.</param>
47 /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
48 /// <exception cref="FileNotFoundException"><paramref name="path"/> does not exist.</exception>
49 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
50 /// <exception cref="UnauthorizedAccessException">The caller does not have required privilege for accessing the <paramref name="path"/>.</exception>
51 /// <exception cref="FileFormatException">The specified file is not supported.</exception>
52 public static Task<ThumbnailExtractionResult> ExtractAsync(string path)
54 return RunExtractAsync(path, null, CancellationToken.None);
58 /// Extracts the thumbnail for the given media with the specified path.
60 /// <returns>A task that represents the asynchronous extracting operation.</returns>
61 /// <remarks>The size of the thumbnail will be the default size(320x240).</remarks>
62 /// <param name="path">The path of the media file to extract the thumbnail.</param>
63 /// <param name="cancellationToken">The token to stop the operation.</param>
64 /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
65 /// <exception cref="FileNotFoundException"><paramref name="path"/> does not exist.</exception>
66 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
67 /// <exception cref="UnauthorizedAccessException">The caller does not have required privilege for accessing the <paramref name="path"/>.</exception>
68 /// <exception cref="FileFormatException">The specified file is not supported.</exception>
69 /// <since_tizen> 4 </since_tizen>
70 public static Task<ThumbnailExtractionResult> ExtractAsync(string path, CancellationToken cancellationToken)
72 return RunExtractAsync(path, null, cancellationToken);
76 /// Extracts the thumbnail for the given media with the specified path and size.
78 /// <since_tizen> 4 </since_tizen>
79 /// <returns>A task that represents the asynchronous extracting operation.</returns>
81 /// If the width is not a multiple of 8, it can be changed by the inner process.<br/>
82 /// The width will be a multiple of 8 greater than the set value.
84 /// <param name="path">The path of the media file to extract the thumbnail.</param>
85 /// <param name="size">The size of the thumbnail.</param>
86 /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
87 /// <exception cref="FileNotFoundException"><paramref name="path"/> does not exist.</exception>
88 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
89 /// <exception cref="UnauthorizedAccessException">The caller does not have required privilege for accessing the <paramref name="path"/>.</exception>
90 /// <exception cref="ArgumentOutOfRangeException">
91 /// The width or the height of <paramref name="size"/> is less than or equal to zero.
93 /// <exception cref="FileFormatException">The specified file is not supported.</exception>
94 public static Task<ThumbnailExtractionResult> ExtractAsync(string path, Size size)
96 return RunExtractAsync(path, size, CancellationToken.None);
100 /// Extracts the thumbnail for the given media with the specified path and size.
102 /// <since_tizen> 4 </since_tizen>
103 /// <returns>A task that represents the asynchronous extracting operation.</returns>
105 /// If the width is not a multiple of 8, it can be changed by the inner process.<br/>
106 /// The width will be a multiple of 8 greater than the set value.
108 /// <param name="path">The path of the media file to extract the thumbnail.</param>
109 /// <param name="size">The size of the thumbnail.</param>
110 /// <param name="cancellationToken">The token to stop the operation.</param>
111 /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
112 /// <exception cref="FileNotFoundException"><paramref name="path"/> does not exist.</exception>
113 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
114 /// <exception cref="UnauthorizedAccessException">The caller does not have required privilege for accessing the <paramref name="path"/>.</exception>
115 /// <exception cref="ArgumentOutOfRangeException">
116 /// The width or the height of <paramref name="size"/> is less than or equal to zero.
118 /// <exception cref="FileFormatException">The specified file is not supported.</exception>
119 public static Task<ThumbnailExtractionResult> ExtractAsync(string path, Size size,
120 CancellationToken cancellationToken)
122 return RunExtractAsync(path, size, cancellationToken);
125 private static Task<ThumbnailExtractionResult> RunExtractAsync(string path, Size? size,
126 CancellationToken cancellationToken)
130 throw new ArgumentNullException(nameof(path));
133 if (File.Exists(path) == false)
135 throw new FileNotFoundException("File does not exists.", path);
140 if (size.Value.Width <= 0)
142 throw new ArgumentOutOfRangeException(nameof(size), size.Value.Width,
143 "The width must be greater than zero.");
146 if (size.Value.Height <= 0)
148 throw new ArgumentOutOfRangeException(nameof(size), size.Value.Height,
149 "The height must be greater than zero.");
153 return cancellationToken.IsCancellationRequested ?
154 Task.FromCanceled<ThumbnailExtractionResult>(cancellationToken) :
155 ExtractAsyncCore(path, size, cancellationToken);
159 private static async Task<ThumbnailExtractionResult> ExtractAsyncCore(string path, Size? size,
160 CancellationToken cancellationToken)
162 using (var handle = CreateHandle())
164 Native.SetPath(handle, path).ThrowIfError("Failed to extract; failed to set the path.");
168 Native.SetSize(handle, size.Value.Width, size.Value.Height).
169 ThrowIfError("Failed to extract; failed to set the size");
172 var tcs = new TaskCompletionSource<ThumbnailExtractionResult>();
174 IntPtr id = IntPtr.Zero;
178 var cb = GetCallback(tcs);
179 using (var cbKeeper = ObjectKeeper.Get(cb))
181 Native.Extract(handle, cb, IntPtr.Zero, out id)
182 .ThrowIfError("Failed to extract.");
184 using (RegisterCancellationToken(tcs, cancellationToken, handle, Marshal.PtrToStringAnsi(id)))
186 return await tcs.Task;
192 LibcSupport.Free(id);
197 private static Native.ThumbnailExtractCallback GetCallback(TaskCompletionSource<ThumbnailExtractionResult> tcs)
199 return (error, requestId, thumbWidth, thumbHeight, thumbData, dataSize, _) =>
201 if (error == ThumbnailExtractorError.None)
205 byte[] tmpBuf = new byte[dataSize];
206 Marshal.Copy(thumbData, tmpBuf, 0, dataSize);
208 tcs.TrySetResult(new ThumbnailExtractionResult(tmpBuf, thumbWidth, thumbHeight));
212 tcs.TrySetException(new InvalidOperationException("[" + error + "] Failed to copy data.", e));
216 LibcSupport.Free(thumbData);
221 tcs.TrySetException(error.ToException("Failed to extract."));
226 private static IDisposable RegisterCancellationToken(TaskCompletionSource<ThumbnailExtractionResult> tcs,
227 CancellationToken cancellationToken, Handle handle, string id)
229 if (cancellationToken.CanBeCanceled == false)
234 return cancellationToken.Register(() =>
236 if (tcs.Task.IsCompleted)
241 Native.Cancel(handle, id).ThrowIfError("Failed to cancel.");
242 tcs.TrySetCanceled();