Release 4.0.0-preview1-00051
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Camera / Camera / Camera.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.Collections.Generic;
19 using System.Diagnostics;
20 using System.Linq;
21 using System.Runtime.InteropServices;
22 using System.Threading;
23 using static Interop;
24 using Native = Interop.Camera;
25
26 namespace Tizen.Multimedia
27 {
28     static internal class CameraLog
29     {
30         internal const string Tag = "Tizen.Multimedia.Camera";
31         internal const string Enter = "[Enter]";
32         internal const string Leave = "[Leave]";
33     }
34
35     /// <summary>
36     /// The camera class provides methods to capture photos and support setting up notifications
37     /// for state changes of capturing, previewing, focusing, information about resolution and 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 e.g. focus.
40     /// </summary>
41     public class Camera : IDisposable, IDisplayable<CameraError>
42     {
43         private IntPtr _handle = IntPtr.Zero;
44         private bool _disposed = false;
45         private CameraState _state = CameraState.None;
46
47         /// <summary>
48         /// Initializes a new instance of the <see cref="Camera"/> Class.
49         /// </summary>
50         /// <since_tizen> 3 </since_tizen>
51         /// <param name="device">The camera device to access</param>
52         public Camera(CameraDevice device)
53         {
54             CameraErrorFactory.ThrowIfError(Native.Create(device, out _handle),
55                 "Failed to create camera instance");
56
57             Capabilities = new CameraCapabilities(this);
58             Settings = new CameraSettings(this);
59             DisplaySettings = new CameraDisplaySettings(this);
60
61             RegisterCallbacks();
62
63             SetState(CameraState.Created);
64         }
65
66         /// <summary>
67         /// Destructor of the camera class.
68         /// </summary>
69         ~Camera()
70         {
71             Dispose(false);
72         }
73
74         public IntPtr Handle => GetHandle();
75
76         internal IntPtr GetHandle()
77         {
78             ValidateNotDisposed();
79             return _handle;
80         }
81
82         #region Dispose support
83         /// <summary>
84         /// Releases the unmanaged resources used by the Camera.
85         /// </summary>
86         /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
87         protected virtual void Dispose(bool disposing)
88         {
89             if (!_disposed)
90             {
91                 if (disposing)
92                 {
93                     // to be used if there are any other disposable objects
94                 }
95
96                 if (_handle != IntPtr.Zero)
97                 {
98                     Native.Destroy(_handle);
99                     _handle = IntPtr.Zero;
100                 }
101
102                 _disposed = true;
103             }
104         }
105
106         /// <summary>
107         /// Releases all resources used by the Camera.
108         /// </summary>
109         /// <since_tizen> 3 </since_tizen>
110         public void Dispose()
111         {
112             ReplaceDisplay(null);
113             Dispose(true);
114             GC.SuppressFinalize(this);
115         }
116
117         internal void ValidateNotDisposed()
118         {
119             if (_disposed)
120             {
121                 Log.Error(CameraLog.Tag, "Camera handle is disposed.");
122                 throw new ObjectDisposedException(nameof(Camera));
123             }
124         }
125         #endregion Dispose support
126
127         #region Check camera state
128         internal void ValidateState(params CameraState[] required)
129         {
130             ValidateNotDisposed();
131
132             Debug.Assert(required.Length > 0);
133
134             var curState = _state;
135             if (!required.Contains(curState))
136             {
137                 throw new InvalidOperationException($"The camera is not in a valid state. " +
138                     $"Current State : { curState }, Valid State : { string.Join(", ", required) }.");
139             }
140         }
141
142         internal void SetState(CameraState state)
143         {
144             _state = state;
145         }
146         #endregion Check camera state
147
148         #region EventHandlers
149         /// <summary>
150         /// Event that occurs when the camera interrupt is started by policy.
151         /// </summary>
152         public event EventHandler<CameraInterruptStartedEventArgs> InterruptStarted;
153         private Native.InterruptStartedCallback _interruptStartedCallback;
154
155         /// <summary>
156         /// Event that occurs when an camera is interrupted by policy.
157         /// </summary>
158         /// <since_tizen> 3 </since_tizen>
159         public event EventHandler<CameraInterruptedEventArgs> Interrupted;
160         private Native.InterruptedCallback _interruptedCallback;
161
162         /// <summary>
163         /// Event that occurs when there is an asynchronous error.
164         /// </summary>
165         /// <since_tizen> 3 </since_tizen>
166         public event EventHandler<CameraErrorOccurredEventArgs> ErrorOccurred;
167         private Native.ErrorCallback _errorCallback;
168
169         /// <summary>
170         /// Event that occurs when the auto focus state is changed.
171         /// </summary>
172         /// <since_tizen> 3 </since_tizen>
173         public event EventHandler<CameraFocusStateChangedEventArgs> FocusStateChanged;
174         private Native.FocusStateChangedCallback _focusStateChangedCallback;
175
176         /// <summary>
177         /// Event that occurs when a face is detected in preview frame.
178         /// </summary>
179         /// <since_tizen> 3 </since_tizen>
180         public event EventHandler<FaceDetectedEventArgs> FaceDetected;
181         private Native.FaceDetectedCallback _faceDetectedCallback;
182
183         /// <summary>
184         /// Event that occurs during capture of image.
185         /// </summary>
186         /// <since_tizen> 3 </since_tizen>
187         public event EventHandler<CameraCapturingEventArgs> Capturing;
188         private Native.CapturingCallback _capturingCallback;
189
190         /// <summary>
191         /// Event that occurs after the capture of the image.
192         /// </summary>
193         /// <since_tizen> 3 </since_tizen>
194         public event EventHandler<EventArgs> CaptureCompleted;
195         private Native.CaptureCompletedCallback _captureCompletedCallback;
196
197         private Native.HdrCaptureProgressCallback _hdrCaptureProgressCallback;
198         private event EventHandler<HdrCaptureProgressEventArgs> _hdrCaptureProgress;
199         private object _hdrCaptureProgressEventLock = new object();
200
201         /// <summary>
202         /// Event that occurs when there is change in HDR capture progress.
203         /// Check whether <see cref="IsHdrCaptureSupported"/> is supported or not before add this EventHandler.
204         /// </summary>
205         /// <since_tizen> 3 </since_tizen>
206         /// <exception cref="NotSupportedException">In case of HDR feature is not supported.</exception>
207         public event EventHandler<HdrCaptureProgressEventArgs> HdrCaptureProgress
208         {
209             add
210             {
211                 lock (_hdrCaptureProgressEventLock)
212                 {
213                     if (_hdrCaptureProgress == null)
214                     {
215                         RegisterHdrCaptureProgress();
216                     }
217
218                     _hdrCaptureProgress += value;
219                 }
220             }
221
222             remove
223             {
224                 lock (_hdrCaptureProgressEventLock)
225                 {
226                     _hdrCaptureProgress -= value;
227
228                     if (_hdrCaptureProgress == null)
229                     {
230                         UnregisterHdrCaptureProgress();
231                     }
232                 }
233             }
234         }
235
236         /// <summary>
237         /// Event that occurs when camera state is changed.
238         /// </summary>
239         /// <since_tizen> 3 </since_tizen>
240         public event EventHandler<CameraStateChangedEventArgs> StateChanged;
241         private Native.StateChangedCallback _stateChangedCallback;
242
243         private static Native.DeviceStateChangedCallback _deviceStateChangedCallback;
244         private static event EventHandler<CameraDeviceStateChangedEventArgs> _deviceStateChanged;
245         private static object _deviceStateChangedEventLock = new object();
246         private static int _deviceStateCallbackId;
247
248         /// <summary>
249         /// Event that occurs after the <see cref="CameraDeviceState"/> is changed.
250         /// </summary>
251         /// <since_tizen> 3 </since_tizen>
252         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
253         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
254         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
255         public static event EventHandler<CameraDeviceStateChangedEventArgs> DeviceStateChanged
256         {
257             add
258             {
259                 lock (_deviceStateChangedEventLock)
260                 {
261                     if (_deviceStateChanged == null)
262                     {
263                         RegisterDeviceStateChangedCallback();
264                     }
265
266                     _deviceStateChanged += value;
267                 }
268             }
269
270             remove
271             {
272                 lock (_deviceStateChangedEventLock)
273                 {
274                     _deviceStateChanged -= value;
275
276                     if (_deviceStateChanged == null)
277                     {
278                         UnregisterDeviceStateChangedCallback();
279                     }
280                 }
281             }
282         }
283
284         private Native.PreviewCallback _previewCallback;
285         private event EventHandler<PreviewEventArgs> _preview;
286         private object _previewEventLock = new object();
287         /// <summary>
288         /// Event that occurs once per frame when previewing.
289         /// Preview callback is registered when user add callback explicitly to avoid useless P/Invoke.
290         /// </summary>
291         /// <since_tizen> 3 </since_tizen>
292         public event EventHandler<PreviewEventArgs> Preview
293         {
294             add
295             {
296                 lock (_previewEventLock)
297                 {
298                     if (_preview == null)
299                     {
300                         RegisterPreviewCallback();
301                     }
302
303                     _preview += value;
304                 }
305             }
306
307             remove
308             {
309                 lock (_previewEventLock)
310                 {
311                     _preview -= value;
312
313                     if (_preview == null)
314                     {
315                         UnregisterPreviewCallback();
316                     }
317                 }
318             }
319         }
320
321         private Native.MediaPacketPreviewCallback _mediaPacketPreviewCallback;
322         private EventHandler<MediaPacketPreviewEventArgs> _mediaPacketPreview;
323         private object _mediaPacketPreviewEventLock = new object();
324
325         /// <summary>
326         /// Event that occurs once per frame when previewing.
327         /// Preview callback is registered when user add callback explicitly to avoid useless P/Invoke.
328         /// </summary>
329         /// <since_tizen> 3 </since_tizen>
330         public event EventHandler<MediaPacketPreviewEventArgs> MediaPacketPreview
331         {
332             add
333             {
334                 lock (_mediaPacketPreviewEventLock)
335                 {
336                     if (_mediaPacketPreview == null)
337                     {
338                         RegisterMediaPacketPreviewCallback();
339                     }
340
341                     _mediaPacketPreview += value;
342                 }
343             }
344
345             remove
346             {
347                 lock (_mediaPacketPreviewEventLock)
348                 {
349                     _mediaPacketPreview -= value;
350
351                     if (_mediaPacketPreview == null)
352                     {
353                         UnregisterMediaPacketPreviewCallback();
354                     }
355                 }
356             }
357         }
358         #endregion EventHandlers
359
360         #region Properties
361         /// <summary>
362         /// Get/Set the various camera settings.
363         /// </summary>
364         /// <since_tizen> 3 </since_tizen>
365         public CameraSettings Settings { get; }
366
367         /// <summary>
368         /// Gets the various camera capabilities.
369         /// </summary>
370         /// <since_tizen> 3 </since_tizen>
371         public CameraCapabilities Capabilities { get; }
372
373         /// <summary>
374         /// Get/set various camera display properties.
375         /// </summary>
376         /// <since_tizen> 3 </since_tizen>
377         public CameraDisplaySettings DisplaySettings{ get; }
378
379         private Display _display;
380
381         private CameraError SetDisplay(Display display)
382         {
383             if (display == null)
384             {
385                 return CameraDisplay.SetTarget(GetHandle(), DisplayType.None, IntPtr.Zero);
386             }
387
388             return display.ApplyTo(this);
389         }
390
391         private void ReplaceDisplay(Display newDisplay)
392         {
393             _display?.SetOwner(null);
394             _display = newDisplay;
395             _display?.SetOwner(this);
396         }
397
398         /// <summary>
399         /// Sets or gets the display type and handle to show preview images.
400         /// The camera must be in the <see cref="CameraState.Created"/> state.
401         /// </summary>
402         /// <since_tizen> 3 </since_tizen>
403         /// <remarks>
404         /// This must be set before StartPreview() method.
405         /// In Custom ROI display mode, DisplayRoiArea property must be set before calling this method.
406         /// </remarks>
407         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
408         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
409         /// <exception cref="ObjectDisposedException" > The camera already has been disposed.</exception>
410         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
411         public Display Display
412         {
413             get
414             {
415                 return _display;
416             }
417
418             set
419             {
420                 ValidateState(CameraState.Created);
421
422                 if (value?.Owner != null)
423                 {
424                     if (ReferenceEquals(this, value.Owner))
425                     {
426                         return;
427                     }
428
429                     throw new ArgumentException("The display has already been assigned to another.");
430                 }
431
432                 CameraErrorFactory.ThrowIfError(SetDisplay(value), "Failed to set the camera display");
433
434                 ReplaceDisplay(value);
435             }
436         }
437
438         CameraError IDisplayable<CameraError>.ApplyEvasDisplay(DisplayType type, ElmSharp.EvasObject evasObject)
439         {
440             Debug.Assert(_disposed == false);
441             ValidationUtil.ValidateEnum(typeof(DisplayType), type, nameof(type));
442
443             return CameraDisplay.SetTarget(GetHandle(), type, evasObject);
444         }
445
446         /// <summary>
447         /// Gets the state of the camera.
448         /// </summary>
449         /// <since_tizen> 3 </since_tizen>
450         /// <value> None, Created, Preview, Capturing, Captured </value>
451         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
452         public CameraState State
453         {
454             get
455             {
456                 ValidateNotDisposed();
457
458                 CameraState val = CameraState.None;
459                 CameraErrorFactory.ThrowIfError(Native.GetState(_handle, out val),
460                     "Failed to get camera state");
461
462                 return val;
463             }
464         }
465
466         /// <summary>
467         /// The hint for display reuse.
468         /// If the hint is set to true, the display will be reused when the camera device is changed with
469         /// ChangeDevice method.
470         /// </summary>
471         /// <since_tizen> 3 </since_tizen>
472         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
473         /// <exception cref="InvalidOperationException">Invalid state.</exception>
474         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
475         public bool DisplayReuseHint
476         {
477             get
478             {
479                 ValidateNotDisposed();
480
481                 CameraErrorFactory.ThrowIfError(Native.GetDisplayReuseHint(_handle, out bool val),
482                     "Failed to get camera display reuse hint");
483
484                 return val;
485             }
486
487             set
488             {
489                 ValidateState(CameraState.Preview);
490
491                 CameraErrorFactory.ThrowIfError(Native.SetDisplayReuseHint(_handle, value),
492                     "Failed to set display reuse hint.");
493             }
494         }
495
496         /// <summary>
497         /// Gets the facing direction of camera module.
498         /// </summary>
499         /// <since_tizen> 3 </since_tizen>
500         /// <value>A <see cref="CameraFacingDirection"/> that specifies the facing direction of camera device.</value>
501         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
502         public CameraFacingDirection Direction
503         {
504             get
505             {
506                 ValidateNotDisposed();
507
508                 CameraErrorFactory.ThrowIfError(Native.GetFacingDirection(_handle, out var val),
509                     "Failed to get camera direction");
510
511                 return val;
512             }
513         }
514
515         /// <summary>
516         /// Gets the camera device count.
517         /// </summary>
518         /// <since_tizen> 3 </since_tizen>
519         /// <value>This returns 2, if the device supports primary and secondary cameras.
520         /// Otherwise 1, if the device only supports primary camera.</value>
521         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
522         public int CameraCount
523         {
524             get
525             {
526                 ValidateNotDisposed();
527
528                 CameraErrorFactory.ThrowIfError(Native.GetDeviceCount(_handle, out int val),
529                     "Failed to get camera device count");
530
531                 return val;
532             }
533         }
534         #endregion Properties
535
536         #region Methods
537         /// <summary>
538         /// Changes the camera device.
539         /// </summary>
540         /// <since_tizen> 3 </since_tizen>
541         /// <param name="device">The hardware camera to access.</param>
542         /// <remarks>
543         /// If display reuse is set using <see cref="DisplayReuseHint"/>
544         /// before stopping the preview, the display will be reused and last frame on the display
545         /// can be kept even though camera device is changed.
546         /// The camera must be in the <see cref="CameraState.Created"/>.
547         /// </remarks>
548         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
549         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
550         /// <exception cref="NotSupportedException">In case of ChangeDevice feature is not supported.</exception>
551         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
552         public void ChangeDevice(CameraDevice device)
553         {
554             ValidateState(CameraState.Created);
555             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
556
557             CameraErrorFactory.ThrowIfError(Native.ChangeDevice(_handle, device),
558                 "Failed to change the camera device");
559         }
560
561         /// <summary>
562         /// Gets the device state.
563         /// </summary>
564         /// <since_tizen> 3 </since_tizen>
565         /// <param name="device">The device to get state.</param>
566         /// <returns>Returns the state of camera device</returns>
567         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
568         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
569         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
570         public static CameraDeviceState GetDeviceState(CameraDevice device)
571         {
572             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
573
574             CameraErrorFactory.ThrowIfError(Native.GetDeviceState(device, out var val),
575                 "Failed to get the camera device state.");
576
577             return val;
578         }
579
580         /// <summary>
581         /// Gets the flash state.
582         /// </summary>
583         /// <since_tizen> 3 </since_tizen>
584         /// <param name="device">The device to get state.</param>
585         /// <returns>Returns the flash state of camera device</returns>
586         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
587         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
588         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
589         public static CameraFlashState GetFlashState(CameraDevice device)
590         {
591             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
592
593             CameraErrorFactory.ThrowIfError(Native.GetFlashState(device, out var val),
594                 "Failed to get camera flash state");
595
596             return val;
597         }
598
599         /// <summary>
600         /// Starts capturing and drawing preview frames on the screen.
601         /// The display handle must be set using <see cref="CameraDisplaySettings.SetInfo"/>
602         /// before using this method.
603         /// If needed set fps <see cref="CameraSettings.PreviewFps"/>, preview resolution
604         /// <see cref="CameraSettings.PreviewResolution"/>, or preview format <see cref="CameraSettings.PreviewPixelFormat"/>
605         /// before using this method.
606         /// The camera must be in the <see cref="CameraState.Created"/> or <see cref="CameraState.Captured"/> state.
607         /// </summary>
608         /// <since_tizen> 3 </since_tizen>
609         /// <privilege>
610         /// http://tizen.org/privilege/camera
611         /// </privilege>
612         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
613         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
614         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
615         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
616         public void StartPreview()
617         {
618             ValidateState(CameraState.Created, CameraState.Captured);
619
620             CameraErrorFactory.ThrowIfError(Native.StartPreview(_handle),
621                 "Failed to start the camera preview.");
622
623             // Update by StateChangedCallback can be delayed for dozens of milliseconds.
624             SetState(CameraState.Preview);
625         }
626
627         /// <summary>
628         /// Stops capturing and drawing preview frames on the screen.
629         /// The camera must be in the <see cref="CameraState.Preview"/> state.
630         /// </summary>
631         /// <since_tizen> 3 </since_tizen>
632         /// <privilege>
633         /// http://tizen.org/privilege/camera
634         /// </privilege>
635         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
636         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
637         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
638         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
639         public void StopPreview()
640         {
641             ValidateState(CameraState.Preview);
642
643             CameraErrorFactory.ThrowIfError(Native.StopPreview(_handle),
644                 "Failed to stop the camera preview.");
645
646             SetState(CameraState.Created);
647         }
648
649         /// <summary>
650         /// Starts capturing of still images.
651         /// EventHandler must be set for capturing using <see cref="Capturing"/>
652         /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
653         /// The camera must be in the <see cref="CameraState.Preview"/> state.
654         /// </summary>
655         /// <since_tizen> 3 </since_tizen>
656         /// <privilege>
657         /// http://tizen.org/privilege/camera
658         /// </privilege>
659         /// <remarks>
660         /// This function causes the transition of the camera state from Capturing to Captured
661         /// automatically and the corresponding EventHandlers will be invoked.
662         /// The preview should be restarted by calling <see cref="StartPreview"/> method after capture is completed.
663         /// </remarks>
664         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
665         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
666         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
667         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
668         public void StartCapture()
669         {
670             ValidateState(CameraState.Preview);
671
672             CameraErrorFactory.ThrowIfError(Native.StartCapture(_handle, _capturingCallback, _captureCompletedCallback, IntPtr.Zero),
673                 "Failed to start the camera capture.");
674
675             SetState(CameraState.Capturing);
676         }
677
678         /// <summary>
679         /// Starts continuously capturing still images.
680         /// EventHandler must be set for capturing using <see cref="Capturing"/>
681         /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
682         /// The camera must be in the <see cref="CameraState.Preview"/> state.
683         /// </summary>
684         /// <since_tizen> 3 </since_tizen>
685         /// <privilege>
686         /// http://tizen.org/privilege/camera
687         /// </privilege>
688         /// <param name="count">The number of still images.</param>
689         /// <param name="interval">The interval of the capture(milliseconds).</param>
690         /// <param name="cancellationToken">The cancellation token to cancel capturing.</param>
691         /// <seealso cref="System.Threading.CancellationToken"/>
692         /// <remarks>
693         /// If this is not supported zero shutter lag occurs. The capture resolution could be
694         /// changed to the preview resolution. This function causes the transition of the camera state
695         /// from Capturing to Captured automatically and the corresponding Eventhandlers will be invoked.
696         /// Each captured image will be delivered through Eventhandler set using <see cref="Capturing"/> event.
697         /// The preview should be restarted by calling <see cref="StartPreview"/> method after capture is completed.
698         /// </remarks>
699         /// <exception cref="ArgumentOutOfRangeException">In case of invalid parameters.</exception>
700         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
701         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
702         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
703         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
704         public void StartCapture(int count, int interval, CancellationToken cancellationToken)
705         {
706             ValidateState(CameraState.Preview);
707
708             if (count < 2)
709             {
710                 throw new ArgumentOutOfRangeException(nameof(count), count, $"{nameof(count)} should be greater than one.");
711             }
712
713             if (interval < 0)
714             {
715                 throw new ArgumentOutOfRangeException(nameof(interval), interval, $"{nameof(interval)} should be greater than or equal to zero.");
716             }
717
718             //Handle CancellationToken
719             if (cancellationToken != CancellationToken.None)
720             {
721                 cancellationToken.Register(() =>
722                 {
723                     CameraErrorFactory.ThrowIfError(Native.StopContinuousCapture(_handle),
724                         "Failed to cancel the continuous capture");
725                     SetState(CameraState.Captured);
726                 });
727             }
728
729             CameraErrorFactory.ThrowIfError(Native.StartContinuousCapture(_handle, count, interval,
730                 _capturingCallback, _captureCompletedCallback, IntPtr.Zero), "Failed to start the continuous capture.");
731
732             SetState(CameraState.Capturing);
733         }
734
735         /// <summary>
736         /// Starts camera auto-focusing, asynchronously.
737         /// The camera must be in the <see cref="CameraState.Preview"/> or <see cref="CameraState.Captured"/> state.
738         /// </summary>
739         /// <since_tizen> 3 </since_tizen>
740         /// <param name="continuous">Continuous auto focus</param>
741         /// <privilege>
742         /// http://tizen.org/privilege/camera
743         /// </privilege>
744         /// <remarks>
745         /// If continuous status is true, the camera continuously tries to focus.
746         /// </remarks>
747         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
748         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
749         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
750         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
751         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
752         public void StartFocusing(bool continuous)
753         {
754             ValidateState(CameraState.Preview, CameraState.Captured);
755
756             CameraErrorFactory.ThrowIfError(Native.StartFocusing(_handle, continuous),
757                 "Failed to cancel the camera focus.");
758         }
759
760         /// <summary>
761         /// Stops camera auto focusing.
762         /// The camera must be in the <see cref="CameraState.Preview"/> or <see cref="CameraState.Captured"/> state.
763         /// </summary>
764         /// <since_tizen> 3 </since_tizen>
765         /// <privilege>
766         /// http://tizen.org/privilege/camera
767         /// </privilege>
768         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
769         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
770         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
771         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
772         public void StopFocusing()
773         {
774             ValidateState(CameraState.Preview, CameraState.Captured);
775
776             CameraErrorFactory.ThrowIfError(Native.CancelFocusing(_handle),
777                 "Failed to cancel the camera focus.");
778         }
779
780         /// <summary>
781         /// Starts face detection.
782         /// The camera must be in the <see cref="CameraState.Preview"/> state.
783         /// </summary>
784         /// <since_tizen> 3 </since_tizen>
785         /// <privilege>
786         /// http://tizen.org/privilege/camera
787         /// </privilege>
788         /// <remarks>
789         /// This should be called after <see cref="StartPreview"/> is started.
790         /// The Eventhandler set using <see cref="FaceDetected"/> invoked when the face is detected in preview frame.
791         /// Internally it starts continuous focus and focusing on the detected face.
792         /// </remarks>
793         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
794         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
795         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
796         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
797         public void StartFaceDetection()
798         {
799             ValidateState(CameraState.Preview);
800
801             _faceDetectedCallback = (IntPtr faces, int count, IntPtr userData) =>
802             {
803                 var result = new List<FaceDetectionData>();
804                 IntPtr current = faces;
805
806                 for (int i = 0; i < count; i++)
807                 {
808                     result.Add(new FaceDetectionData(current));
809                     current = IntPtr.Add(current, Marshal.SizeOf<Native.DetectedFaceStruct>());
810                 }
811
812                 FaceDetected?.Invoke(this, new FaceDetectedEventArgs(result));
813             };
814             CameraErrorFactory.ThrowIfError(Native.StartFaceDetection(_handle, _faceDetectedCallback, IntPtr.Zero),
815                 "Failed to start face detection");
816         }
817
818         /// <summary>
819         /// Stops face detection.
820         /// </summary>
821         /// <since_tizen> 3 </since_tizen>
822         /// <privilege>
823         /// http://tizen.org/privilege/camera
824         /// </privilege>
825         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
826         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
827         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
828         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
829         public void StopFaceDetection()
830         {
831             if (_faceDetectedCallback == null)
832             {
833                 throw new InvalidOperationException("The face detection is not started.");
834             }
835
836             CameraErrorFactory.ThrowIfError(Native.StopFaceDetection(_handle),
837                 "Failed to stop the face detection.");
838
839             _faceDetectedCallback = null;
840         }
841         #endregion Methods
842
843         #region Callback registrations
844         private void RegisterCallbacks()
845         {
846             RegisterErrorCallback();
847             RegisterFocusStateChanged();
848             RegisterInterruptStartedCallback();
849             RegisterInterruptedCallback();
850             RegisterStateChangedCallback();
851
852             //Define capturing callback
853             _capturingCallback = (IntPtr main, IntPtr postview, IntPtr thumbnail, IntPtr userData) =>
854             {
855                 Capturing?.Invoke(this, new CameraCapturingEventArgs(new StillImage(main),
856                     postview == IntPtr.Zero ? null : new StillImage(postview),
857                     thumbnail == IntPtr.Zero ? null : new StillImage(thumbnail)));
858             };
859
860             //Define captureCompleted callback
861             _captureCompletedCallback = _ =>
862             {
863                 SetState(CameraState.Captured);
864                 CaptureCompleted?.Invoke(this, EventArgs.Empty);
865             };
866         }
867
868         private void RegisterInterruptStartedCallback()
869         {
870             _interruptStartedCallback = (CameraPolicy policy, CameraState state, IntPtr userData) =>
871             {
872                 InterruptStarted?.Invoke(this, new CameraInterruptStartedEventArgs(policy, state));
873             };
874             CameraErrorFactory.ThrowIfError(Native.SetInterruptStartedCallback(_handle, _interruptStartedCallback, IntPtr.Zero),
875                 "Failed to set interrupt callback");
876         }
877
878         private void RegisterInterruptedCallback()
879         {
880             _interruptedCallback = (CameraPolicy policy, CameraState previous, CameraState current, IntPtr userData) =>
881             {
882                 Interrupted?.Invoke(this, new CameraInterruptedEventArgs(policy, previous, current));
883             };
884             CameraErrorFactory.ThrowIfError(Native.SetInterruptedCallback(_handle, _interruptedCallback, IntPtr.Zero),
885                 "Failed to set interrupt callback");
886         }
887
888         private void RegisterErrorCallback()
889         {
890             _errorCallback = (CameraErrorCode error, CameraState current, IntPtr userData) =>
891             {
892                 ErrorOccurred?.Invoke(this, new CameraErrorOccurredEventArgs(error, current));
893             };
894             CameraErrorFactory.ThrowIfError(Native.SetErrorCallback(_handle, _errorCallback, IntPtr.Zero),
895                 "Setting error callback failed");
896         }
897
898         private void RegisterStateChangedCallback()
899         {
900             _stateChangedCallback = (CameraState previous, CameraState current, bool byPolicy, IntPtr _) =>
901             {
902                 SetState(current);
903                 Log.Info(CameraLog.Tag, "Camera state changed " + previous.ToString() + " -> " + current.ToString());
904                 StateChanged?.Invoke(this, new CameraStateChangedEventArgs(previous, current, byPolicy));
905             };
906             CameraErrorFactory.ThrowIfError(Native.SetStateChangedCallback(_handle, _stateChangedCallback, IntPtr.Zero),
907                 "Setting state changed callback failed");
908         }
909
910         private static void RegisterDeviceStateChangedCallback()
911         {
912             _deviceStateChangedCallback = (CameraDevice device, CameraDeviceState state, IntPtr userData) =>
913             {
914                 _deviceStateChanged?.Invoke(null, new CameraDeviceStateChangedEventArgs(device, state));
915             };
916
917             CameraErrorFactory.ThrowIfError(Native.SetDeviceStateChangedCallback(_deviceStateChangedCallback, IntPtr.Zero, out _deviceStateCallbackId),
918                 "Failed to set device state changed callback");
919
920             Log.Info(CameraLog.Tag, "add callbackId " + _deviceStateCallbackId.ToString());
921         }
922
923         private static void UnregisterDeviceStateChangedCallback()
924         {
925             CameraErrorFactory.ThrowIfError(Native.UnsetDeviceStateChangedCallback(_deviceStateCallbackId),
926                 "Unsetting device state changed callback failed");
927             _deviceStateChangedCallback = null;
928             _deviceStateCallbackId = 0;
929         }
930
931         private void RegisterFocusStateChanged()
932         {
933             _focusStateChangedCallback = (CameraFocusState state, IntPtr userData) =>
934             {
935                 FocusStateChanged?.Invoke(this, new CameraFocusStateChangedEventArgs(state));
936             };
937             CameraErrorFactory.ThrowIfError(Native.SetFocusStateChangedCallback(_handle, _focusStateChangedCallback, IntPtr.Zero),
938                 "Setting focus changed callback failed");
939         }
940
941         private void RegisterHdrCaptureProgress()
942         {
943             _hdrCaptureProgressCallback = (int percent, IntPtr userData) =>
944             {
945                 _hdrCaptureProgress?.Invoke(this, new HdrCaptureProgressEventArgs(percent));
946             };
947             CameraErrorFactory.ThrowIfError(Native.SetHdrCaptureProgressCallback(_handle, _hdrCaptureProgressCallback, IntPtr.Zero),
948                 "Setting Hdr capture progress callback failed");
949         }
950
951         private void UnregisterHdrCaptureProgress()
952         {
953             CameraErrorFactory.ThrowIfError(Native.UnsetHdrCaptureProgressCallback(_handle),
954                 "Unsetting hdr capture progress is failed");
955             _hdrCaptureProgressCallback = null;
956         }
957
958         private void RegisterPreviewCallback()
959         {
960             _previewCallback = (IntPtr frame, IntPtr userData) =>
961             {
962                 _preview?.Invoke(this, new PreviewEventArgs(new PreviewFrame(frame)));
963             };
964             CameraErrorFactory.ThrowIfError(Native.SetPreviewCallback(_handle, _previewCallback, IntPtr.Zero),
965                 "Setting preview callback failed");
966         }
967
968         private void UnregisterPreviewCallback()
969         {
970             CameraErrorFactory.ThrowIfError(Native.UnsetPreviewCallback(_handle),
971                 "Unsetting preview callback failed");
972             _previewCallback = null;
973         }
974
975         private void RegisterMediaPacketPreviewCallback()
976         {
977             _mediaPacketPreviewCallback = (IntPtr mediaPacket, IntPtr userData) =>
978             {
979                 MediaPacket packet = MediaPacket.From(mediaPacket);
980                 var eventHandler = _mediaPacketPreview;
981
982                 if (eventHandler != null)
983                 {
984                     eventHandler.Invoke(this, new MediaPacketPreviewEventArgs(packet));
985                 }
986                 else
987                 {
988                     packet.Dispose();
989                 }
990             };
991             CameraErrorFactory.ThrowIfError(Native.SetMediaPacketPreviewCallback(_handle, _mediaPacketPreviewCallback, IntPtr.Zero),
992                 "Setting media packet preview callback failed");
993         }
994
995         private void UnregisterMediaPacketPreviewCallback()
996         {
997             CameraErrorFactory.ThrowIfError(Native.UnsetMediaPacketPreviewCallback(_handle),
998                 "Unsetting media packet preview callback failed");
999             _mediaPacketPreviewCallback = null;
1000         }
1001         #endregion Callback registrations
1002     }
1003 }
1004