ecbeae9dcbc451d462d2cbf539f5b80c1237ec1e
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia / 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 System.Collections;
24 namespace Tizen.Multimedia
25 {
26     static internal class CameraLog
27     {
28         internal const string Tag = "Tizen.Multimedia.Camera";
29     }
30
31     /// <summary>
32     /// The camera class provides methods to capture photos and support setting up notifications
33     /// for state changes of capturing, previewing, focusing, information about resolution and binary format
34     /// and functions for picture manipulations like sepia negative and many more.
35     /// It also notifies you when a significant picture parameter changes e.g. focus.
36     /// </summary>
37     /// <privilege>
38     /// http://tizen.org/privilege/camera
39     /// </privilege>
40     public class Camera : IDisposable
41     {
42         private IntPtr _handle = IntPtr.Zero;
43         private bool _disposed = false;
44         private CameraState _state = CameraState.None;
45         private static Dictionary<object, int> _callbackIdInfo = new Dictionary<object, int>();
46
47         /// <summary>
48         /// Initializes a new instance of the <see cref="Camera"/> Class.
49         /// </summary>
50         /// <param name="device">The camera device to access</param>
51         public Camera(CameraDevice device)
52         {
53             CameraErrorFactory.ThrowIfError(Interop.Camera.Create((int)device, out _handle),
54                 "Failed to create camera instance");
55
56             Feature = new CameraFeatures(this);
57             Setting = new CameraSettings(this);
58             Display = new CameraDisplay(this);
59
60             RegisterCallbacks();
61
62             _state = CameraState.Created;
63         }
64
65         /// <summary>
66         /// Destructor of the camera class.
67         /// </summary>
68         ~Camera()
69         {
70             Dispose(false);
71         }
72
73         internal IntPtr GetHandle()
74         {
75             ValidateNotDisposed();
76             return _handle;
77         }
78
79 #region Dispose support
80         /// <summary>
81         /// Release any unmanaged resources used by this object.
82         /// </summary>
83         public void Dispose()
84         {
85             Dispose(true);
86             GC.SuppressFinalize(this);
87         }
88
89         protected virtual void Dispose(bool disposing)
90         {
91             if (!_disposed)
92             {
93                 if (disposing)
94                 {
95                     // to be used if there are any other disposable objects
96                 }
97
98                 if (_handle != IntPtr.Zero)
99                 {
100                     Interop.Camera.Destroy(_handle);
101                     _handle = IntPtr.Zero;
102                 }
103
104                 _disposed = true;
105             }
106         }
107
108         internal void ValidateNotDisposed()
109         {
110             if (_disposed)
111             {
112                 throw new ObjectDisposedException(nameof(Camera));
113             }
114         }
115 #endregion Dispose support
116
117 #region Check camera state
118         internal void ValidateState(params CameraState[] required)
119         {
120             ValidateNotDisposed();
121
122             Debug.Assert(required.Length > 0);
123
124             var curState = _state;
125             if (!required.Contains(curState))
126             {
127                 throw new InvalidOperationException($"The camera is not in a valid state. " +
128                     $"Current State : { curState }, Valid State : { string.Join(", ", required) }.");
129             }
130         }
131
132         internal void SetState(CameraState state)
133         {
134             _state = state;
135         }
136 #endregion Check camera state
137
138 #region EventHandlers
139         /// <summary>
140         /// Event that occurs when an camera is interrupted by policy.
141         /// </summary>
142         public event EventHandler<CameraInterruptedEventArgs> Interrupted;
143         private Interop.Camera.InterruptedCallback _interruptedCallback;
144
145         /// <summary>
146         /// Event that occurs when there is an asynchronous error.
147         /// </summary>
148         public event EventHandler<CameraErrorOccurredEventArgs> ErrorOccurred;
149         private Interop.Camera.ErrorCallback _errorCallback;
150
151         /// <summary>
152         /// Event that occurs when the auto focus state is changed.
153         /// </summary>
154         public event EventHandler<CameraFocusStateChangedEventArgs> FocusStateChanged;
155         private Interop.Camera.FocusStateChangedCallback _focusStateChangedCallback;
156
157         /// <summary>
158         /// Event that occurs when a face is detected in preview frame.
159         /// </summary>
160         public event EventHandler<FaceDetectedEventArgs> FaceDetected;
161         private Interop.Camera.FaceDetectedCallback _faceDetectedCallback;
162
163         /// <summary>
164         /// Event that occurs during capture of image.
165         /// </summary>
166         public event EventHandler<CameraCapturingEventArgs> Capturing;
167         private Interop.Camera.CapturingCallback _capturingCallback;
168
169         /// <summary>
170         /// Event that occurs after the capture of the image.
171         /// </summary>
172         public event EventHandler<EventArgs> CaptureCompleted;
173         private Interop.Camera.CaptureCompletedCallback _captureCompletedCallback;
174
175         /// <summary>
176         /// Event that occurs when there is change in HDR capture progress.
177         /// Check whether HdrCapture feature is supported or not before add this EventHandler.
178         /// </summary>
179         public event EventHandler<HdrCaptureProgressEventArgs> HdrCaptureProgress;
180         private Interop.Camera.HdrCaptureProgressCallback _hdrCaptureProgressCallback;
181
182         /// <summary>
183         /// Event that occurs when camera state is changed.
184         /// </summary>
185         public event EventHandler<CameraStateChangedEventArgs> StateChanged;
186         private Interop.Camera.StateChangedCallback _stateChangedCallback;
187
188     #region DeviceStateChanged callback
189         internal static Interop.Camera.DeviceStateChangedCallback _deviceStateChangedCallback;
190         public static event EventHandler<CameraDeviceStateChangedEventArgs> _deviceStateChanged;
191         public static object _deviceStateChangedEventLock = new object();
192
193         /// <summary>
194         /// Set the DeviceStateChanged Callback.
195         /// User doesn't need to create camera instance.
196         /// This static EventHandler calls platform function every time because each callback function have to remain its own callbackId.
197         /// </summary>
198         /// <param name="callback">Callback of type <see cref="Interop.Camera.DeviceStateChangedCallback"/>.</param>
199         /// <param name="callbackId">The Id of registered callback.</param>
200         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
201         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
202         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
203         public static event EventHandler<CameraDeviceStateChangedEventArgs> DeviceStateChanged
204         {
205             add
206             {
207                 lock (_deviceStateChangedEventLock)
208                 {
209                     int callbackId = 0;
210
211                     _deviceStateChangedCallback = (CameraDevice device, CameraDeviceState state, IntPtr userData) =>
212                     {
213                         _deviceStateChanged?.Invoke(null, new CameraDeviceStateChangedEventArgs(device, state));
214                     };
215                     CameraErrorFactory.ThrowIfError(Interop.Camera.SetDeviceStateChangedCallback(_deviceStateChangedCallback, IntPtr.Zero, out callbackId),
216                         "Failed to set interrupt callback");
217
218                     // Keep current callbackId and EventHandler pair to remove EventHandler later.
219                     _callbackIdInfo.Add(value, callbackId);
220                     Log.Info(CameraLog.Tag, "add callbackId " + callbackId.ToString());
221
222                     _deviceStateChanged += value;
223                 }
224             }
225
226             remove
227             {
228                 lock (_deviceStateChangedEventLock)
229                 {
230                     _deviceStateChanged -= value;
231
232                     int callbackId = 0;
233                     _callbackIdInfo.TryGetValue(value, out callbackId);
234                     Log.Info(CameraLog.Tag, "remove callbackId " + callbackId.ToString());
235
236                     CameraErrorFactory.ThrowIfError(Interop.Camera.UnsetDeviceStateChangedCallback(callbackId),
237                             "Unsetting media packet preview callback failed");
238
239                     _callbackIdInfo.Remove(value);
240
241                     if (_deviceStateChanged == null)
242                     {
243                         _deviceStateChangedCallback = null;
244                     }
245                 }
246             }
247         }
248         #endregion DeviceStateChanged callback
249
250     #region Preview EventHandler
251         private Interop.Camera.PreviewCallback _previewCallback;
252         private event EventHandler<PreviewEventArgs> _preview;
253         private object _previewEventLock = new object();
254         /// <summary>
255         /// Event that occurs once per frame when previewing.
256         /// Preview callback is registered when user add callback explicitly to avoid useless P/Invoke.
257         /// </summary>
258         public event EventHandler<PreviewEventArgs> Preview
259         {
260             add
261             {
262                 lock (_previewEventLock)
263                 {
264                     if (_preview == null)
265                     {
266                         RegisterPreviewCallback();
267                     }
268
269                     _preview += value;
270                 }
271             }
272
273             remove
274             {
275                 lock (_previewEventLock)
276                 {
277                     _preview -= value;
278
279                     if (_preview == null)
280                     {
281                         CameraErrorFactory.ThrowIfError(Interop.Camera.UnsetPreviewCallback(_handle),
282                             "Unsetting preview callback failed");
283                         _previewCallback = null;
284                     }
285                 }
286             }
287         }
288     #endregion Preview EventHandler
289
290     #region MediaPacketPreview EventHandler
291         private Interop.Camera.MediaPacketPreviewCallback _mediaPacketPreviewCallback;
292         private EventHandler<MediaPacketPreviewEventArgs> _mediaPacketPreview;
293         private object _mediaPacketPreviewEventLock = new object();
294
295         /// <summary>
296         /// Event that occurs once per frame when previewing.
297         /// Preview callback is registered when user add callback explicitly to avoid useless P/Invoke.
298         /// </summary>
299         public event EventHandler<MediaPacketPreviewEventArgs> MediaPacketPreview
300         {
301             add
302             {
303                 lock (_mediaPacketPreviewEventLock)
304                 {
305                     if (_mediaPacketPreview == null)
306                     {
307                         RegisterMediaPacketPreviewCallback();
308                     }
309
310                     _mediaPacketPreview += value;
311                 }
312             }
313
314             remove
315             {
316                 lock (_mediaPacketPreviewEventLock)
317                 {
318                     _mediaPacketPreview -= value;
319
320                     if (_mediaPacketPreview == null)
321                     {
322                         CameraErrorFactory.ThrowIfError(Interop.Camera.UnsetMediaPacketPreviewCallback(_handle),
323                             "Unsetting media packet preview callback failed");
324                         _mediaPacketPreviewCallback = null;
325                     }
326                 }
327             }
328         }
329     #endregion MediaPacketPreview EventHandler
330
331 #endregion EventHandlers
332
333 #region Properties
334         /// <summary>
335         /// Get/Set the various camera settings.
336         /// </summary>
337         public CameraSettings Setting { get; }
338
339         /// <summary>
340         /// Gets the various camera features.
341         /// </summary>
342         public CameraFeatures Feature { get; }
343
344         /// <summary>
345         /// Get/set various camera display properties.
346         /// </summary>
347         public CameraDisplay Display { get; }
348
349         /// <summary>
350         /// Gets the state of the camera.
351         /// </summary>
352         public CameraState State
353         {
354             get
355             {
356                 CameraState val = CameraState.None;
357                 CameraErrorFactory.ThrowIfError(Interop.Camera.GetState(_handle, out val),
358                     "Failed to get camera state");
359
360                 return val;
361             }
362         }
363
364         /// <summary>
365         /// The hint for display reuse.
366         /// If the hint is set to true, the display will be reused when the camera device is changed with
367         /// ChangeDevice method.
368         /// </summary>
369         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
370         public bool DisplayReuseHint
371         {
372             get
373             {
374                 bool val = false;
375
376                 CameraErrorFactory.ThrowIfError(Interop.Camera.GetDisplayReuseHint(_handle, out val),
377                     "Failed to get camera display reuse hint");
378
379                 return val;
380             }
381
382             set
383             {
384                 CameraErrorFactory.ThrowIfError(Interop.Camera.SetDisplayReuseHint(_handle, value),
385                     "Failed to set display reuse hint.");
386             }
387         }
388
389         /// <summary>
390         /// Gets the facing direction of camera module.
391         /// </summary>
392         public CameraFacingDirection Direction
393         {
394             get
395             {
396                 CameraFacingDirection val = 0;
397
398                 CameraErrorFactory.ThrowIfError(Interop.Camera.GetFacingDirection(_handle, out val),
399                     "Failed to get camera direction");
400
401                 return val;
402             }
403         }
404
405         /// <summary>
406         /// Gets the camera device count.
407         /// </summary>
408         /// <remarks>
409         /// This returns 2, if the device supports primary and secondary cameras.
410         /// Otherwise 1, if the device only supports primary camera.
411         /// </remarks>
412         public int CameraCount
413         {
414             get
415             {
416                 int val = 0;
417
418                 CameraErrorFactory.ThrowIfError(Interop.Camera.GetDeviceCount(_handle, out val),
419                     "Failed to get camera device count");
420
421                 return val;
422             }
423         }
424 #endregion Properties
425
426 #region Methods
427         /// <summary>
428         /// Changes the camera device.
429         /// </summary>
430         /// <param name="device">The hardware camera to access.</param>
431         /// <privilege>
432         /// http://tizen.org/privilege/camera
433         /// </privilege>
434         /// <remarks>
435         /// If display reuse is set using <see cref="DisplayReuseHint"/>
436         /// before stopping the preview, the display will be reused and last frame on the display
437         /// can be kept even though camera device is changed.
438         /// The camera must be in the <see cref="CameraState.Created"/> or <see cref="CameraState.Preview"/> state.
439         /// </remarks>
440         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
441         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
442         /// <exception cref="NotSupportedException">In case of ChangeDevice feature is not supported</exception>
443         public void ChangeDevice(CameraDevice device)
444         {
445             ValidateState(CameraState.Created, CameraState.Preview);
446
447             CameraErrorFactory.ThrowIfError(Interop.Camera.ChangeDevice(_handle, (int)device),
448                 "Failed to change the camera device");
449         }
450
451         /// <summary>
452         /// Gets the device state.
453         /// </summary>
454         /// <privilege>
455         /// http://tizen.org/privilege/camera
456         /// </privilege>
457         /// <param name="device">The device to get state.</param>
458         /// <returns>Returns the state of camera device</returns>
459         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
460         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
461         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
462         public CameraDeviceState GetDeviceState(CameraDevice device)
463         {
464             int val = 0;
465
466             CameraErrorFactory.ThrowIfError(Interop.Camera.GetDeviceState(device, out val),
467                 "Failed to get the camera device state.");
468
469             return (CameraDeviceState)val;
470         }
471
472         public static CameraFlashState GetFlashState(CameraDevice device)
473         {
474             CameraFlashState val = CameraFlashState.NotUsed;
475
476             CameraErrorFactory.ThrowIfError(Interop.Camera.GetFlashState(device, out val),
477                 "Failed to get camera flash state");
478
479             return val;
480         }
481
482         /// <summary>
483         /// Starts capturing and drawing preview frames on the screen.
484         /// The display handle must be set using <see cref="Tizen.Multimedia.Camera.SetDisplay"/>
485         /// before using this method.
486         /// If needed set fps <see cref="Tizen.Multimedia.CameraSetting.PreviewFps"/>, preview resolution
487         /// <see cref="Tizen.Multimedia.Camera.PreviewResolution"/>, or preview format <see cref="Tizen.Multimedia.Camera.PreviewFormat"/>
488         /// before using this method.
489         /// </summary>
490         /// <privilege>
491         /// http://tizen.org/privilege/camera
492         /// </privilege>
493         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
494         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
495         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
496         public void StartPreview()
497         {
498             ValidateState(CameraState.Created, CameraState.Captured);
499
500             CameraErrorFactory.ThrowIfError(Interop.Camera.StartPreview(_handle),
501                 "Failed to start the camera preview.");
502
503             // Update by StateChangedCallback can be delayed for dozens of milliseconds.
504             SetState(CameraState.Preview);
505         }
506
507         /// <summary>
508         /// Stops capturing and drawing preview frames on the screen.
509         /// </summary>
510         /// <privilege>
511         /// http://tizen.org/privilege/camera
512         /// </privilege>
513         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
514         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
515         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
516         public void StopPreview()
517         {
518             CameraErrorFactory.ThrowIfError(Interop.Camera.StopPreview(_handle),
519                 "Failed to stop the camera preview.");
520
521             SetState(CameraState.Created);
522         }
523
524         /// <summary>
525         /// Starts capturing of still images.
526         /// EventHandler must be set for capturing using <see cref="Tizen.Multimedia.Camera.Capturing"/>
527         /// and for completed using <see cref="Tizen.Multimedia.Camera.CaptureCompleted"/> before
528         /// calling this method.
529         /// </summary>
530         /// <privilege>
531         /// http://tizen.org/privilege/camera
532         /// </privilege>
533         /// <remarks>
534         /// This function causes the transition of the camera state from Capturing to Captured
535         /// automatically and the corresponding EventHandlers will be invoked.
536         /// The camera's preview should be restarted by calling <see cref="Tizen.Multimedia.Camera.StartPreview"/>
537         /// method.
538         /// </remarks>
539         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
540         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
541         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
542         public void StartCapture()
543         {
544             ValidateState(CameraState.Preview);
545
546             CameraErrorFactory.ThrowIfError(Interop.Camera.StartCapture(_handle, _capturingCallback, _captureCompletedCallback, IntPtr.Zero),
547                 "Failed to start the camera capture.");
548
549             SetState(CameraState.Capturing);
550         }
551
552         /// <summary>
553         /// Starts continuously capturing still images.
554         /// EventHandler must be set for capturing using <see cref="Tizen.Multimedia.Camera.Capturing"/>
555         /// and for completed using <see cref="Tizen.Multimedia.Camera.CaptureCompleted"/> before
556         /// calling this method.
557         /// </summary>
558         /// <privilege>
559         /// http://tizen.org/privilege/camera
560         /// </privilege>
561         /// <param name="count">The number of still images.</param>
562         /// <param name="interval">The interval of the capture(milliseconds).</param>
563         /// <remarks>
564         /// If this is not supported zero shutter lag occurs. The capture resolution could be
565         /// changed to the preview resolution. This function causes the transition of the camera state
566         /// from Capturing to Captured automatically and the corresponding Eventhandlers will be invoked.
567         /// Each captured image will be delivered through Eventhandler set using <see cref="Tizen.Multimedia.Camera.Capturing"/> event.
568         /// The camera's preview should be restarted by calling <see cref="Tizen.Multimedia.Camera.StartPreview"/> method.
569         /// </remarks>
570         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
571         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
572         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
573         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
574         public void StartCapture(int count, int interval, CancellationToken cancellationToken)
575         {
576             ValidateState(CameraState.Preview);
577
578             if (count < 2)
579             {
580                 throw new ArgumentOutOfRangeException(nameof(count), count, $"{nameof(count)} should be greater than one.");
581             }
582
583             if (interval < 0)
584             {
585                 throw new ArgumentOutOfRangeException(nameof(interval), interval, $"{nameof(interval)} should be greater than or equal to zero.");
586             }
587
588             //Handle CancellationToken
589             if (cancellationToken != CancellationToken.None)
590             {
591                 cancellationToken.Register(() =>
592                 {
593                     CameraErrorFactory.ThrowIfError(Interop.Camera.StopContinuousCapture(_handle),
594                         "Failed to cancel the continuous capture");
595                     SetState(CameraState.Captured);
596                 });
597             }
598
599             CameraErrorFactory.ThrowIfError(Interop.Camera.StartContinuousCapture(_handle, count, interval,
600                 _capturingCallback, _captureCompletedCallback, IntPtr.Zero), "Failed to start the continuous capture.");
601
602             SetState(CameraState.Capturing);
603         }
604
605         /// <summary>
606         /// Starts camera auto-focusing, asynchronously.
607         /// </summary>
608         /// <param name="continuous">Continuous.</param>
609         /// <privilege>
610         /// http://tizen.org/privilege/camera
611         /// </privilege>
612         /// <remarks>
613         /// If continuous status is true, the camera continuously tries to focus.
614         /// </remarks>
615         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
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="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
619         public void StartFocusing(bool continuous)
620         {
621             ValidateState(CameraState.Preview, CameraState.Captured);
622
623             CameraErrorFactory.ThrowIfError(Interop.Camera.StartFocusing(_handle, continuous),
624                 "Failed to cancel the camera focus.");
625         }
626
627         /// <summary>
628         /// Stops camera auto focusing.
629         /// </summary>
630         /// <privilege>
631         /// http://tizen.org/privilege/camera
632         /// </privilege>
633         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
634         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
635         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
636         public void StopFocusing()
637         {
638             ValidateState(CameraState.Preview, CameraState.Captured);
639
640             CameraErrorFactory.ThrowIfError(Interop.Camera.CancelFocusing(_handle),
641                 "Failed to cancel the camera focus.");
642         }
643
644         /// <summary>
645         /// Starts face detection.
646         /// </summary>
647         /// <privilege>
648         /// http://tizen.org/privilege/camera
649         /// </privilege>
650         /// <remarks>
651         /// This should be called after <see cref="Tizen.Multimedia.Camera.StartPreview"/> is started.
652         /// The Eventhandler set using <see cref="Tizen.Multimedia.Camera.FaceDetected"/> invoked when the face is detected in preview frame.
653         /// Internally it starts continuous focus and focusing on the detected face.
654         /// </remarks>
655         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
656         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
657         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
658         public void StartFaceDetection()
659         {
660             ValidateState(CameraState.Preview);
661
662             _faceDetectedCallback = (IntPtr faces, int count, IntPtr userData) =>
663             {
664                 var result = new List<FaceDetectionData>();
665                 IntPtr current = faces;
666
667                 for (int i = 0; i < count; i++)
668                 {
669                     result.Add(new FaceDetectionData(current));
670                     current = IntPtr.Add(current, Marshal.SizeOf<Interop.Camera.DetectedFaceStruct>());
671                 }
672
673                 FaceDetected?.Invoke(this, new FaceDetectedEventArgs(result));
674             };
675             CameraErrorFactory.ThrowIfError(Interop.Camera.StartFaceDetection(_handle, _faceDetectedCallback, IntPtr.Zero),
676                 "Failed to start face detection");
677         }
678
679         /// <summary>
680         /// Stops face detection.
681         /// </summary>
682         /// <privilege>
683         /// http://tizen.org/privilege/camera
684         /// </privilege>
685         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
686         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
687         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
688         public void StopFaceDetection()
689         {
690             if (_faceDetectedCallback == null)
691             {
692                 throw new InvalidOperationException("The face detection is not started.");
693             }
694
695             CameraErrorFactory.ThrowIfError(Interop.Camera.StopFaceDetection(_handle),
696                 "Failed to stop the face detection.");
697
698             _faceDetectedCallback = null;
699         }
700 #endregion Methods
701
702 #region Callback registrations
703         private void RegisterCallbacks()
704         {
705             RegisterErrorCallback();
706             RegisterFocusStateChanged();
707             RegisterHdrCaptureProgress();
708             RegisterInterruptedCallback();
709             RegisterStateChangedCallback();
710
711             //Define capturing callback
712             _capturingCallback = (IntPtr image, IntPtr postview, IntPtr thumbnail, IntPtr userData) =>
713             {
714                 Capturing?.Invoke(this, new CameraCapturingEventArgs(new ImageData(image),
715                     postview == IntPtr.Zero ? null : new ImageData(postview),
716                     thumbnail == IntPtr.Zero ? null : new ImageData(thumbnail)));
717             };
718
719             //Define captureCompleted callback
720             _captureCompletedCallback = _ =>
721             {
722                 SetState(CameraState.Captured);
723                 CaptureCompleted?.Invoke(this, EventArgs.Empty);
724             };
725         }
726
727         private void RegisterInterruptedCallback()
728         {
729             _interruptedCallback = (CameraPolicy policy, CameraState previous, CameraState current, IntPtr userData) =>
730             {
731                 Interrupted?.Invoke(this, new CameraInterruptedEventArgs(policy, previous, current));
732             };
733             CameraErrorFactory.ThrowIfError(Interop.Camera.SetInterruptedCallback(_handle, _interruptedCallback, IntPtr.Zero),
734                 "Failed to set interrupt callback");
735         }
736
737         private void RegisterErrorCallback()
738         {
739             _errorCallback = (CameraErrorCode error, CameraState current, IntPtr userData) =>
740             {
741                 ErrorOccurred?.Invoke(this, new CameraErrorOccurredEventArgs(error, current));
742             };
743             CameraErrorFactory.ThrowIfError(Interop.Camera.SetErrorCallback(_handle, _errorCallback, IntPtr.Zero),
744                 "Setting error callback failed");
745         }
746
747         private void RegisterStateChangedCallback()
748         {
749             _stateChangedCallback = (CameraState previous, CameraState current, bool byPolicy, IntPtr _) =>
750             {
751                 _state = current;
752                 Log.Info(CameraLog.Tag, "Camera state changed " + previous.ToString() + " -> " + current.ToString());
753                 StateChanged?.Invoke(this, new CameraStateChangedEventArgs(previous, current, byPolicy));
754             };
755             CameraErrorFactory.ThrowIfError(Interop.Camera.SetStateChangedCallback(_handle, _stateChangedCallback, IntPtr.Zero),
756                 "Setting state changed callback failed");
757         }
758
759         private void RegisterFocusStateChanged()
760         {
761             _focusStateChangedCallback = (CameraFocusState state, IntPtr userData) =>
762             {
763                 FocusStateChanged?.Invoke(this, new CameraFocusStateChangedEventArgs(state));
764             };
765             CameraErrorFactory.ThrowIfError(Interop.Camera.SetFocusStateChangedCallback(_handle, _focusStateChangedCallback, IntPtr.Zero),
766                 "Setting focus changed callback failed");
767         }
768
769         private void RegisterHdrCaptureProgress()
770         {
771             //Hdr Capture can not be supported.
772             if (Feature.IsHdrCaptureSupported)
773             {
774                 _hdrCaptureProgressCallback = (int percent, IntPtr userData) =>
775                 {
776                     HdrCaptureProgress?.Invoke(this, new HdrCaptureProgressEventArgs(percent));
777                 };
778                 CameraErrorFactory.ThrowIfError(Interop.Camera.SetHdrCaptureProgressCallback(_handle, _hdrCaptureProgressCallback, IntPtr.Zero),
779                     "Setting Hdr capture progress callback failed");
780             }
781         }
782
783         private void RegisterPreviewCallback()
784         {
785             _previewCallback = (IntPtr frame, IntPtr userData) =>
786             {
787                 _preview?.Invoke(this, new PreviewEventArgs(new PreviewData(frame)));
788             };
789             CameraErrorFactory.ThrowIfError(Interop.Camera.SetPreviewCallback(_handle, _previewCallback, IntPtr.Zero),
790                 "Setting preview callback failed");
791         }
792
793         private void RegisterMediaPacketPreviewCallback()
794         {
795             _mediaPacketPreviewCallback = (IntPtr mediaPacket, IntPtr userData) =>
796             {
797                 MediaPacket packet = MediaPacket.From(mediaPacket);
798                 var eventHandler = _mediaPacketPreview;
799
800                 if (eventHandler != null)
801                 {
802                     eventHandler.Invoke(this, new MediaPacketPreviewEventArgs(packet));
803                 }
804                 else
805                 {
806                     packet.Dispose();
807                 }
808             };
809             CameraErrorFactory.ThrowIfError(Interop.Camera.SetMediaPacketPreviewCallback(_handle, _mediaPacketPreviewCallback, IntPtr.Zero),
810                 "Setting media packet preview callback failed");
811         }
812 #endregion Callback registrations
813     }
814 }
815