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.
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 public static class ThumbnailExtractor
32 private static Handle CreateHandle()
34 Native.Create(out var handle).ThrowIfError("Failed to extract.");
40 /// Extracts the thumbnail for the given media with the specified path.
42 /// <since_tizen> 3 </since_tizen>
43 /// <returns>A task that represents the asynchronous extracting operation.</returns>
44 /// <remarks>The size of the thumbnail will be the default size (320x240).</remarks>
45 /// <param name="path">The path of the media file to extract the thumbnail.</param>
46 /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
47 /// <exception cref="FileNotFoundException"><paramref name="path"/> does not exist.</exception>
48 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
49 /// <exception cref="UnauthorizedAccessException">The caller does not have required privilege for accessing the <paramref name="path"/>.</exception>
50 /// <exception cref="FileFormatException">The specified file is not supported.</exception>
51 public static Task<ThumbnailExtractionResult> ExtractAsync(string path)
53 return RunExtractAsync(path, null, CancellationToken.None);
57 /// Extracts the thumbnail for the given media with the specified path.
59 /// <returns>A task that represents the asynchronous extracting operation.</returns>
60 /// <remarks>The size of the thumbnail will be the default size(320x240).\n</remarks>
61 /// <param name="path">The path of the media file to extract the thumbnail.</param>
62 /// <param name="cancellationToken">The token to stop the operation.</param>
63 /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
64 /// <exception cref="FileNotFoundException"><paramref name="path"/> does not exist.</exception>
65 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
66 /// <exception cref="UnauthorizedAccessException">The caller does not have required privilege for accessing the <paramref name="path"/>.</exception>
67 /// <exception cref="FileFormatException">The specified file is not supported.</exception>
68 public static Task<ThumbnailExtractionResult> ExtractAsync(string path, CancellationToken cancellationToken)
70 return RunExtractAsync(path, null, cancellationToken);
74 /// Extracts the thumbnail for the given media with the specified path and size.
76 /// <since_tizen> 3 </since_tizen>
77 /// <returns>A task that represents the asynchronous extracting operation.</returns>
79 /// If the width is not a multiple of 8, it can be changed by the inner process.\n
80 /// The width will be a multiple of 8 greater than the set value.
82 /// <param name="path">The path of the media file to extract the thumbnail.</param>
83 /// <param name="size">The size of the thumbnail.</param>
84 /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
85 /// <exception cref="FileNotFoundException"><paramref name="path"/> does not exist.</exception>
86 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
87 /// <exception cref="UnauthorizedAccessException">The caller does not have required privilege for accessing the <paramref name="path"/>.</exception>
88 /// <exception cref="ArgumentOutOfRangeException">
89 /// The width or the height of <paramref name="size"/> is less than or equal to zero.
91 /// <exception cref="FileFormatException">The specified file is not supported.</exception>
92 public static Task<ThumbnailExtractionResult> ExtractAsync(string path, Size size)
94 return RunExtractAsync(path, size, CancellationToken.None);
98 /// Extracts the thumbnail for the given media with the specified path and size.
100 /// <since_tizen> 3 </since_tizen>
101 /// <returns>A task that represents the asynchronous extracting operation.</returns>
103 /// If the width is not a multiple of 8, it can be changed by the inner process.\n
104 /// The width will be a multiple of 8 greater than the set value.
106 /// <param name="path">The path of the media file to extract the thumbnail.</param>
107 /// <param name="size">The size of the thumbnail.</param>
108 /// <param name="cancellationToken">The token to stop the operation.</param>
109 /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
110 /// <exception cref="FileNotFoundException"><paramref name="path"/> does not exist.</exception>
111 /// <exception cref="InvalidOperationException">An internal error occurs.</exception>
112 /// <exception cref="UnauthorizedAccessException">The caller does not have required privilege for accessing the <paramref name="path"/>.</exception>
113 /// <exception cref="ArgumentOutOfRangeException">
114 /// The width or the height of <paramref name="size"/> is less than or equal to zero.
116 /// <exception cref="FileFormatException">The specified file is not supported.</exception>
117 public static Task<ThumbnailExtractionResult> ExtractAsync(string path, Size size,
118 CancellationToken cancellationToken)
120 return RunExtractAsync(path, size, cancellationToken);
123 private static Task<ThumbnailExtractionResult> RunExtractAsync(string path, Size? size,
124 CancellationToken cancellationToken)
128 throw new ArgumentNullException(nameof(path));
131 if (File.Exists(path) == false)
133 throw new FileNotFoundException("File does not exists.", path);
138 if (size.Value.Width <= 0)
140 throw new ArgumentOutOfRangeException(nameof(size), size.Value.Width,
141 "The width must be greater than zero.");
144 if (size.Value.Height <= 0)
146 throw new ArgumentOutOfRangeException(nameof(size), size.Value.Height,
147 "The height must be greater than zero.");
151 return cancellationToken.IsCancellationRequested ?
152 Task.FromCanceled<ThumbnailExtractionResult>(cancellationToken) :
153 ExtractAsyncCore(path, size, cancellationToken);
157 private static async Task<ThumbnailExtractionResult> ExtractAsyncCore(string path, Size? size,
158 CancellationToken cancellationToken)
160 using (var handle = CreateHandle())
162 Native.SetPath(handle, path).ThrowIfError("Failed to extract; failed to set the path.");
166 Native.SetSize(handle, size.Value.Width, size.Value.Height).
167 ThrowIfError("Failed to extract; failed to set the size");
170 var tcs = new TaskCompletionSource<ThumbnailExtractionResult>();
172 IntPtr id = IntPtr.Zero;
176 Native.Extract(handle, GetCallback(tcs), IntPtr.Zero, out id)
177 .ThrowIfError("Failed to extract.");
179 using (RegisterCancellationToken(tcs, cancellationToken, handle, Marshal.PtrToStringAnsi(id)))
181 return await tcs.Task;
186 LibcSupport.Free(id);
191 private static Native.ThumbnailExtractCallback GetCallback(TaskCompletionSource<ThumbnailExtractionResult> tcs)
193 return (error, requestId, thumbWidth, thumbHeight, thumbData, dataSize, _) =>
195 if (error == ThumbnailExtractorError.None)
199 byte[] tmpBuf = new byte[dataSize];
200 Marshal.Copy(thumbData, tmpBuf, 0, dataSize);
202 tcs.SetResult(new ThumbnailExtractionResult(tmpBuf, thumbWidth, thumbHeight));
206 tcs.SetException(new InvalidOperationException("[" + error + "] Failed to copy data.", e));
210 LibcSupport.Free(thumbData);
215 tcs.SetException(error.ToException("Failed to extract."));
220 private static IDisposable RegisterCancellationToken(TaskCompletionSource<ThumbnailExtractionResult> tcs,
221 CancellationToken cancellationToken, Handle handle, string id)
223 if (cancellationToken.CanBeCanceled == false)
228 return cancellationToken.Register(() =>
230 if (tcs.Task.IsCompleted)
235 Native.Cancel(handle, id).ThrowIfError("Failed to cancel.");
236 tcs.TrySetCanceled();