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.ComponentModel;
20 using System.Diagnostics;
22 using System.Runtime.InteropServices;
23 using System.Threading;
24 using Native = Interop.Camera;
26 namespace Tizen.Multimedia
28 static internal class CameraLog
30 internal const string Tag = "Tizen.Multimedia.Camera";
31 internal const string Enter = "[Enter]";
32 internal const string Leave = "[Leave]";
36 /// This camera class provides methods to capture photos and supports setting up notifications
37 /// for state changes of capturing, previewing, focusing, and informing about the resolution and the binary format,
38 /// and functions for picture manipulations like sepia, negative, and many more.
39 /// It also notifies you when a significant picture parameter changes, (For example, focus).
41 /// <since_tizen> 3 </since_tizen>
42 /// <feature> http://tizen.org/feature/camera </feature>
43 public partial class Camera : IDisposable, IDisplayable<CameraError>
45 private IntPtr _handle = IntPtr.Zero;
46 private bool _disposed = false;
47 private CameraState _state = CameraState.None;
48 private CameraDeviceManager _cameraDeviceManager;
51 /// Initializes a new instance of the <see cref="Camera"/> class.
53 /// <param name="device">The camera device to access.</param>
54 /// <exception cref="ArgumentException">Invalid CameraDevice type.</exception>
55 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
56 /// <exception cref="NotSupportedException">The camera feature is not supported.</exception>
57 /// <since_tizen> 3 </since_tizen>
58 /// <feature> http://tizen.org/feature/camera </feature>
59 public Camera(CameraDevice device)
61 ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
65 Capabilities = new CameraCapabilities(this);
66 Settings = new CameraSettings(this);
67 DisplaySettings = new CameraDisplaySettings(this);
71 SetState(CameraState.Created);
74 private void Create(CameraDevice device)
76 CameraDeviceType cameraDeviceType = CameraDeviceType.BuiltIn;
80 _cameraDeviceManager = new CameraDeviceManager();
81 var deviceInfo = _cameraDeviceManager.GetDeviceInformation();
82 Log.Info(CameraLog.Tag, deviceInfo.ToString());
84 cameraDeviceType = deviceInfo.First().Type;
86 catch (NotSupportedException e)
88 Tizen.Log.Info(CameraLog.Tag,
89 $"CameraDeviceManager is not supported. {e.Message}. Not error.");
92 if (cameraDeviceType == CameraDeviceType.BuiltIn ||
93 cameraDeviceType == CameraDeviceType.Usb)
95 Native.Create(device, out _handle).
96 ThrowIfFailed($"Failed to create {cameraDeviceType.ToString()} camera");
100 Native.CreateNetworkCamera(device, out _handle).
101 ThrowIfFailed($"Failed to create {cameraDeviceType.ToString()} camera");
106 /// Finalizes an instance of the Camera class.
114 /// Gets the native handle of the camera.
116 /// <since_tizen> 3 </since_tizen>
117 /// <feature> http://tizen.org/feature/camera </feature>
118 public IntPtr Handle => GetHandle();
120 internal IntPtr GetHandle()
122 ValidateNotDisposed();
126 #region Dispose support
128 /// Releases the unmanaged resources used by the camera.
130 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
131 /// <since_tizen> 3 </since_tizen>
132 protected virtual void Dispose(bool disposing)
138 // to be used if there are any other disposable objects
141 if (_handle != IntPtr.Zero)
143 Native.Destroy(_handle);
144 _handle = IntPtr.Zero;
152 /// Releases all resources used by the camera.
154 /// <since_tizen> 3 </since_tizen>
155 /// <feature> http://tizen.org/feature/camera </feature>
156 public void Dispose()
158 ReplaceDisplay(null);
160 GC.SuppressFinalize(this);
163 internal void ValidateNotDisposed()
167 Log.Error(CameraLog.Tag, "Camera handle is disposed.");
168 throw new ObjectDisposedException(nameof(Camera));
171 #endregion Dispose support
173 internal void ValidateState(params CameraState[] required)
175 ValidateNotDisposed();
177 Debug.Assert(required.Length > 0);
179 var curState = _state;
180 if (!required.Contains(curState))
182 throw new InvalidOperationException($"The camera is not in a valid state. " +
183 $"Current State : { curState }, Valid State : { string.Join(", ", required) }.");
187 internal void SetState(CameraState state)
193 /// Changes the camera device.
195 /// <param name="device">The hardware camera to access.</param>
196 /// <since_tizen> 3 </since_tizen>
197 /// <feature> http://tizen.org/feature/camera </feature>
199 /// If display reuse is set using <see cref="DisplayReuseHint"/>
200 /// before stopping the preview, the display will be reused and last frame on the display
201 /// can be kept even though camera device is changed.
202 /// The camera must be in the <see cref="CameraState.Created"/>.
204 /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
205 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
206 /// <exception cref="NotSupportedException">In case of the ChangeDevice feature is not supported.</exception>
207 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
208 public void ChangeDevice(CameraDevice device)
210 ValidateState(CameraState.Created);
211 ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
213 Native.ChangeDevice(_handle, device).ThrowIfFailed("Failed to change the camera device");
217 /// Gets the device state.
219 /// <param name="device">The device to get the state.</param>
220 /// <returns>Returns the state of the camera device.</returns>
221 /// <since_tizen> 4 </since_tizen>
222 /// <feature> http://tizen.org/feature/camera </feature>
223 /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
224 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
225 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
226 public static CameraDeviceState GetDeviceState(CameraDevice device)
228 ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
230 Native.GetDeviceState(device, out var val).ThrowIfFailed("Failed to get the camera device state.");
236 /// Gets the flash state.
238 /// <param name="device">The device to get the state.</param>
239 /// <returns>Returns the flash state of the camera device.</returns>
240 /// <since_tizen> 3 </since_tizen>
241 /// <feature> http://tizen.org/feature/camera </feature>
242 /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
243 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
244 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
245 public static CameraFlashState GetFlashState(CameraDevice device)
247 ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
249 Native.GetFlashState(device, out var val).ThrowIfFailed("Failed to get camera flash state");
255 /// Starts capturing and drawing preview frames on the screen.
256 /// The display property must be set using <see cref="Display"/> before using this method.
257 /// If needed set fps <see cref="CameraSettings.PreviewFps"/>, preview resolution
258 /// <see cref="CameraSettings.PreviewResolution"/>, or preview format <see cref="CameraSettings.PreviewPixelFormat"/>
259 /// before using this method.
260 /// The camera must be in the <see cref="CameraState.Created"/> or the <see cref="CameraState.Captured"/> state.
262 /// <since_tizen> 3 </since_tizen>
263 /// <privilege> http://tizen.org/privilege/camera </privilege>
264 /// <feature> http://tizen.org/feature/camera </feature>
265 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
266 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
267 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
268 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
269 public void StartPreview()
271 ValidateState(CameraState.Created, CameraState.Captured);
273 Native.StartPreview(_handle).ThrowIfFailed("Failed to start the camera preview.");
275 // Update by StateChangedCallback can be delayed for dozens of milliseconds.
276 SetState(CameraState.Preview);
280 /// Stops capturing and drawing preview frames on the screen.
281 /// The camera must be in the <see cref="CameraState.Preview"/> state.
283 /// <since_tizen> 3 </since_tizen>
284 /// <privilege> http://tizen.org/privilege/camera </privilege>
285 /// <feature> http://tizen.org/feature/camera </feature>
286 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
287 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
288 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
289 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
290 public void StopPreview()
292 ValidateState(CameraState.Preview);
294 Native.StopPreview(_handle).ThrowIfFailed("Failed to stop the camera preview.");
296 SetState(CameraState.Created);
300 /// Starts capturing of still images.
301 /// EventHandler must be set for capturing using <see cref="Capturing"/>
302 /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
303 /// The camera must be in the <see cref="CameraState.Preview"/> state.
305 /// <since_tizen> 3 </since_tizen>
306 /// <privilege> http://tizen.org/privilege/camera </privilege>
307 /// <feature> http://tizen.org/feature/camera </feature>
309 /// This function causes the transition of the camera state from capturing to captured
310 /// automatically and the corresponding EventHandlers will be invoked.
311 /// The preview should be restarted by calling the <see cref="StartPreview"/> method after capture is completed.
313 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
314 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
315 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
316 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
317 public void StartCapture()
319 ValidateState(CameraState.Preview);
321 Native.StartCapture(_handle, _capturingCallback, _captureCompletedCallback).
322 ThrowIfFailed("Failed to start the camera capture.");
324 SetState(CameraState.Capturing);
328 /// Starts continuously capturing still images.
329 /// EventHandler must be set for capturing using <see cref="Capturing"/>
330 /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
331 /// The camera must be in the <see cref="CameraState.Preview"/> state.
333 /// <param name="count">The number of still images.</param>
334 /// <param name="interval">The interval of the capture(milliseconds).</param>
335 /// <param name="cancellationToken">The cancellation token to cancel capturing.</param>
336 /// <seealso cref="CancellationToken"/>
337 /// <since_tizen> 3 </since_tizen>
338 /// <privilege> http://tizen.org/privilege/camera </privilege>
339 /// <feature> http://tizen.org/feature/camera </feature>
341 /// If this is not supported, zero shutter lag occurs. The capture resolution could be
342 /// changed to the preview resolution. This function causes the transition of the camera state
343 /// from capturing to captured automatically and the corresponding Eventhandlers will be invoked.
344 /// Each captured image will be delivered through Eventhandler set using the <see cref="Capturing"/> event.
345 /// The preview should be restarted by calling the <see cref="StartPreview"/> method after capture is completed.
347 /// <exception cref="ArgumentOutOfRangeException">In case of invalid parameters.</exception>
348 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
349 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
350 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
351 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
352 public void StartCapture(int count, int interval, CancellationToken cancellationToken)
354 ValidateState(CameraState.Preview);
358 throw new ArgumentOutOfRangeException(nameof(count), count, $"{nameof(count)} should be greater than one.");
363 throw new ArgumentOutOfRangeException(nameof(interval), interval, $"{nameof(interval)} should be greater than or equal to zero.");
366 //Handle CancellationToken
367 if (cancellationToken != CancellationToken.None)
369 cancellationToken.Register(() =>
371 Native.StopContinuousCapture(_handle).ThrowIfFailed("Failed to cancel the continuous capture");
372 SetState(CameraState.Captured);
376 Native.StartContinuousCapture(_handle, count, interval, _capturingCallback, _captureCompletedCallback).
377 ThrowIfFailed("Failed to start the continuous capture.");
379 SetState(CameraState.Capturing);
383 /// Starts camera auto-focusing, asynchronously.
384 /// The camera must be in the <see cref="CameraState.Preview"/> or the <see cref="CameraState.Captured"/> state.
386 /// <param name="continuous">Continuous auto focus.</param>
387 /// <since_tizen> 3 </since_tizen>
388 /// <privilege> http://tizen.org/privilege/camera </privilege>
389 /// <feature> http://tizen.org/feature/camera </feature>
391 /// If continuous status is true, the camera continuously tries to focus.
393 /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
394 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
395 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
396 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
397 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
398 public void StartFocusing(bool continuous)
400 ValidateState(CameraState.Preview, CameraState.Captured);
402 Native.StartFocusing(_handle, continuous).ThrowIfFailed("Failed to cancel the camera focus.");
406 /// Stops camera auto focusing.
407 /// The camera must be in the <see cref="CameraState.Preview"/> or the <see cref="CameraState.Captured"/> state.
409 /// <since_tizen> 3 </since_tizen>
410 /// <privilege> http://tizen.org/privilege/camera </privilege>
411 /// <feature> http://tizen.org/feature/camera </feature>
412 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
413 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
414 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
415 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
416 public void StopFocusing()
418 ValidateState(CameraState.Preview, CameraState.Captured);
420 Native.CancelFocusing(_handle).ThrowIfFailed("Failed to cancel the camera focus.");
424 /// Starts face detection.
425 /// The camera must be in the <see cref="CameraState.Preview"/> state.
427 /// <since_tizen> 3 </since_tizen>
428 /// <privilege> http://tizen.org/privilege/camera </privilege>
429 /// <feature> http://tizen.org/feature/camera </feature>
431 /// This should be called after <see cref="StartPreview"/> is started.
432 /// The Eventhandler set using <see cref="FaceDetected"/> is invoked when the face is detected in the preview frame.
433 /// Internally, it starts continuously focus and focusing on the detected face.
435 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
436 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
437 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
438 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
439 public void StartFaceDetection()
441 ValidateState(CameraState.Preview);
443 _faceDetectedCallback = (IntPtr faces, int count, IntPtr userData) =>
445 var result = new List<FaceDetectionData>();
446 IntPtr current = faces;
448 for (int i = 0; i < count; i++)
450 result.Add(new FaceDetectionData(current));
451 current = IntPtr.Add(current, Marshal.SizeOf<Native.DetectedFaceStruct>());
454 FaceDetected?.Invoke(this, new FaceDetectedEventArgs(result));
457 Native.StartFaceDetection(_handle, _faceDetectedCallback).
458 ThrowIfFailed("Failed to start face detection");
462 /// Stops face detection.
464 /// <since_tizen> 3 </since_tizen>
465 /// <privilege> http://tizen.org/privilege/camera </privilege>
466 /// <feature> http://tizen.org/feature/camera </feature>
467 /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
468 /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
469 /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
470 /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
471 public void StopFaceDetection()
473 ValidateNotDisposed();
475 if (_faceDetectedCallback == null)
477 throw new InvalidOperationException("The face detection is not started.");
480 Native.StopFaceDetection(_handle).ThrowIfFailed("Failed to stop the face detection.");
482 _faceDetectedCallback = null;