Release 4.0.0-preview1-00201
[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     /// 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).
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         /// An event that occurs when the camera interrupt is started by the policy.
151         /// </summary>
152         public event EventHandler<CameraInterruptStartedEventArgs> InterruptStarted;
153         private Native.InterruptStartedCallback _interruptStartedCallback;
154
155         /// <summary>
156         /// An event that occurs when an camera is interrupted by the policy.
157         /// </summary>
158         /// <since_tizen> 3 </since_tizen>
159         public event EventHandler<CameraInterruptedEventArgs> Interrupted;
160         private Native.InterruptedCallback _interruptedCallback;
161
162         /// <summary>
163         /// An 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         /// An 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         /// An event that occurs when a face is detected in the 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         /// An event that occurs during capture of an image.
185         /// </summary>
186         /// <since_tizen> 3 </since_tizen>
187         public event EventHandler<CameraCapturingEventArgs> Capturing;
188         private Native.CapturingCallback _capturingCallback;
189
190         /// <summary>
191         /// An 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         /// An event that occurs when there is a change in the HDR capture progress.
203         /// Checks whether the <see cref="CameraCapabilities.IsHdrCaptureSupported"/> is supported or not before adding 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         /// An event that occurs when the 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         /// An 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         /// An event that occurs once per frame when previewing.
289         /// Preview callback is registered when an user adds a 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         /// An event that occurs once per frame when previewing.
327         /// Preview callback is registered when an user adds a 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         /// Gets or sets 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 the 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 of.</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         CameraError IDisplayable<CameraError>.ApplyEcoreWindow(IntPtr windowHandle)
447         {
448             throw new NotSupportedException("Camera does not support NUI.Window display.");
449         }
450
451         /// <summary>
452         /// Gets the state of the camera.
453         /// </summary>
454         /// <since_tizen> 3 </since_tizen>
455         /// <value> None, Created, Preview, Capturing, Captured.</value>
456         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
457         public CameraState State
458         {
459             get
460             {
461                 ValidateNotDisposed();
462
463                 CameraState val = CameraState.None;
464                 CameraErrorFactory.ThrowIfError(Native.GetState(_handle, out val),
465                     "Failed to get camera state");
466
467                 return val;
468             }
469         }
470
471         /// <summary>
472         /// The hint for the display reuse.
473         /// If the hint is set to true, the display will be reused when the camera device is changed with
474         /// the ChangeDevice method.
475         /// </summary>
476         /// <since_tizen> 3 </since_tizen>
477         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
478         /// <exception cref="InvalidOperationException">An invalid state.</exception>
479         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
480         public bool DisplayReuseHint
481         {
482             get
483             {
484                 ValidateNotDisposed();
485
486                 CameraErrorFactory.ThrowIfError(Native.GetDisplayReuseHint(_handle, out bool val),
487                     "Failed to get camera display reuse hint");
488
489                 return val;
490             }
491
492             set
493             {
494                 ValidateState(CameraState.Preview);
495
496                 CameraErrorFactory.ThrowIfError(Native.SetDisplayReuseHint(_handle, value),
497                     "Failed to set display reuse hint.");
498             }
499         }
500
501         /// <summary>
502         /// Gets the facing direction of the camera module.
503         /// </summary>
504         /// <since_tizen> 3 </since_tizen>
505         /// <value>A <see cref="CameraFacingDirection"/> that specifies the facing direction of the camera device.</value>
506         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
507         public CameraFacingDirection Direction
508         {
509             get
510             {
511                 ValidateNotDisposed();
512
513                 CameraErrorFactory.ThrowIfError(Native.GetFacingDirection(_handle, out var val),
514                     "Failed to get camera direction");
515
516                 return val;
517             }
518         }
519
520         /// <summary>
521         /// Gets the camera device count.
522         /// </summary>
523         /// <since_tizen> 3 </since_tizen>
524         /// <value>This returns 2, if the device supports primary and secondary cameras.
525         /// Otherwise 1, if the device only supports primary camera.</value>
526         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
527         public int CameraCount
528         {
529             get
530             {
531                 ValidateNotDisposed();
532
533                 CameraErrorFactory.ThrowIfError(Native.GetDeviceCount(_handle, out int val),
534                     "Failed to get camera device count");
535
536                 return val;
537             }
538         }
539         #endregion Properties
540
541         #region Methods
542         /// <summary>
543         /// Changes the camera device.
544         /// </summary>
545         /// <since_tizen> 3 </since_tizen>
546         /// <param name="device">The hardware camera to access.</param>
547         /// <remarks>
548         /// If display reuse is set using <see cref="DisplayReuseHint"/>
549         /// before stopping the preview, the display will be reused and last frame on the display
550         /// can be kept even though camera device is changed.
551         /// The camera must be in the <see cref="CameraState.Created"/>.
552         /// </remarks>
553         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
554         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
555         /// <exception cref="NotSupportedException">In case of the ChangeDevice feature is not supported.</exception>
556         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
557         public void ChangeDevice(CameraDevice device)
558         {
559             ValidateState(CameraState.Created);
560             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
561
562             CameraErrorFactory.ThrowIfError(Native.ChangeDevice(_handle, device),
563                 "Failed to change the camera device");
564         }
565
566         /// <summary>
567         /// Gets the device state.
568         /// </summary>
569         /// <since_tizen> 3 </since_tizen>
570         /// <param name="device">The device to get the state.</param>
571         /// <returns>Returns the state of the camera device.</returns>
572         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
573         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
574         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
575         public static CameraDeviceState GetDeviceState(CameraDevice device)
576         {
577             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
578
579             CameraErrorFactory.ThrowIfError(Native.GetDeviceState(device, out var val),
580                 "Failed to get the camera device state.");
581
582             return val;
583         }
584
585         /// <summary>
586         /// Gets the flash state.
587         /// </summary>
588         /// <since_tizen> 3 </since_tizen>
589         /// <param name="device">The device to get the state.</param>
590         /// <returns>Returns the flash state of the camera device.</returns>
591         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
592         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
593         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
594         public static CameraFlashState GetFlashState(CameraDevice device)
595         {
596             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
597
598             CameraErrorFactory.ThrowIfError(Native.GetFlashState(device, out var val),
599                 "Failed to get camera flash state");
600
601             return val;
602         }
603
604         /// <summary>
605         /// Starts capturing and drawing preview frames on the screen.
606         /// The display property must be set using <see cref="Display"/> before using this method.
607         /// If needed set fps <see cref="CameraSettings.PreviewFps"/>, preview resolution
608         /// <see cref="CameraSettings.PreviewResolution"/>, or preview format <see cref="CameraSettings.PreviewPixelFormat"/>
609         /// before using this method.
610         /// The camera must be in the <see cref="CameraState.Created"/> or the <see cref="CameraState.Captured"/> state.
611         /// </summary>
612         /// <since_tizen> 3 </since_tizen>
613         /// <privilege>
614         /// http://tizen.org/privilege/camera
615         /// </privilege>
616         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
617         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
618         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
619         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
620         public void StartPreview()
621         {
622             ValidateState(CameraState.Created, CameraState.Captured);
623
624             CameraErrorFactory.ThrowIfError(Native.StartPreview(_handle),
625                 "Failed to start the camera preview.");
626
627             // Update by StateChangedCallback can be delayed for dozens of milliseconds.
628             SetState(CameraState.Preview);
629         }
630
631         /// <summary>
632         /// Stops capturing and drawing preview frames on the screen.
633         /// The camera must be in the <see cref="CameraState.Preview"/> state.
634         /// </summary>
635         /// <since_tizen> 3 </since_tizen>
636         /// <privilege>
637         /// http://tizen.org/privilege/camera
638         /// </privilege>
639         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
640         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
641         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
642         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
643         public void StopPreview()
644         {
645             ValidateState(CameraState.Preview);
646
647             CameraErrorFactory.ThrowIfError(Native.StopPreview(_handle),
648                 "Failed to stop the camera preview.");
649
650             SetState(CameraState.Created);
651         }
652
653         /// <summary>
654         /// Starts capturing of still images.
655         /// EventHandler must be set for capturing using <see cref="Capturing"/>
656         /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
657         /// The camera must be in the <see cref="CameraState.Preview"/> state.
658         /// </summary>
659         /// <since_tizen> 3 </since_tizen>
660         /// <privilege>
661         /// http://tizen.org/privilege/camera
662         /// </privilege>
663         /// <remarks>
664         /// This function causes the transition of the camera state from capturing to captured
665         /// automatically and the corresponding EventHandlers will be invoked.
666         /// The preview should be restarted by calling the <see cref="StartPreview"/> method after capture is completed.
667         /// </remarks>
668         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
669         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
670         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
671         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
672         public void StartCapture()
673         {
674             ValidateState(CameraState.Preview);
675
676             CameraErrorFactory.ThrowIfError(Native.StartCapture(_handle, _capturingCallback, _captureCompletedCallback, IntPtr.Zero),
677                 "Failed to start the camera capture.");
678
679             SetState(CameraState.Capturing);
680         }
681
682         /// <summary>
683         /// Starts continuously capturing still images.
684         /// EventHandler must be set for capturing using <see cref="Capturing"/>
685         /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
686         /// The camera must be in the <see cref="CameraState.Preview"/> state.
687         /// </summary>
688         /// <since_tizen> 3 </since_tizen>
689         /// <privilege>
690         /// http://tizen.org/privilege/camera
691         /// </privilege>
692         /// <param name="count">The number of still images.</param>
693         /// <param name="interval">The interval of the capture(milliseconds).</param>
694         /// <param name="cancellationToken">The cancellation token to cancel capturing.</param>
695         /// <seealso cref="CancellationToken"/>
696         /// <remarks>
697         /// If this is not supported, zero shutter lag occurs. The capture resolution could be
698         /// changed to the preview resolution. This function causes the transition of the camera state
699         /// from capturing to captured automatically and the corresponding Eventhandlers will be invoked.
700         /// Each captured image will be delivered through Eventhandler set using the <see cref="Capturing"/> event.
701         /// The preview should be restarted by calling the <see cref="StartPreview"/> method after capture is completed.
702         /// </remarks>
703         /// <exception cref="ArgumentOutOfRangeException">In case of invalid parameters.</exception>
704         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
705         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
706         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
707         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
708         public void StartCapture(int count, int interval, CancellationToken cancellationToken)
709         {
710             ValidateState(CameraState.Preview);
711
712             if (count < 2)
713             {
714                 throw new ArgumentOutOfRangeException(nameof(count), count, $"{nameof(count)} should be greater than one.");
715             }
716
717             if (interval < 0)
718             {
719                 throw new ArgumentOutOfRangeException(nameof(interval), interval, $"{nameof(interval)} should be greater than or equal to zero.");
720             }
721
722             //Handle CancellationToken
723             if (cancellationToken != CancellationToken.None)
724             {
725                 cancellationToken.Register(() =>
726                 {
727                     CameraErrorFactory.ThrowIfError(Native.StopContinuousCapture(_handle),
728                         "Failed to cancel the continuous capture");
729                     SetState(CameraState.Captured);
730                 });
731             }
732
733             CameraErrorFactory.ThrowIfError(Native.StartContinuousCapture(_handle, count, interval,
734                 _capturingCallback, _captureCompletedCallback, IntPtr.Zero), "Failed to start the continuous capture.");
735
736             SetState(CameraState.Capturing);
737         }
738
739         /// <summary>
740         /// Starts camera auto-focusing, asynchronously.
741         /// The camera must be in the <see cref="CameraState.Preview"/> or the <see cref="CameraState.Captured"/> state.
742         /// </summary>
743         /// <since_tizen> 3 </since_tizen>
744         /// <param name="continuous">Continuous auto focus.</param>
745         /// <privilege>
746         /// http://tizen.org/privilege/camera
747         /// </privilege>
748         /// <remarks>
749         /// If continuous status is true, the camera continuously tries to focus.
750         /// </remarks>
751         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
752         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
753         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
754         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
755         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
756         public void StartFocusing(bool continuous)
757         {
758             ValidateState(CameraState.Preview, CameraState.Captured);
759
760             CameraErrorFactory.ThrowIfError(Native.StartFocusing(_handle, continuous),
761                 "Failed to cancel the camera focus.");
762         }
763
764         /// <summary>
765         /// Stops camera auto focusing.
766         /// The camera must be in the <see cref="CameraState.Preview"/> or the <see cref="CameraState.Captured"/> state.
767         /// </summary>
768         /// <since_tizen> 3 </since_tizen>
769         /// <privilege>
770         /// http://tizen.org/privilege/camera
771         /// </privilege>
772         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
773         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
774         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
775         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
776         public void StopFocusing()
777         {
778             ValidateState(CameraState.Preview, CameraState.Captured);
779
780             CameraErrorFactory.ThrowIfError(Native.CancelFocusing(_handle),
781                 "Failed to cancel the camera focus.");
782         }
783
784         /// <summary>
785         /// Starts face detection.
786         /// The camera must be in the <see cref="CameraState.Preview"/> state.
787         /// </summary>
788         /// <since_tizen> 3 </since_tizen>
789         /// <privilege>
790         /// http://tizen.org/privilege/camera
791         /// </privilege>
792         /// <remarks>
793         /// This should be called after <see cref="StartPreview"/> is started.
794         /// The Eventhandler set using <see cref="FaceDetected"/> is invoked when the face is detected in the preview frame.
795         /// Internally, it starts continuously focus and focusing on the detected face.
796         /// </remarks>
797         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
798         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
799         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
800         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
801         public void StartFaceDetection()
802         {
803             ValidateState(CameraState.Preview);
804
805             _faceDetectedCallback = (IntPtr faces, int count, IntPtr userData) =>
806             {
807                 var result = new List<FaceDetectionData>();
808                 IntPtr current = faces;
809
810                 for (int i = 0; i < count; i++)
811                 {
812                     result.Add(new FaceDetectionData(current));
813                     current = IntPtr.Add(current, Marshal.SizeOf<Native.DetectedFaceStruct>());
814                 }
815
816                 FaceDetected?.Invoke(this, new FaceDetectedEventArgs(result));
817             };
818             CameraErrorFactory.ThrowIfError(Native.StartFaceDetection(_handle, _faceDetectedCallback, IntPtr.Zero),
819                 "Failed to start face detection");
820         }
821
822         /// <summary>
823         /// Stops face detection.
824         /// </summary>
825         /// <since_tizen> 3 </since_tizen>
826         /// <privilege>
827         /// http://tizen.org/privilege/camera
828         /// </privilege>
829         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
830         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
831         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
832         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
833         public void StopFaceDetection()
834         {
835             if (_faceDetectedCallback == null)
836             {
837                 throw new InvalidOperationException("The face detection is not started.");
838             }
839
840             CameraErrorFactory.ThrowIfError(Native.StopFaceDetection(_handle),
841                 "Failed to stop the face detection.");
842
843             _faceDetectedCallback = null;
844         }
845         #endregion Methods
846
847         #region Callback registrations
848         private void RegisterCallbacks()
849         {
850             RegisterErrorCallback();
851             RegisterFocusStateChanged();
852             RegisterInterruptStartedCallback();
853             RegisterInterruptedCallback();
854             RegisterStateChangedCallback();
855
856             //Define capturing callback
857             _capturingCallback = (IntPtr main, IntPtr postview, IntPtr thumbnail, IntPtr userData) =>
858             {
859                 Capturing?.Invoke(this, new CameraCapturingEventArgs(new StillImage(main),
860                     postview == IntPtr.Zero ? null : new StillImage(postview),
861                     thumbnail == IntPtr.Zero ? null : new StillImage(thumbnail)));
862             };
863
864             //Define captureCompleted callback
865             _captureCompletedCallback = _ =>
866             {
867                 SetState(CameraState.Captured);
868                 CaptureCompleted?.Invoke(this, EventArgs.Empty);
869             };
870         }
871
872         private void RegisterInterruptStartedCallback()
873         {
874             _interruptStartedCallback = (CameraPolicy policy, CameraState state, IntPtr userData) =>
875             {
876                 InterruptStarted?.Invoke(this, new CameraInterruptStartedEventArgs(policy, state));
877             };
878             CameraErrorFactory.ThrowIfError(Native.SetInterruptStartedCallback(_handle, _interruptStartedCallback, IntPtr.Zero),
879                 "Failed to set interrupt callback");
880         }
881
882         private void RegisterInterruptedCallback()
883         {
884             _interruptedCallback = (CameraPolicy policy, CameraState previous, CameraState current, IntPtr userData) =>
885             {
886                 Interrupted?.Invoke(this, new CameraInterruptedEventArgs(policy, previous, current));
887             };
888             CameraErrorFactory.ThrowIfError(Native.SetInterruptedCallback(_handle, _interruptedCallback, IntPtr.Zero),
889                 "Failed to set interrupt callback");
890         }
891
892         private void RegisterErrorCallback()
893         {
894             _errorCallback = (CameraErrorCode error, CameraState current, IntPtr userData) =>
895             {
896                 ErrorOccurred?.Invoke(this, new CameraErrorOccurredEventArgs(error, current));
897             };
898             CameraErrorFactory.ThrowIfError(Native.SetErrorCallback(_handle, _errorCallback, IntPtr.Zero),
899                 "Setting error callback failed");
900         }
901
902         private void RegisterStateChangedCallback()
903         {
904             _stateChangedCallback = (CameraState previous, CameraState current, bool byPolicy, IntPtr _) =>
905             {
906                 SetState(current);
907                 Log.Info(CameraLog.Tag, "Camera state changed " + previous.ToString() + " -> " + current.ToString());
908                 StateChanged?.Invoke(this, new CameraStateChangedEventArgs(previous, current, byPolicy));
909             };
910             CameraErrorFactory.ThrowIfError(Native.SetStateChangedCallback(_handle, _stateChangedCallback, IntPtr.Zero),
911                 "Setting state changed callback failed");
912         }
913
914         private static void RegisterDeviceStateChangedCallback()
915         {
916             _deviceStateChangedCallback = (CameraDevice device, CameraDeviceState state, IntPtr userData) =>
917             {
918                 _deviceStateChanged?.Invoke(null, new CameraDeviceStateChangedEventArgs(device, state));
919             };
920
921             CameraErrorFactory.ThrowIfError(Native.SetDeviceStateChangedCallback(_deviceStateChangedCallback, IntPtr.Zero, out _deviceStateCallbackId),
922                 "Failed to set device state changed callback");
923
924             Log.Info(CameraLog.Tag, "add callbackId " + _deviceStateCallbackId.ToString());
925         }
926
927         private static void UnregisterDeviceStateChangedCallback()
928         {
929             CameraErrorFactory.ThrowIfError(Native.UnsetDeviceStateChangedCallback(_deviceStateCallbackId),
930                 "Unsetting device state changed callback failed");
931             _deviceStateChangedCallback = null;
932             _deviceStateCallbackId = 0;
933         }
934
935         private void RegisterFocusStateChanged()
936         {
937             _focusStateChangedCallback = (CameraFocusState state, IntPtr userData) =>
938             {
939                 FocusStateChanged?.Invoke(this, new CameraFocusStateChangedEventArgs(state));
940             };
941             CameraErrorFactory.ThrowIfError(Native.SetFocusStateChangedCallback(_handle, _focusStateChangedCallback, IntPtr.Zero),
942                 "Setting focus changed callback failed");
943         }
944
945         private void RegisterHdrCaptureProgress()
946         {
947             _hdrCaptureProgressCallback = (int percent, IntPtr userData) =>
948             {
949                 _hdrCaptureProgress?.Invoke(this, new HdrCaptureProgressEventArgs(percent));
950             };
951             CameraErrorFactory.ThrowIfError(Native.SetHdrCaptureProgressCallback(_handle, _hdrCaptureProgressCallback, IntPtr.Zero),
952                 "Setting Hdr capture progress callback failed");
953         }
954
955         private void UnregisterHdrCaptureProgress()
956         {
957             CameraErrorFactory.ThrowIfError(Native.UnsetHdrCaptureProgressCallback(_handle),
958                 "Unsetting hdr capture progress is failed");
959             _hdrCaptureProgressCallback = null;
960         }
961
962         private void RegisterPreviewCallback()
963         {
964             _previewCallback = (IntPtr frame, IntPtr userData) =>
965             {
966                 _preview?.Invoke(this, new PreviewEventArgs(new PreviewFrame(frame)));
967             };
968             CameraErrorFactory.ThrowIfError(Native.SetPreviewCallback(_handle, _previewCallback, IntPtr.Zero),
969                 "Setting preview callback failed");
970         }
971
972         private void UnregisterPreviewCallback()
973         {
974             CameraErrorFactory.ThrowIfError(Native.UnsetPreviewCallback(_handle),
975                 "Unsetting preview callback failed");
976             _previewCallback = null;
977         }
978
979         private void RegisterMediaPacketPreviewCallback()
980         {
981             _mediaPacketPreviewCallback = (IntPtr mediaPacket, IntPtr userData) =>
982             {
983                 MediaPacket packet = MediaPacket.From(mediaPacket);
984                 var eventHandler = _mediaPacketPreview;
985
986                 if (eventHandler != null)
987                 {
988                     eventHandler.Invoke(this, new MediaPacketPreviewEventArgs(packet));
989                 }
990                 else
991                 {
992                     packet.Dispose();
993                 }
994             };
995             CameraErrorFactory.ThrowIfError(Native.SetMediaPacketPreviewCallback(_handle, _mediaPacketPreviewCallback, IntPtr.Zero),
996                 "Setting media packet preview callback failed");
997         }
998
999         private void UnregisterMediaPacketPreviewCallback()
1000         {
1001             CameraErrorFactory.ThrowIfError(Native.UnsetMediaPacketPreviewCallback(_handle),
1002                 "Unsetting media packet preview callback failed");
1003             _mediaPacketPreviewCallback = null;
1004         }
1005         #endregion Callback registrations
1006     }
1007 }