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