Release 4.0.0-preview1-00083
[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="CameraCapabilities.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 property must be set using <see cref="Display"/> before using this method.
602         /// If needed set fps <see cref="CameraSettings.PreviewFps"/>, preview resolution
603         /// <see cref="CameraSettings.PreviewResolution"/>, or preview format <see cref="CameraSettings.PreviewPixelFormat"/>
604         /// before using this method.
605         /// The camera must be in the <see cref="CameraState.Created"/> or <see cref="CameraState.Captured"/> state.
606         /// </summary>
607         /// <since_tizen> 3 </since_tizen>
608         /// <privilege>
609         /// http://tizen.org/privilege/camera
610         /// </privilege>
611         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
612         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
613         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
614         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
615         public void StartPreview()
616         {
617             ValidateState(CameraState.Created, CameraState.Captured);
618
619             CameraErrorFactory.ThrowIfError(Native.StartPreview(_handle),
620                 "Failed to start the camera preview.");
621
622             // Update by StateChangedCallback can be delayed for dozens of milliseconds.
623             SetState(CameraState.Preview);
624         }
625
626         /// <summary>
627         /// Stops capturing and drawing preview frames on the screen.
628         /// The camera must be in the <see cref="CameraState.Preview"/> state.
629         /// </summary>
630         /// <since_tizen> 3 </since_tizen>
631         /// <privilege>
632         /// http://tizen.org/privilege/camera
633         /// </privilege>
634         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
635         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
636         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
637         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
638         public void StopPreview()
639         {
640             ValidateState(CameraState.Preview);
641
642             CameraErrorFactory.ThrowIfError(Native.StopPreview(_handle),
643                 "Failed to stop the camera preview.");
644
645             SetState(CameraState.Created);
646         }
647
648         /// <summary>
649         /// Starts capturing of still images.
650         /// EventHandler must be set for capturing using <see cref="Capturing"/>
651         /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
652         /// The camera must be in the <see cref="CameraState.Preview"/> state.
653         /// </summary>
654         /// <since_tizen> 3 </since_tizen>
655         /// <privilege>
656         /// http://tizen.org/privilege/camera
657         /// </privilege>
658         /// <remarks>
659         /// This function causes the transition of the camera state from Capturing to Captured
660         /// automatically and the corresponding EventHandlers will be invoked.
661         /// The preview should be restarted by calling <see cref="StartPreview"/> method after capture is completed.
662         /// </remarks>
663         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
664         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
665         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
666         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
667         public void StartCapture()
668         {
669             ValidateState(CameraState.Preview);
670
671             CameraErrorFactory.ThrowIfError(Native.StartCapture(_handle, _capturingCallback, _captureCompletedCallback, IntPtr.Zero),
672                 "Failed to start the camera capture.");
673
674             SetState(CameraState.Capturing);
675         }
676
677         /// <summary>
678         /// Starts continuously capturing still images.
679         /// EventHandler must be set for capturing using <see cref="Capturing"/>
680         /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
681         /// The camera must be in the <see cref="CameraState.Preview"/> state.
682         /// </summary>
683         /// <since_tizen> 3 </since_tizen>
684         /// <privilege>
685         /// http://tizen.org/privilege/camera
686         /// </privilege>
687         /// <param name="count">The number of still images.</param>
688         /// <param name="interval">The interval of the capture(milliseconds).</param>
689         /// <param name="cancellationToken">The cancellation token to cancel capturing.</param>
690         /// <seealso cref="CancellationToken"/>
691         /// <remarks>
692         /// If this is not supported zero shutter lag occurs. The capture resolution could be
693         /// changed to the preview resolution. This function causes the transition of the camera state
694         /// from Capturing to Captured automatically and the corresponding Eventhandlers will be invoked.
695         /// Each captured image will be delivered through Eventhandler set using <see cref="Capturing"/> event.
696         /// The preview should be restarted by calling <see cref="StartPreview"/> method after capture is completed.
697         /// </remarks>
698         /// <exception cref="ArgumentOutOfRangeException">In case of invalid parameters.</exception>
699         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
700         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
701         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
702         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
703         public void StartCapture(int count, int interval, CancellationToken cancellationToken)
704         {
705             ValidateState(CameraState.Preview);
706
707             if (count < 2)
708             {
709                 throw new ArgumentOutOfRangeException(nameof(count), count, $"{nameof(count)} should be greater than one.");
710             }
711
712             if (interval < 0)
713             {
714                 throw new ArgumentOutOfRangeException(nameof(interval), interval, $"{nameof(interval)} should be greater than or equal to zero.");
715             }
716
717             //Handle CancellationToken
718             if (cancellationToken != CancellationToken.None)
719             {
720                 cancellationToken.Register(() =>
721                 {
722                     CameraErrorFactory.ThrowIfError(Native.StopContinuousCapture(_handle),
723                         "Failed to cancel the continuous capture");
724                     SetState(CameraState.Captured);
725                 });
726             }
727
728             CameraErrorFactory.ThrowIfError(Native.StartContinuousCapture(_handle, count, interval,
729                 _capturingCallback, _captureCompletedCallback, IntPtr.Zero), "Failed to start the continuous capture.");
730
731             SetState(CameraState.Capturing);
732         }
733
734         /// <summary>
735         /// Starts camera auto-focusing, asynchronously.
736         /// The camera must be in the <see cref="CameraState.Preview"/> or <see cref="CameraState.Captured"/> state.
737         /// </summary>
738         /// <since_tizen> 3 </since_tizen>
739         /// <param name="continuous">Continuous auto focus</param>
740         /// <privilege>
741         /// http://tizen.org/privilege/camera
742         /// </privilege>
743         /// <remarks>
744         /// If continuous status is true, the camera continuously tries to focus.
745         /// </remarks>
746         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
747         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
748         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
749         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
750         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
751         public void StartFocusing(bool continuous)
752         {
753             ValidateState(CameraState.Preview, CameraState.Captured);
754
755             CameraErrorFactory.ThrowIfError(Native.StartFocusing(_handle, continuous),
756                 "Failed to cancel the camera focus.");
757         }
758
759         /// <summary>
760         /// Stops camera auto focusing.
761         /// The camera must be in the <see cref="CameraState.Preview"/> or <see cref="CameraState.Captured"/> state.
762         /// </summary>
763         /// <since_tizen> 3 </since_tizen>
764         /// <privilege>
765         /// http://tizen.org/privilege/camera
766         /// </privilege>
767         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
768         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
769         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
770         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
771         public void StopFocusing()
772         {
773             ValidateState(CameraState.Preview, CameraState.Captured);
774
775             CameraErrorFactory.ThrowIfError(Native.CancelFocusing(_handle),
776                 "Failed to cancel the camera focus.");
777         }
778
779         /// <summary>
780         /// Starts face detection.
781         /// The camera must be in the <see cref="CameraState.Preview"/> state.
782         /// </summary>
783         /// <since_tizen> 3 </since_tizen>
784         /// <privilege>
785         /// http://tizen.org/privilege/camera
786         /// </privilege>
787         /// <remarks>
788         /// This should be called after <see cref="StartPreview"/> is started.
789         /// The Eventhandler set using <see cref="FaceDetected"/> invoked when the face is detected in preview frame.
790         /// Internally it starts continuous focus and focusing on the detected face.
791         /// </remarks>
792         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
793         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
794         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
795         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
796         public void StartFaceDetection()
797         {
798             ValidateState(CameraState.Preview);
799
800             _faceDetectedCallback = (IntPtr faces, int count, IntPtr userData) =>
801             {
802                 var result = new List<FaceDetectionData>();
803                 IntPtr current = faces;
804
805                 for (int i = 0; i < count; i++)
806                 {
807                     result.Add(new FaceDetectionData(current));
808                     current = IntPtr.Add(current, Marshal.SizeOf<Native.DetectedFaceStruct>());
809                 }
810
811                 FaceDetected?.Invoke(this, new FaceDetectedEventArgs(result));
812             };
813             CameraErrorFactory.ThrowIfError(Native.StartFaceDetection(_handle, _faceDetectedCallback, IntPtr.Zero),
814                 "Failed to start face detection");
815         }
816
817         /// <summary>
818         /// Stops face detection.
819         /// </summary>
820         /// <since_tizen> 3 </since_tizen>
821         /// <privilege>
822         /// http://tizen.org/privilege/camera
823         /// </privilege>
824         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
825         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
826         /// <exception cref="ObjectDisposedException">The camera already has been disposed.</exception>
827         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
828         public void StopFaceDetection()
829         {
830             if (_faceDetectedCallback == null)
831             {
832                 throw new InvalidOperationException("The face detection is not started.");
833             }
834
835             CameraErrorFactory.ThrowIfError(Native.StopFaceDetection(_handle),
836                 "Failed to stop the face detection.");
837
838             _faceDetectedCallback = null;
839         }
840         #endregion Methods
841
842         #region Callback registrations
843         private void RegisterCallbacks()
844         {
845             RegisterErrorCallback();
846             RegisterFocusStateChanged();
847             RegisterInterruptStartedCallback();
848             RegisterInterruptedCallback();
849             RegisterStateChangedCallback();
850
851             //Define capturing callback
852             _capturingCallback = (IntPtr main, IntPtr postview, IntPtr thumbnail, IntPtr userData) =>
853             {
854                 Capturing?.Invoke(this, new CameraCapturingEventArgs(new StillImage(main),
855                     postview == IntPtr.Zero ? null : new StillImage(postview),
856                     thumbnail == IntPtr.Zero ? null : new StillImage(thumbnail)));
857             };
858
859             //Define captureCompleted callback
860             _captureCompletedCallback = _ =>
861             {
862                 SetState(CameraState.Captured);
863                 CaptureCompleted?.Invoke(this, EventArgs.Empty);
864             };
865         }
866
867         private void RegisterInterruptStartedCallback()
868         {
869             _interruptStartedCallback = (CameraPolicy policy, CameraState state, IntPtr userData) =>
870             {
871                 InterruptStarted?.Invoke(this, new CameraInterruptStartedEventArgs(policy, state));
872             };
873             CameraErrorFactory.ThrowIfError(Native.SetInterruptStartedCallback(_handle, _interruptStartedCallback, IntPtr.Zero),
874                 "Failed to set interrupt callback");
875         }
876
877         private void RegisterInterruptedCallback()
878         {
879             _interruptedCallback = (CameraPolicy policy, CameraState previous, CameraState current, IntPtr userData) =>
880             {
881                 Interrupted?.Invoke(this, new CameraInterruptedEventArgs(policy, previous, current));
882             };
883             CameraErrorFactory.ThrowIfError(Native.SetInterruptedCallback(_handle, _interruptedCallback, IntPtr.Zero),
884                 "Failed to set interrupt callback");
885         }
886
887         private void RegisterErrorCallback()
888         {
889             _errorCallback = (CameraErrorCode error, CameraState current, IntPtr userData) =>
890             {
891                 ErrorOccurred?.Invoke(this, new CameraErrorOccurredEventArgs(error, current));
892             };
893             CameraErrorFactory.ThrowIfError(Native.SetErrorCallback(_handle, _errorCallback, IntPtr.Zero),
894                 "Setting error callback failed");
895         }
896
897         private void RegisterStateChangedCallback()
898         {
899             _stateChangedCallback = (CameraState previous, CameraState current, bool byPolicy, IntPtr _) =>
900             {
901                 SetState(current);
902                 Log.Info(CameraLog.Tag, "Camera state changed " + previous.ToString() + " -> " + current.ToString());
903                 StateChanged?.Invoke(this, new CameraStateChangedEventArgs(previous, current, byPolicy));
904             };
905             CameraErrorFactory.ThrowIfError(Native.SetStateChangedCallback(_handle, _stateChangedCallback, IntPtr.Zero),
906                 "Setting state changed callback failed");
907         }
908
909         private static void RegisterDeviceStateChangedCallback()
910         {
911             _deviceStateChangedCallback = (CameraDevice device, CameraDeviceState state, IntPtr userData) =>
912             {
913                 _deviceStateChanged?.Invoke(null, new CameraDeviceStateChangedEventArgs(device, state));
914             };
915
916             CameraErrorFactory.ThrowIfError(Native.SetDeviceStateChangedCallback(_deviceStateChangedCallback, IntPtr.Zero, out _deviceStateCallbackId),
917                 "Failed to set device state changed callback");
918
919             Log.Info(CameraLog.Tag, "add callbackId " + _deviceStateCallbackId.ToString());
920         }
921
922         private static void UnregisterDeviceStateChangedCallback()
923         {
924             CameraErrorFactory.ThrowIfError(Native.UnsetDeviceStateChangedCallback(_deviceStateCallbackId),
925                 "Unsetting device state changed callback failed");
926             _deviceStateChangedCallback = null;
927             _deviceStateCallbackId = 0;
928         }
929
930         private void RegisterFocusStateChanged()
931         {
932             _focusStateChangedCallback = (CameraFocusState state, IntPtr userData) =>
933             {
934                 FocusStateChanged?.Invoke(this, new CameraFocusStateChangedEventArgs(state));
935             };
936             CameraErrorFactory.ThrowIfError(Native.SetFocusStateChangedCallback(_handle, _focusStateChangedCallback, IntPtr.Zero),
937                 "Setting focus changed callback failed");
938         }
939
940         private void RegisterHdrCaptureProgress()
941         {
942             _hdrCaptureProgressCallback = (int percent, IntPtr userData) =>
943             {
944                 _hdrCaptureProgress?.Invoke(this, new HdrCaptureProgressEventArgs(percent));
945             };
946             CameraErrorFactory.ThrowIfError(Native.SetHdrCaptureProgressCallback(_handle, _hdrCaptureProgressCallback, IntPtr.Zero),
947                 "Setting Hdr capture progress callback failed");
948         }
949
950         private void UnregisterHdrCaptureProgress()
951         {
952             CameraErrorFactory.ThrowIfError(Native.UnsetHdrCaptureProgressCallback(_handle),
953                 "Unsetting hdr capture progress is failed");
954             _hdrCaptureProgressCallback = null;
955         }
956
957         private void RegisterPreviewCallback()
958         {
959             _previewCallback = (IntPtr frame, IntPtr userData) =>
960             {
961                 _preview?.Invoke(this, new PreviewEventArgs(new PreviewFrame(frame)));
962             };
963             CameraErrorFactory.ThrowIfError(Native.SetPreviewCallback(_handle, _previewCallback, IntPtr.Zero),
964                 "Setting preview callback failed");
965         }
966
967         private void UnregisterPreviewCallback()
968         {
969             CameraErrorFactory.ThrowIfError(Native.UnsetPreviewCallback(_handle),
970                 "Unsetting preview callback failed");
971             _previewCallback = null;
972         }
973
974         private void RegisterMediaPacketPreviewCallback()
975         {
976             _mediaPacketPreviewCallback = (IntPtr mediaPacket, IntPtr userData) =>
977             {
978                 MediaPacket packet = MediaPacket.From(mediaPacket);
979                 var eventHandler = _mediaPacketPreview;
980
981                 if (eventHandler != null)
982                 {
983                     eventHandler.Invoke(this, new MediaPacketPreviewEventArgs(packet));
984                 }
985                 else
986                 {
987                     packet.Dispose();
988                 }
989             };
990             CameraErrorFactory.ThrowIfError(Native.SetMediaPacketPreviewCallback(_handle, _mediaPacketPreviewCallback, IntPtr.Zero),
991                 "Setting media packet preview callback failed");
992         }
993
994         private void UnregisterMediaPacketPreviewCallback()
995         {
996             CameraErrorFactory.ThrowIfError(Native.UnsetMediaPacketPreviewCallback(_handle),
997                 "Unsetting media packet preview callback failed");
998             _mediaPacketPreviewCallback = null;
999         }
1000         #endregion Callback registrations
1001     }
1002 }
1003