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.
18 using System.Collections.Generic;
19 using System.Diagnostics;
21 using System.Runtime.InteropServices;
22 using System.Threading;
23 using Native = Interop.Camera;
25 namespace Tizen.Multimedia
27 static internal class CameraLog
29 internal const string Tag = "Tizen.Multimedia.Camera";
30 internal const string Enter = "[Enter]";
31 internal const string Leave = "[Leave]";
35 /// This camera class provides methods to capture photos and supports setting up notifications
36 /// for state changes of capturing, previewing, focusing, and informing about the resolution and the binary format,
37 /// and functions for picture manipulations like sepia, negative, and many more.
38 /// It also notifies you when a significant picture parameter changes, (For example, focus).
40 /// <since_tizen> 3 </since_tizen>
41 /// <feature> http://tizen.org/feature/camera </feature>
42 public partial class Camera : IDisposable, IDisplayable<CameraError>
44 private IntPtr _handle = IntPtr.Zero;
45 private bool _disposed = false;
46 private CameraState _state = CameraState.None;
49 /// Initializes a new instance of the <see cref="Camera"/> class.
51 /// <param name="device">The camera device to access.</param>
52 /// <exception cref="ArgumentException">Invalid CameraDevice type.</exception>
53 /// <exception cref="NotSupportedException">The camera feature is not supported.</exception>
54 /// <since_tizen> 3 </since_tizen>
55 /// <feature> http://tizen.org/feature/camera </feature>
56 public Camera(CameraDevice device)
58 Native.Create(device, out _handle).ThrowIfFailed("Failed to create camera instance");
60 Capabilities = new CameraCapabilities(this);
61 Settings = new CameraSettings(this);
62 DisplaySettings = new CameraDisplaySettings(this);
66 SetState(CameraState.Created);
70 /// Finalizes an instance of the Camera class.
78 /// Gets the native handle of the camera.
80 /// <since_tizen> 3 </since_tizen>
81 /// <feature> http://tizen.org/feature/camera </feature>
82 public IntPtr Handle => GetHandle();
84 internal IntPtr GetHandle()
86 ValidateNotDisposed();
90 #region Dispose support
92 /// Releases the unmanaged resources used by the camera.
94 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
95 /// <since_tizen> 3 </since_tizen>
96 protected virtual void Dispose(bool disposing)
102 // to be used if there are any other disposable objects
105 if (_handle != IntPtr.Zero)
107 Native.Destroy(_handle);
108 _handle = IntPtr.Zero;
116 /// Releases all resources used by the camera.
118 /// <since_tizen> 3 </since_tizen>
119 /// <feature> http://tizen.org/feature/camera </feature>
120 public void Dispose()
122 ReplaceDisplay(null);
124 GC.SuppressFinalize(this);
127 internal void ValidateNotDisposed()
131 Log.Error(CameraLog.Tag, "Camera handle is disposed.");
132 throw new ObjectDisposedException(nameof(Camera));
135 #endregion Dispose support
137 #region Check camera state
138 internal void ValidateState(params CameraState[] required)
140 ValidateNotDisposed();
142 Debug.Assert(required.Length > 0);
144 var curState = _state;
145 if (!required.Contains(curState))
147 throw new InvalidOperationException($"The camera is not in a valid state. " +
148 $"Current State : { curState }, Valid State : { string.Join(", ", required) }.");
152 internal void SetState(CameraState state)
156 #endregion Check camera state
162 /// Changes the camera device.
164 /// <param name="device">The hardware camera to access.</param>
165 /// <since_tizen> 3 </since_tizen>
166 /// <feature> http://tizen.org/feature/camera </feature>
168 /// If display reuse is set using <see cref="DisplayReuseHint"/>
169 /// before stopping the preview, the display will be reused and last frame on the display
170 /// can be kept even though camera device is changed.
171 /// The camera must be in the <see cref="CameraState.Created"/>.
173 /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
174 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
175 /// <exception cref="NotSupportedException">In case of the ChangeDevice feature is not supported.</exception>
176 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
177 public void ChangeDevice(CameraDevice device)
179 ValidateState(CameraState.Created);
180 ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
182 Native.ChangeDevice(_handle, device).ThrowIfFailed("Failed to change the camera device");
186 /// Gets the device state.
188 /// <param name="device">The device to get the state.</param>
189 /// <returns>Returns the state of the camera device.</returns>
190 /// <since_tizen> 4 </since_tizen>
191 /// <feature> http://tizen.org/feature/camera </feature>
192 /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
193 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
194 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
195 public static CameraDeviceState GetDeviceState(CameraDevice device)
197 ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
199 Native.GetDeviceState(device, out var val).ThrowIfFailed("Failed to get the camera device state.");
205 /// Gets the flash state.
207 /// <param name="device">The device to get the state.</param>
208 /// <returns>Returns the flash state of the camera device.</returns>
209 /// <since_tizen> 3 </since_tizen>
210 /// <feature> http://tizen.org/feature/camera </feature>
211 /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
212 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
213 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
214 public static CameraFlashState GetFlashState(CameraDevice device)
216 ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
218 Native.GetFlashState(device, out var val).ThrowIfFailed("Failed to get camera flash state");
224 /// Starts capturing and drawing preview frames on the screen.
225 /// The display property must be set using <see cref="Display"/> before using this method.
226 /// If needed set fps <see cref="CameraSettings.PreviewFps"/>, preview resolution
227 /// <see cref="CameraSettings.PreviewResolution"/>, or preview format <see cref="CameraSettings.PreviewPixelFormat"/>
228 /// before using this method.
229 /// The camera must be in the <see cref="CameraState.Created"/> or the <see cref="CameraState.Captured"/> state.
231 /// <since_tizen> 3 </since_tizen>
232 /// <privilege> http://tizen.org/privilege/camera </privilege>
233 /// <feature> http://tizen.org/feature/camera </feature>
234 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
235 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
236 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
237 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
238 public void StartPreview()
240 ValidateState(CameraState.Created, CameraState.Captured);
242 Native.StartPreview(_handle).ThrowIfFailed("Failed to start the camera preview.");
244 // Update by StateChangedCallback can be delayed for dozens of milliseconds.
245 SetState(CameraState.Preview);
249 /// Stops capturing and drawing preview frames on the screen.
250 /// The camera must be in the <see cref="CameraState.Preview"/> state.
252 /// <since_tizen> 3 </since_tizen>
253 /// <privilege> http://tizen.org/privilege/camera </privilege>
254 /// <feature> http://tizen.org/feature/camera </feature>
255 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
256 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
257 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
258 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
259 public void StopPreview()
261 ValidateState(CameraState.Preview);
263 Native.StopPreview(_handle).ThrowIfFailed("Failed to stop the camera preview.");
265 SetState(CameraState.Created);
269 /// Starts capturing of still images.
270 /// EventHandler must be set for capturing using <see cref="Capturing"/>
271 /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
272 /// The camera must be in the <see cref="CameraState.Preview"/> state.
274 /// <since_tizen> 3 </since_tizen>
275 /// <privilege> http://tizen.org/privilege/camera </privilege>
276 /// <feature> http://tizen.org/feature/camera </feature>
278 /// This function causes the transition of the camera state from capturing to captured
279 /// automatically and the corresponding EventHandlers will be invoked.
280 /// The preview should be restarted by calling the <see cref="StartPreview"/> method after capture is completed.
282 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
283 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
284 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
285 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
286 public void StartCapture()
288 ValidateState(CameraState.Preview);
290 Native.StartCapture(_handle, _capturingCallback, _captureCompletedCallback).
291 ThrowIfFailed("Failed to start the camera capture.");
293 SetState(CameraState.Capturing);
297 /// Starts continuously capturing still images.
298 /// EventHandler must be set for capturing using <see cref="Capturing"/>
299 /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
300 /// The camera must be in the <see cref="CameraState.Preview"/> state.
302 /// <param name="count">The number of still images.</param>
303 /// <param name="interval">The interval of the capture(milliseconds).</param>
304 /// <param name="cancellationToken">The cancellation token to cancel capturing.</param>
305 /// <seealso cref="CancellationToken"/>
306 /// <since_tizen> 3 </since_tizen>
307 /// <privilege> http://tizen.org/privilege/camera </privilege>
308 /// <feature> http://tizen.org/feature/camera </feature>
310 /// If this is not supported, zero shutter lag occurs. The capture resolution could be
311 /// changed to the preview resolution. This function causes the transition of the camera state
312 /// from capturing to captured automatically and the corresponding Eventhandlers will be invoked.
313 /// Each captured image will be delivered through Eventhandler set using the <see cref="Capturing"/> event.
314 /// The preview should be restarted by calling the <see cref="StartPreview"/> method after capture is completed.
316 /// <exception cref="ArgumentOutOfRangeException">In case of invalid parameters.</exception>
317 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
318 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
319 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
320 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
321 public void StartCapture(int count, int interval, CancellationToken cancellationToken)
323 ValidateState(CameraState.Preview);
327 throw new ArgumentOutOfRangeException(nameof(count), count, $"{nameof(count)} should be greater than one.");
332 throw new ArgumentOutOfRangeException(nameof(interval), interval, $"{nameof(interval)} should be greater than or equal to zero.");
335 //Handle CancellationToken
336 if (cancellationToken != CancellationToken.None)
338 cancellationToken.Register(() =>
340 Native.StopContinuousCapture(_handle).ThrowIfFailed("Failed to cancel the continuous capture");
341 SetState(CameraState.Captured);
345 Native.StartContinuousCapture(_handle, count, interval, _capturingCallback, _captureCompletedCallback).
346 ThrowIfFailed("Failed to start the continuous capture.");
348 SetState(CameraState.Capturing);
352 /// Starts camera auto-focusing, asynchronously.
353 /// The camera must be in the <see cref="CameraState.Preview"/> or the <see cref="CameraState.Captured"/> state.
355 /// <param name="continuous">Continuous auto focus.</param>
356 /// <since_tizen> 3 </since_tizen>
357 /// <privilege> http://tizen.org/privilege/camera </privilege>
358 /// <feature> http://tizen.org/feature/camera </feature>
360 /// If continuous status is true, the camera continuously tries to focus.
362 /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
363 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
364 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
365 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
366 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
367 public void StartFocusing(bool continuous)
369 ValidateState(CameraState.Preview, CameraState.Captured);
371 Native.StartFocusing(_handle, continuous).ThrowIfFailed("Failed to cancel the camera focus.");
375 /// Stops camera auto focusing.
376 /// The camera must be in the <see cref="CameraState.Preview"/> or the <see cref="CameraState.Captured"/> state.
378 /// <since_tizen> 3 </since_tizen>
379 /// <privilege> http://tizen.org/privilege/camera </privilege>
380 /// <feature> http://tizen.org/feature/camera </feature>
381 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
382 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
383 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
384 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
385 public void StopFocusing()
387 ValidateState(CameraState.Preview, CameraState.Captured);
389 Native.CancelFocusing(_handle).ThrowIfFailed("Failed to cancel the camera focus.");
393 /// Starts face detection.
394 /// The camera must be in the <see cref="CameraState.Preview"/> state.
396 /// <since_tizen> 3 </since_tizen>
397 /// <privilege> http://tizen.org/privilege/camera </privilege>
398 /// <feature> http://tizen.org/feature/camera </feature>
400 /// This should be called after <see cref="StartPreview"/> is started.
401 /// The Eventhandler set using <see cref="FaceDetected"/> is invoked when the face is detected in the preview frame.
402 /// Internally, it starts continuously focus and focusing on the detected face.
404 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
405 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
406 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
407 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
408 public void StartFaceDetection()
410 ValidateState(CameraState.Preview);
412 _faceDetectedCallback = (IntPtr faces, int count, IntPtr userData) =>
414 var result = new List<FaceDetectionData>();
415 IntPtr current = faces;
417 for (int i = 0; i < count; i++)
419 result.Add(new FaceDetectionData(current));
420 current = IntPtr.Add(current, Marshal.SizeOf<Native.DetectedFaceStruct>());
423 FaceDetected?.Invoke(this, new FaceDetectedEventArgs(result));
426 Native.StartFaceDetection(_handle, _faceDetectedCallback).
427 ThrowIfFailed("Failed to start face detection");
431 /// Stops face detection.
433 /// <since_tizen> 3 </since_tizen>
434 /// <privilege> http://tizen.org/privilege/camera </privilege>
435 /// <feature> http://tizen.org/feature/camera </feature>
436 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
437 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
438 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
439 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
440 public void StopFaceDetection()
442 ValidateNotDisposed();
444 if (_faceDetectedCallback == null)
446 throw new InvalidOperationException("The face detection is not started.");
449 Native.StopFaceDetection(_handle).ThrowIfFailed("Failed to stop the face detection.");
451 _faceDetectedCallback = null;