[Camera] Remove useless set of properties
[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.Runtime.InteropServices;
20 using Tizen.Internals.Errors;
21 using Tizen.Multimedia;
22 using System.IO;
23
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 Interop.Camera.CapturingCallback _capturingCallback;
45         private Interop.Camera.CaptureCompletedCallback _captureCompletedCallback;
46         private Interop.Camera.FaceDetectedCallback _faceDetectedCallback;
47         private EventHandler<CameraErrorOccurredEventArgs> _cameraErrorOccurred;
48         private EventHandler<CameraStateChangedEventArgs> _cameraStateChanged;
49         private EventHandler<PreviewEventArgs> _preview;
50         private EventHandler<CameraFocusChangedEventArgs> _cameraFocusChanged;
51         private EventHandler<CameraInterruptedEventArgs> _cameraInterrupted;
52         private EventHandler<HdrCaptureProgressEventArgs> _hdrProgress;
53         private EventHandler<MediaPacketPreviewEventArgs> _mediaPacketPreview;
54         private readonly CameraFeature _cameraFeature;
55         private readonly CameraSetting _cameraSetting;
56         private readonly CameraDisplay _cameraDisplay;
57         private readonly List<FaceDetectedData> _faces = new List<FaceDetectedData>();
58         private Interop.Camera.PreviewCallback _previewCallback;
59         Interop.Camera.MediaPacketPreviewCallback _mediaPacketCallback;
60         private Interop.Camera.FocusChangedCallback _focusCallback;
61         private Interop.Camera.HdrCaptureProgressCallback _hdrProgressCallback;
62         private Interop.Camera.StateChangedCallback _stateChangedCallback;
63         private Interop.Camera.InterruptedCallback _interruptedCallback;
64         private Interop.Camera.ErrorCallback _errorCallback;
65
66         /// <summary>
67         /// Initializes a new instance of the <see cref="Tizen.Multimedia.Camera"/> Class.
68         /// </summary>
69         /// <param name="device">Device.</param>
70         public Camera(CameraDevice device)
71         {
72             int ret = Interop.Camera.Create((int)device, out _handle);
73             if (ret != (int)CameraError.None)
74             {
75                 CameraErrorFactory.ThrowException(ret, "Failed to create camera instance");
76             }
77
78             _cameraFeature = new CameraFeature(_handle);
79             _cameraSetting = new CameraSetting(_handle);
80             _cameraDisplay = new CameraDisplay(_handle);
81         }
82
83         /// <summary>
84         /// Destructor of the camera class.
85         /// </summary>
86         ~Camera()
87         {
88             Dispose(false);
89         }
90
91         internal IntPtr GetHandle()
92         {
93             ValidateNotDisposed();
94             return _handle;
95         }
96
97         /// <summary>
98         /// Event that occurs when there is change in HDR capture progress.
99         /// </summary>
100         public event EventHandler<HdrCaptureProgressEventArgs> HdrCaptureProgress
101         {
102             add
103             {
104                 if (_hdrProgress == null)
105                 {
106                     _hdrProgressCallback = (int percent, IntPtr userData) =>
107                     {
108                         HdrCaptureProgressEventArgs eventArgs = new HdrCaptureProgressEventArgs(percent);
109                         _hdrProgress?.Invoke(this, eventArgs);
110                     };
111                     int ret = Interop.Camera.SetHdrCaptureProgressCallback(_handle, _hdrProgressCallback, IntPtr.Zero);
112                     if (ret != (int)CameraError.None)
113                     {
114                         CameraErrorFactory.ThrowException(ret, "Setting hdr progress callback failed");
115                     }
116                 }
117
118                 _hdrProgress += value;
119             }
120
121             remove
122             {
123                 _hdrProgress -= value;
124                 if (_hdrProgress == null)
125                 {
126                     int ret = Interop.Camera.UnsetHdrCaptureProgressCallback(_handle);
127                     if (ret != (int)CameraError.None)
128                     {
129                         CameraErrorFactory.ThrowException(ret, "Unsetting hdr progress callback failed");
130                     }
131                 }
132             }
133         }
134
135         /// <summary>
136         /// Event that occurs during capture of image.
137         /// </summary>
138         public event EventHandler<CapturingEventArgs> Capturing;
139
140         /// <summary>
141         /// Event that occurs after the capture of the image.
142         /// </summary>
143         public event EventHandler<EventArgs> CaptureCompleted;
144
145         /// <summary>
146         /// Event that occurs when camera state is changed.
147         /// </summary>
148         public event EventHandler<CameraStateChangedEventArgs> CameraStateChanged
149         {
150             add
151             {
152                 if (_cameraStateChanged == null)
153                 {
154                     _stateChangedCallback = (CameraState previous, CameraState current, bool byPolicy, IntPtr userData) =>
155                     {
156                         CameraStateChangedEventArgs eventArgs = new CameraStateChangedEventArgs(previous, current, byPolicy);
157                         _cameraStateChanged?.Invoke(this, eventArgs);
158                     };
159                     int ret = Interop.Camera.SetStateChangedCallback(_handle, _stateChangedCallback, IntPtr.Zero);
160                     if (ret != (int)CameraError.None)
161                     {
162                         CameraErrorFactory.ThrowException(ret, "Setting state changed callback failed");
163                     }
164                 }
165
166                 _cameraStateChanged += value;
167             }
168
169             remove
170             {
171                 _cameraStateChanged -= value;
172                 if (_cameraStateChanged == null)
173                 {
174                     int ret = Interop.Camera.UnsetStateChangedCallback(_handle);
175                     if (ret != (int)CameraError.None)
176                     {
177                         CameraErrorFactory.ThrowException(ret, "Unsetting state changed callback failed");
178                     }
179                 }
180             }
181         }
182
183         /// <summary>
184         /// Event that occurs when the auto-focus state of camera changes.
185         /// </summary>
186         public event EventHandler<CameraFocusChangedEventArgs> CameraFocusChanged
187         {
188             add
189             {
190                 if (_cameraFocusChanged == null)
191                 {
192                     _focusCallback = (CameraFocusState state, IntPtr userData) =>
193                     {
194                         CameraFocusChangedEventArgs eventArgs = new CameraFocusChangedEventArgs(state);
195                         _cameraFocusChanged?.Invoke(this, eventArgs);
196                     };
197                     int ret = Interop.Camera.SetFocusChangedCallback(_handle, _focusCallback, IntPtr.Zero);
198                     if (ret != (int)CameraError.None)
199                     {
200                         CameraErrorFactory.ThrowException(ret, "Setting focus changed callback failed");
201                     }
202                 }
203
204                 _cameraFocusChanged += value;
205             }
206
207             remove
208             {
209                 _cameraFocusChanged -= value;
210                 if (_cameraFocusChanged == null)
211                 {
212                     int ret = Interop.Camera.UnsetFocusChangedCallback(_handle);
213                     if (ret != (int)CameraError.None)
214                     {
215                         CameraErrorFactory.ThrowException(ret, "Unsetting focus changed callback failed");
216                     }
217                 }
218             }
219         }
220
221         /// <summary>
222         /// Event that occurs when an camera is interrupted by policy.
223         /// </summary>
224         public event EventHandler<CameraInterruptedEventArgs> CameraInterrupted
225         {
226             add
227             {
228                 if (_cameraInterrupted == null)
229                 {
230                     _interruptedCallback = (CameraPolicy policy, CameraState previous, CameraState current, IntPtr userData) =>
231                     {
232                         CameraInterruptedEventArgs eventArgs = new CameraInterruptedEventArgs(policy, previous, current);
233                         _cameraInterrupted?.Invoke(this, eventArgs);
234                     };
235                     int ret = Interop.Camera.SetInterruptedCallback(_handle, _interruptedCallback, IntPtr.Zero);
236                     if (ret != (int)CameraError.None)
237                     {
238                         CameraErrorFactory.ThrowException(ret, "Setting interrupt callback failed");
239                     }
240                 }
241
242                 _cameraInterrupted += value;
243             }
244
245             remove
246             {
247                 _cameraInterrupted -= value;
248                 if (_cameraInterrupted == null)
249                 {
250                     int ret = Interop.Camera.UnsetInterruptedCallback(_handle);
251                     if (ret != (int)CameraError.None)
252                     {
253                         CameraErrorFactory.ThrowException(ret, "Unsetting interrupt callback failed");
254                     }
255                 }
256             }
257         }
258
259         /// <summary>
260         /// Event that occurs when there is an asynchronous error.
261         /// </summary>
262         public event EventHandler<CameraErrorOccurredEventArgs> CameraErrorOccurred
263         {
264             add
265             {
266                 if (_cameraErrorOccurred == null)
267                 {
268                     _errorCallback = (CameraErrorCode error, CameraState current, IntPtr userData) =>
269                     {
270                         CameraErrorOccurredEventArgs eventArgs = new CameraErrorOccurredEventArgs(error, current);
271                         _cameraErrorOccurred?.Invoke(this, eventArgs);
272                     };
273                     int ret = Interop.Camera.SetErrorCallback(_handle, _errorCallback, IntPtr.Zero);
274                     if (ret != (int)CameraError.None)
275                     {
276                         CameraErrorFactory.ThrowException(ret, "Setting error callback failed");
277                     }
278                 }
279
280                 _cameraErrorOccurred += value;
281             }
282
283             remove
284             {
285                 _cameraErrorOccurred -= value;
286                 if (_cameraErrorOccurred == null)
287                 {
288                     int ret = Interop.Camera.UnsetErrorCallback(_handle);
289                     if (ret != (int)CameraError.None)
290                     {
291                         CameraErrorFactory.ThrowException(ret, "Unsetting error callback failed");
292                     }
293                 }
294             }
295         }
296
297         /// <summary>
298         /// Event that occurs when a face is detected in preview frame.
299         /// </summary>
300         public event EventHandler<FaceDetectedEventArgs> FaceDetected;
301
302         /// <summary>
303         /// Event that occurs once per frame when previewing.
304         /// </summary>
305         public event EventHandler<PreviewEventArgs> Preview
306         {
307             add
308             {
309                 if (_preview == null)
310                 {
311                     CreatePreviewCallback();
312                 }
313
314                 _preview += value;
315             }
316
317             remove
318             {
319                 _preview -= value;
320                 if (_preview == null)
321                 {
322                     int ret = Interop.Camera.UnsetPreviewCallback(_handle);
323                     if (ret != (int)CameraError.None)
324                     {
325                         CameraErrorFactory.ThrowException(ret, "Unsetting preview callback failed");
326                     }
327                 }
328             }
329         }
330
331         /// <summary>
332         /// Event that occurs once per frame when previewing.
333         /// </summary>
334         public event EventHandler<MediaPacketPreviewEventArgs> MediaPacketPreview
335         {
336             add
337             {
338                 if (_mediaPacketPreview == null)
339                 {
340                     CreateMediaPacketPreviewCallback();
341                 }
342
343                 _mediaPacketPreview += value;
344             }
345
346             remove
347             {
348                 _mediaPacketPreview -= value;
349                 if (_mediaPacketPreview == null)
350                 {
351                     int ret = Interop.Camera.UnsetMediaPacketPreviewCallback(_handle);
352                     if (ret != (int)CameraError.None)
353                     {
354                         CameraErrorFactory.ThrowException(ret, "Unsetting media packet preview callback failed");
355                     }
356                 }
357             }
358         }
359
360         /// <summary>
361         /// Get/Set the various camera settings.
362         /// </summary>
363         public CameraSetting Setting
364         {
365             get
366             {
367                 return _cameraSetting;
368             }
369         }
370
371         /// <summary>
372         /// Gets the various camera features.
373         /// </summary>
374         public CameraFeature Feature
375         {
376             get
377             {
378                 return _cameraFeature;
379             }
380         }
381
382         /// <summary>
383         /// Get/set various camera display properties.
384         /// </summary>
385         public CameraDisplay Display
386         {
387             get
388             {
389                 return _cameraDisplay;
390             }
391         }
392
393         /// <summary>
394         /// Gets the state of the camera.
395         /// </summary>
396         public CameraState State
397         {
398             get
399             {
400                 int val = 0;
401
402                 int ret = Interop.Camera.GetState(_handle, out val);
403                 if ((CameraError)ret != CameraError.None)
404                 {
405                     Log.Error(CameraLog.Tag, "Failed to get camera state, " + (CameraError)ret);
406                 }
407
408                 return (CameraState)val;
409             }
410         }
411
412         /// <summary>
413         /// The hint for display reuse.
414         /// If the hint is set to true, the display will be reused when the camera device is changed with
415         /// ChangeDevice method.
416         /// </summary>
417         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
418         public bool DisplayReuseHint
419         {
420             get
421             {
422                 bool val = false;
423
424                 int ret = Interop.Camera.GetDisplayReuseHint(_handle, out val);
425                 if ((CameraError)ret != CameraError.None)
426                 {
427                     Log.Error(CameraLog.Tag, "Failed to get camera display reuse hint, " + (CameraError)ret);
428                 }
429
430                 return val;
431             }
432
433             set
434             {
435                 int ret = Interop.Camera.SetDisplayReuseHint(_handle, value);
436                 if ((CameraError)ret != CameraError.None)
437                 {
438                     Log.Error(CameraLog.Tag, "Failed to set display reuse hint, " + (CameraError)ret);
439                     CameraErrorFactory.ThrowException(ret, "Failed to set display reuse hint.");
440                 }
441             }
442         }
443
444         /// <summary>
445         /// Resolution of the preview.
446         /// </summary>
447         /// <privilege>
448         /// http://tizen.org/privilege/camera
449         /// </privilege>
450         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
451         public CameraResolution PreviewResolution
452         {
453             get
454             {
455                 int width = 0;
456                 int height = 0;
457                 int ret = Interop.Camera.GetPreviewResolution(_handle, out width, out height);
458                 if ((CameraError)ret != CameraError.None)
459                 {
460                     Log.Error(CameraLog.Tag, "Failed to get camera preview resolution, " + (CameraError)ret);
461                 }
462
463                 CameraResolution res = new CameraResolution(width, height);
464                 return res;
465             }
466
467             set
468             {
469                 CameraResolution res = value;
470                 int ret = Interop.Camera.SetPreviewResolution(_handle, res.Width, res.Height);
471                 if ((CameraError)ret != CameraError.None)
472                 {
473                     Log.Error(CameraLog.Tag, "Failed to set preview resolution, " + (CameraError)ret);
474                     CameraErrorFactory.ThrowException(ret, "Failed to set preview resolution.");
475                 }
476             }
477         }
478
479         /// <summary>
480         /// Gets the recommended preview resolution.
481         /// </summary>
482         /// <remarks>
483         /// Depending on the capture resolution aspect ratio and display resolution,
484         /// the recommended preview resolution is determined.
485         /// </remarks>
486         public CameraResolution RecommendedPreviewResolution
487         {
488             get
489             {
490                 int width = 0;
491                 int height = 0;
492                 int ret = Interop.Camera.GetRecommendedPreviewResolution(_handle, out width, out height);
493                 if ((CameraError)ret != CameraError.None)
494                 {
495                     Log.Error(CameraLog.Tag, "Failed to get recommended preview resolution, " + (CameraError)ret);
496                 }
497
498                 CameraResolution res = new CameraResolution(width, height);
499                 return res;
500             }
501         }
502
503         /// <summary>
504         /// Resolution of the captured image.
505         /// </summary>
506         /// <privilege>
507         /// http://tizen.org/privilege/camera
508         /// </privilege>
509         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
510         public CameraResolution CaptureResolution
511         {
512             get
513             {
514                 int width = 0;
515                 int height = 0;
516                 int ret = Interop.Camera.GetCaptureResolution(_handle, out width, out height);
517                 if ((CameraError)ret != CameraError.None)
518                 {
519                     Log.Error(CameraLog.Tag, "Failed to get camera capture resolution, " + (CameraError)ret);
520                 }
521
522                 CameraResolution res = new CameraResolution(width, height);
523                 return res;
524             }
525
526             set
527             {
528                 CameraResolution res = value;
529                 int ret = Interop.Camera.SetCaptureResolution(_handle, res.Width, res.Height);
530                 if ((CameraError)ret != CameraError.None)
531                 {
532                     Log.Error(CameraLog.Tag, "Failed to set capture resolution, " + (CameraError)ret);
533                     CameraErrorFactory.ThrowException(ret, "Failed to set capture resolution.");
534                 }
535             }
536         }
537
538         /// <summary>
539         /// Format of an image to be captured.
540         /// </summary>
541         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
542         public CameraPixelFormat CaptureFormat
543         {
544             get
545             {
546                 int val = 0;
547                 int ret = Interop.Camera.GetCaptureFormat(_handle, out val);
548                 if ((CameraError)ret != CameraError.None)
549                 {
550                     Log.Error(CameraLog.Tag, "Failed to get camera capture format, " + (CameraError)ret);
551                 }
552
553                 return (CameraPixelFormat)val;
554             }
555
556             set
557             {
558                 int ret = Interop.Camera.SetCaptureFormat(_handle, (int)value);
559                 if ((CameraError)ret != CameraError.None)
560                 {
561                     Log.Error(CameraLog.Tag, "Failed to set capture format, " + (CameraError)ret);
562                     CameraErrorFactory.ThrowException(ret, "Failed to set capture format.");
563                 }
564             }
565         }
566
567         /// <summary>
568         /// The preview data format.
569         /// </summary>
570         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
571         public CameraPixelFormat PreviewFormat
572         {
573             get
574             {
575                 int val = 0;
576                 int ret = Interop.Camera.GetPreviewFormat(_handle, out val);
577                 if ((CameraError)ret != CameraError.None)
578                 {
579                     Log.Error(CameraLog.Tag, "Failed to get preview format, " + (CameraError)ret);
580                 }
581
582                 return (CameraPixelFormat)val;
583             }
584
585             set
586             {
587                 int ret = Interop.Camera.SetPreviewFormat(_handle, (int)value);
588                 if ((CameraError)ret != CameraError.None)
589                 {
590                     Log.Error(CameraLog.Tag, "Failed to set preview format, " + (CameraError)ret);
591                     CameraErrorFactory.ThrowException(ret, "Failed to set preview format.");
592                 }
593             }
594         }
595
596         /// <summary>
597         /// Gets the facing direction of camera module.
598         /// </summary>
599         public CameraFacingDirection Direction
600         {
601             get
602             {
603                 int val = 0;
604                 int ret = Interop.Camera.GetFacingDirection(_handle, out val);
605                 if ((CameraError)ret != CameraError.None)
606                 {
607                     Log.Error(CameraLog.Tag, "Failed to get camera direction, " + (CameraError)ret);
608                 }
609
610                 return (CameraFacingDirection)val;
611             }
612         }
613
614         /// <summary>
615         /// Gets the camera's flash state.
616         /// </summary>
617         public CameraFlashState FlashState
618         {
619             get
620             {
621                 int val = 0;
622                 int ret = Interop.Camera.GetFlashState(_handle, out val);
623                 if ((CameraError)ret != CameraError.None)
624                 {
625                     Log.Error(CameraLog.Tag, "Failed to get camera flash state, " + (CameraError)ret);
626                 }
627
628                 return (CameraFlashState)val;
629             }
630         }
631
632         /// <summary>
633         /// Gets the camera device count.
634         /// </summary>
635         /// <remarks>
636         /// If the device supports primary and secondary camera, this returns 2.
637         /// If 1 is returned, the device only supports primary camera.
638         /// </remarks>
639         public int CameraCount
640         {
641             get
642             {
643                 int val = 0;
644                 int ret = Interop.Camera.GetDeviceCount(_handle, out val);
645                 if ((CameraError)ret != CameraError.None)
646                 {
647                     Log.Error(CameraLog.Tag, "Failed to get camera device count, " + (CameraError)ret);
648                 }
649
650                 return val;
651             }
652         }
653
654         /// <summary>
655         /// Changes the camera device.
656         /// </summary>
657         /// <param name="device">The hardware camera to access.</param>
658         /// <privilege>
659         /// http://tizen.org/privilege/camera
660         /// </privilege>
661         /// <remarks>
662         /// This method can be used to change camera device without using destory and create method.
663         /// If display reuse is set using <see cref="Tizen.Multimedia.Camera.DisplayReuseHint"/>
664         /// before stopping the preview, display handle  will be reused and last frame on display
665         /// can be kept even though cameradevice is changed.
666         /// </remarks>
667         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
668         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
669         /// <exception cref="NotSupportedException">In case of ChangeDevice feature is not supported</exception>
670         public void ChangeDevice(CameraDevice device)
671         {
672             int ret = Interop.Camera.ChangeDevice(_handle, (int)device);
673             if (ret != (int)CameraError.None)
674             {
675                 CameraErrorFactory.ThrowException(ret, "Failed to change the camera device");
676             }
677         }
678
679         /// <summary>
680         /// Gets the device state.
681         /// </summary>
682         /// <privilege>
683         /// http://tizen.org/privilege/camera
684         /// </privilege>
685         /// <param name="device">The device to get state.</param>
686         /// <returns>Returns the state of camera device</returns>
687         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
688         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
689         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
690         public CameraDeviceState GetDeviceState(CameraDevice device)
691         {
692             int val = 0;
693             int ret = Interop.Camera.GetDeviceState(device, out val);
694             if (ret != (int)CameraError.None)
695             {
696                 CameraErrorFactory.ThrowException(ret, "Failed to get the camera device state.");
697             }
698
699             return (CameraDeviceState)val;
700         }
701
702         /// <summary>
703         /// Starts capturing and drawing preview frames on the screen.
704         /// The display handle must be set using <see cref="Tizen.Multimedia.Camera.SetDisplay"/>
705         /// before using this method.
706         /// If needed set fps <see cref="Tizen.Multimedia.CameraSetting.PreviewFps"/>, preview resolution
707         /// <see cref="Tizen.Multimedia.Camera.PreviewResolution"/>, or preview format <see cref="Tizen.Multimedia.Camera.PreviewFormat"/>
708         /// before using this method.
709         /// </summary>
710         /// <privilege>
711         /// http://tizen.org/privilege/camera
712         /// </privilege>
713         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
714         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
715         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
716         public void StartPreview()
717         {
718             int ret = Interop.Camera.StartPreview(_handle);
719             if (ret != (int)CameraError.None)
720             {
721                 CameraErrorFactory.ThrowException(ret, "Failed to start the camera preview.");
722             }
723         }
724
725         /// <summary>
726         /// Stops capturing and drawing preview frames on the screen.
727         /// </summary>
728         /// <privilege>
729         /// http://tizen.org/privilege/camera
730         /// </privilege>
731         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
732         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
733         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
734         public void StopPreview()
735         {
736             int ret = Interop.Camera.StopPreview(_handle);
737             if (ret != (int)CameraError.None)
738             {
739                 CameraErrorFactory.ThrowException(ret, "Failed to stop the camera preview.");
740             }
741         }
742
743         /// <summary>
744         /// Starts capturing of still images.
745         /// EventHandler must be set for capturing using <see cref="Tizen.Multimedia.Camera.Capturing"/>
746         /// and for completed using <see cref="Tizen.Multimedia.Camera.CaptureCompleted"/> before
747         /// calling this method.
748         /// </summary>
749         /// <privilege>
750         /// http://tizen.org/privilege/camera
751         /// </privilege>
752         /// <remarks>
753         /// This function causes the transition of the camera state from Capturing to Captured
754         /// automatically and the corresponding EventHandlers will be invoked.
755         /// The camera's preview should be restarted by calling <see cref="Tizen.Multimedia.Camera.StartPreview"/>
756         /// method.
757         /// </remarks>
758         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
759         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
760         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
761         public void StartCapture()
762         {
763             Log.Info(CameraLog.Tag, "StartCapture API starting");
764
765             _capturingCallback = (IntPtr image, IntPtr postview, IntPtr thumbnail, IntPtr userData) =>
766             {
767                 Interop.Camera.ImageDataStruct _img = new Interop.Camera.ImageDataStruct();
768                 Interop.Camera.ImageDataStruct _post = new Interop.Camera.ImageDataStruct();
769                 Interop.Camera.ImageDataStruct _thumb = new Interop.Camera.ImageDataStruct();
770                 ImageData img = new ImageData();
771                 ImageData post = new ImageData();
772                 ImageData thumb = new ImageData();
773
774                 if (image != IntPtr.Zero)
775                 {
776                     _img = Interop.Camera.IntPtrToImageDataStruct(image);
777                     CopyImageData(img, _img);
778                 }
779                 if (postview != IntPtr.Zero)
780                 {
781                     _post = Interop.Camera.IntPtrToImageDataStruct(postview);
782                     CopyImageData(post, _post);
783                 }
784                 if (thumbnail != IntPtr.Zero)
785                 {
786                     _thumb = Interop.Camera.IntPtrToImageDataStruct(thumbnail);
787                     CopyImageData(thumb, _thumb);
788                 }
789
790                 CapturingEventArgs eventArgs = new CapturingEventArgs(img, post, thumb);
791                 Capturing?.Invoke(this, eventArgs);
792             };
793
794             _captureCompletedCallback = (IntPtr userData) =>
795             {
796                 EventArgs eventArgs = new EventArgs();
797                 CaptureCompleted?.Invoke(this, eventArgs);
798             };
799
800             int ret = Interop.Camera.StartCapture(_handle, _capturingCallback, _captureCompletedCallback, IntPtr.Zero);
801             if (ret != (int)CameraError.None)
802             {
803                 CameraErrorFactory.ThrowException(ret, "Failed to start the camera capture.");
804             }
805             Log.Info(CameraLog.Tag, "StartCapture API finished");
806         }
807
808         /// <summary>
809         /// Aborts continuous capturing.
810         /// </summary>
811         /// <privilege>
812         /// http://tizen.org/privilege/camera
813         /// </privilege>
814         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
815         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
816         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
817         public void StopContinuousCapture()
818         {
819             int ret = Interop.Camera.StopContinuousCapture(_handle);
820             if (ret != (int)CameraError.None)
821             {
822                 CameraErrorFactory.ThrowException(ret, "Failed to stop the continuous capture.");
823             }
824         }
825
826         /// <summary>
827         /// Starts continuously capturing still images.
828         /// EventHandler must be set for capturing using <see cref="Tizen.Multimedia.Camera.Capturing"/>
829         /// and for completed using <see cref="Tizen.Multimedia.Camera.CaptureCompleted"/> before
830         /// calling this method.
831         /// </summary>
832         /// <privilege>
833         /// http://tizen.org/privilege/camera
834         /// </privilege>
835         /// <param name="count">The number of still images.</param>
836         /// <param name="interval">The interval of the capture(milliseconds).</param>
837         /// <remarks>
838         /// If this is not supported zero shutter lag occurs. The capture resolution could be
839         /// changed to the preview resolution. This function causes the transition of the camera state
840         /// from Capturing to Captured automatically and the corresponding Eventhandlers will be invoked.
841         /// Each captured image will be delivered through Eventhandler set using <see cref="Tizen.Multimedia.Camera.Capturing"/> event.
842         /// The camera's preview should be restarted by calling <see cref="Tizen.Multimedia.Camera.StartPreview"/> method.
843         /// </remarks>
844         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
845         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
846         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
847         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
848         public void StartContinuousCapture(int count, int interval)
849         {
850             _capturingCallback = (IntPtr image, IntPtr postview, IntPtr thumbnail, IntPtr userData) =>
851             {
852                 Interop.Camera.ImageDataStruct _img = new Interop.Camera.ImageDataStruct();
853                 Interop.Camera.ImageDataStruct _post = new Interop.Camera.ImageDataStruct();
854                 Interop.Camera.ImageDataStruct _thumb = new Interop.Camera.ImageDataStruct();
855                 ImageData img = new ImageData();
856                 ImageData post = new ImageData();
857                 ImageData thumb = new ImageData();
858
859                 if (image != IntPtr.Zero)
860                 {
861                     _img = Interop.Camera.IntPtrToImageDataStruct(image);
862                     CopyImageData(img, _img);
863                 }
864                 if (postview != IntPtr.Zero)
865                 {
866                     _post = Interop.Camera.IntPtrToImageDataStruct(postview);
867                     CopyImageData(post, _post);
868                 }
869                 if (thumbnail != IntPtr.Zero)
870                 {
871                     _thumb = Interop.Camera.IntPtrToImageDataStruct(thumbnail);
872                     CopyImageData(thumb, _thumb);
873                 }
874
875                 CapturingEventArgs eventArgs = new CapturingEventArgs(img, post, thumb);
876                 Capturing?.Invoke(this, eventArgs);
877             };
878
879             _captureCompletedCallback = (IntPtr userData) =>
880             {
881                 EventArgs eventArgs = new EventArgs();
882                 CaptureCompleted?.Invoke(this, eventArgs);
883             };
884
885             int ret = Interop.Camera.StartContinuousCapture(_handle, count, interval, _capturingCallback, _captureCompletedCallback, IntPtr.Zero);
886             if (ret != (int)CameraError.None)
887             {
888                 CameraErrorFactory.ThrowException(ret, "Failed to start the continuous capture.");
889             }
890         }
891
892         /// <summary>
893         /// Sets the display handle to show preview images.
894         /// </summary>
895         /// <param name="displayType">Display type.</param>
896         /// <param name="preview">MediaView object to display preview.</param>
897         /// <remarks>
898         /// This method must be called before StartPreview() method.
899         /// In Custom ROI display mode, DisplayRoiArea property must be set before calling this method.
900         /// </remarks>
901         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
902         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
903         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
904         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
905         public void SetDisplay(CameraDisplayType displayType, MediaView preview)
906         {
907              int ret = Interop.Camera.SetDisplay(_handle, (int)displayType, preview);
908              if (ret != (int)CameraError.None)
909              {
910                  CameraErrorFactory.ThrowException(ret, "Failed to set the camera display.");
911              }
912         }
913
914         /// <summary>
915         /// Starts camera auto-focusing, asynchronously.
916         /// </summary>
917         /// <param name="continuous">Continuous.</param>
918         /// <privilege>
919         /// http://tizen.org/privilege/camera
920         /// </privilege>
921         /// <remarks>
922         /// If continuous status is true, the camera continuously tries to focus.
923         /// </remarks>
924         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
925         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
926         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
927         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
928         public void StartFocusing(bool continuous)
929         {
930             int ret = Interop.Camera.StartFocusing(_handle, continuous);
931             if (ret != (int)CameraError.None)
932             {
933                 CameraErrorFactory.ThrowException(ret, "Failed to cancel the camera focus.");
934             }
935         }
936
937         /// <summary>
938         /// Stops camera auto focusing.
939         /// </summary>
940         /// <privilege>
941         /// http://tizen.org/privilege/camera
942         /// </privilege>
943         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
944         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
945         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
946         public void CancelFocusing()
947         {
948             int ret = Interop.Camera.CancelFocusing(_handle);
949             if (ret != (int)CameraError.None)
950             {
951                 CameraErrorFactory.ThrowException(ret, "Failed to cancel the camera focus.");
952             }
953         }
954
955         /// <summary>
956         /// Starts face detection.
957         /// </summary>
958         /// <privilege>
959         /// http://tizen.org/privilege/camera
960         /// </privilege>
961         /// <remarks>
962         /// This should be called after <see cref="Tizen.Multimedia.Camera.StartPreview"/> is started.
963         /// The Eventhandler set using <see cref="Tizen.Multimedia.Camera.FaceDetected"/> invoked when the face is detected in preview frame.
964         /// Internally it starts continuous focus and focusing on the detected face.
965         /// </remarks>
966         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
967         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
968         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
969         public void StartFaceDetection()
970         {
971             _faceDetectedCallback = (IntPtr faces, int count, IntPtr userData) =>
972             {
973                 Interop.Camera.DetectedFaceStruct[] faceStruct = new Interop.Camera.DetectedFaceStruct[count];
974                 IntPtr current = faces;
975                 for (int i = 0; i < count; i++)
976                 {
977                     faceStruct[i] = Marshal.PtrToStructure<Interop.Camera.DetectedFaceStruct>(current);
978                     FaceDetectedData face = new FaceDetectedData(faceStruct[i].id, faceStruct[i].score, faceStruct[i].x, faceStruct[i].y, faceStruct[i].width, faceStruct[i].height);
979                     _faces.Add(face);
980                     current = (IntPtr)((long)current + Marshal.SizeOf(faceStruct[i]));
981                 }
982
983                 FaceDetectedEventArgs eventArgs = new FaceDetectedEventArgs(_faces);
984                 FaceDetected?.Invoke(this, eventArgs);
985             };
986
987             int ret = Interop.Camera.StartFaceDetection(_handle, _faceDetectedCallback, IntPtr.Zero);
988             if (ret != (int)CameraError.None)
989             {
990                 CameraErrorFactory.ThrowException(ret, "Failed to start the face detection.");
991             }
992         }
993
994         /// <summary>
995         /// Stops face detection.
996         /// </summary>
997         /// <privilege>
998         /// http://tizen.org/privilege/camera
999         /// </privilege>
1000         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
1001         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
1002         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted</exception>
1003         public void StopFaceDetection()
1004         {
1005             int ret = Interop.Camera.StopFaceDetection(_handle);
1006             if (ret != (int)CameraError.None)
1007             {
1008                 CameraErrorFactory.ThrowException(ret, "Failed to stop the face detection.");
1009             }
1010         }
1011
1012         /// <summary>
1013         /// DeviceChangedCallback delegate.
1014         /// </summary>
1015         public delegate void DeviceChangedCallback(CameraDevice device, CameraDeviceState state, IntPtr userData);
1016
1017         /// <summary>
1018         /// set the DeviceStateChanged Callback.
1019         /// </summary>
1020         /// <param name="callback">Callback of type <see cref="Tizen.Multimedia.Camera.DeviceChangedCallback"/>.</param>
1021         /// <param name="callbackId">The Id of registered callback.</param>
1022         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
1023         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
1024         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
1025         public static void SetDeviceStateChangedCallback(DeviceChangedCallback callback, out int callbackId)
1026         {
1027             int ret = Camera.AddDeviceChangedCallback(callback, IntPtr.Zero, out callbackId);
1028             if (ret != (int)CameraError.None)
1029             {
1030                 CameraErrorFactory.ThrowException(ret, "Setting device state changed callback failed");
1031             }
1032         }
1033
1034         /// <summary>
1035         /// Unset the DeviceStateChanged Callback.
1036         /// </summary>
1037         /// <param name="callbackId">Registered callbackId to be deleted.</param>
1038         /// <exception cref="InvalidOperationException">In case of any invalid operations</exception>
1039         /// <exception cref="NotSupportedException">In case of this feature is not supported</exception>
1040         /// <exception cref="ArgumentException">In case of invalid parameters</exception>
1041         public static void UnsetDeviceStateChangedCallback(int callbackId)
1042         {
1043             int ret = Interop.Camera.UnsetDeviceStateChangedCallback(callbackId);
1044             if (ret != (int)CameraError.None)
1045             {
1046                 CameraErrorFactory.ThrowException(ret, "Unsetting device state changed callback failed");
1047             }
1048         }
1049
1050         /// <summary>
1051         /// Release any unmanaged resources used by this object.
1052         /// </summary>
1053         public void Dispose()
1054         {
1055             Dispose(true);
1056             GC.SuppressFinalize(this);
1057         }
1058
1059         protected virtual void Dispose(bool disposing)
1060         {
1061             if (!_disposed)
1062             {
1063                 if (disposing)
1064                 {
1065                     // to be used if there are any other disposable objects
1066                 }
1067
1068                 if (_handle != IntPtr.Zero)
1069                 {
1070                     Interop.Camera.Destroy(_handle);
1071                     _handle = IntPtr.Zero;
1072                 }
1073
1074                 _disposed = true;
1075             }
1076         }
1077
1078         internal void ValidateNotDisposed()
1079         {
1080             if (_disposed)
1081             {
1082                 throw new ObjectDisposedException(nameof(Camera));
1083             }
1084         }
1085
1086         [DllImport(Interop.Libraries.Camera, EntryPoint = "camera_add_device_state_changed_cb")]
1087         internal static extern int AddDeviceChangedCallback(DeviceChangedCallback callback, IntPtr userData, out int callbackId);
1088
1089         internal static void CopyImageData(ImageData image, Interop.Camera.ImageDataStruct img)
1090         {
1091             image._data = new byte[img.size];
1092             if(img.data != IntPtr.Zero)
1093                 Marshal.Copy(img.data, image._data, 0, (int)img.size);
1094             image._width = img.width;
1095             image._height = img.height;
1096             image._format = img.format;
1097             image._exif = new byte[img.exifSize];
1098             if (img.exif != IntPtr.Zero)
1099                 Marshal.Copy(img.exif, image._exif, 0, (int)img.exifSize);
1100         }
1101
1102         internal static PreviewData CopyPreviewData(Interop.Camera.CameraPreviewDataStruct previewStruct, PlaneType type)
1103         {
1104             Log.Info(CameraLog.Tag, "plane type " + type.ToString());
1105             if (type == PlaneType.SinglePlane)
1106             {
1107                 SinglePlaneData singleData = new SinglePlaneData();
1108                 singleData.Format = previewStruct.format;
1109                 singleData.Height = previewStruct.height;
1110                 singleData.TimeStamp = previewStruct.timestamp;
1111                 singleData.Width = previewStruct.width;
1112                 Interop.Camera.SinglePlane singlePlane = previewStruct.frameData.singlePlane;
1113                 singleData.YUVData = new byte[singlePlane.yuvsize];
1114
1115                 if (singlePlane.yuvsize > 0)
1116                     Marshal.Copy(singlePlane.yuv, singleData.YUVData, 0, (int)singlePlane.yuvsize);
1117
1118                 return singleData;
1119             }
1120             else if (type == PlaneType.DoublePlane)
1121             {
1122                 DoublePlaneData doubleData = new DoublePlaneData();
1123                 doubleData.Format = previewStruct.format;
1124                 doubleData.Height = previewStruct.height;
1125                 doubleData.TimeStamp = previewStruct.timestamp;
1126                 doubleData.Width = previewStruct.width;
1127                 Interop.Camera.DoublePlane doublePlane = previewStruct.frameData.doublePlane;
1128                 doubleData.YData = new byte[doublePlane.ysize];
1129                 doubleData.UVData = new byte[doublePlane.uvsize];
1130                 Log.Info(CameraLog.Tag, "ysize " + doublePlane.ysize);
1131                 Log.Info(CameraLog.Tag, "uv size " + doublePlane.uvsize);
1132
1133                 if (doublePlane.ysize > 0)
1134                     Marshal.Copy(doublePlane.y, doubleData.YData, 0, (int)doublePlane.ysize);
1135
1136                 if (doublePlane.uvsize > 0)
1137                     Marshal.Copy(doublePlane.uv, doubleData.UVData, 0, (int)doublePlane.uvsize);
1138
1139                 return doubleData;
1140             }
1141             else if (type == PlaneType.TriplePlane)
1142             {
1143                 TriplePlaneData tripleData = new TriplePlaneData();
1144                 tripleData.Format = previewStruct.format;
1145                 tripleData.Height = previewStruct.height;
1146                 tripleData.TimeStamp = previewStruct.timestamp;
1147                 tripleData.Width = previewStruct.width;
1148                 Interop.Camera.TriplePlane triplePlane = previewStruct.frameData.triplePlane;
1149                 tripleData.YData = new byte[triplePlane.ysize];
1150                 tripleData.UData = new byte[triplePlane.usize];
1151                 tripleData.VData = new byte[triplePlane.vsize];
1152
1153                 if (triplePlane.ysize > 0)
1154                     Marshal.Copy(triplePlane.y, tripleData.YData, 0, (int)triplePlane.ysize);
1155
1156                 if (triplePlane.usize > 0)
1157                     Marshal.Copy(triplePlane.u, tripleData.UData, 0, (int)triplePlane.usize);
1158
1159                 if (triplePlane.vsize > 0)
1160                     Marshal.Copy(triplePlane.v, tripleData.VData, 0, (int)triplePlane.vsize);
1161
1162                 return tripleData;
1163             }
1164             else
1165             {
1166                 EncodedPlaneData encodedData = new EncodedPlaneData();
1167                 encodedData.Format = previewStruct.format;
1168                 encodedData.Height = previewStruct.height;
1169                 encodedData.TimeStamp = previewStruct.timestamp;
1170                 encodedData.Width = previewStruct.width;
1171                 Interop.Camera.EncodedPlane encodedPlane = previewStruct.frameData.encodedPlane;
1172                 encodedData.Data = new byte[encodedPlane.size];
1173
1174                 if (encodedPlane.size > 0)
1175                     Marshal.Copy(encodedPlane.data, encodedData.Data, 0, (int)encodedPlane.size);
1176
1177                 return encodedData;
1178             }
1179         }
1180
1181         private void CreatePreviewCallback()
1182         {
1183             Log.Info(CameraLog.Tag, "Create preview callback.");
1184
1185             _previewCallback = (IntPtr frame, IntPtr userData) =>
1186             {
1187                 Interop.Camera.CameraPreviewDataStruct _previewStruct = Interop.Camera.IntPtrToCameraPreviewDataStruct(frame);
1188                 PlaneType _type = PlaneType.SinglePlane;
1189                 PreviewData _previewData = new PreviewData();
1190
1191                 if (_previewStruct.format == CameraPixelFormat.H264 || _previewStruct.format == CameraPixelFormat.Jpeg)
1192                 {
1193                     _type = PlaneType.EncodedPlane;
1194                     _previewData = CopyPreviewData(_previewStruct, _type);
1195                 }
1196                 else
1197                 {
1198                     Log.Info(CameraLog.Tag, "Number of plane " + _previewStruct.numOfPlanes);
1199                     if (_previewStruct.numOfPlanes == 1)
1200                     {
1201                         _type = PlaneType.SinglePlane;
1202                         _previewData = CopyPreviewData(_previewStruct, _type);
1203                     }
1204                     else if (_previewStruct.numOfPlanes == 2)
1205                     {
1206                         _type = PlaneType.DoublePlane;
1207                         _previewData = CopyPreviewData(_previewStruct, _type);
1208                     }
1209                     else if (_previewStruct.numOfPlanes == 3)
1210                     {
1211                         _type = PlaneType.TriplePlane;
1212                         _previewData = CopyPreviewData(_previewStruct, _type);
1213                     }
1214                 }
1215
1216                 PreviewEventArgs eventArgs = new PreviewEventArgs(_previewData, _type);
1217
1218                 _preview?.Invoke(this, eventArgs);
1219             };
1220
1221             int ret = Interop.Camera.SetPreviewCallback(_handle, _previewCallback, IntPtr.Zero);
1222             if (ret != (int)CameraError.None)
1223             {
1224                 CameraErrorFactory.ThrowException(ret, "Setting preview callback failed");
1225             }
1226         }
1227
1228         private void CreateMediaPacketPreviewCallback()
1229         {
1230             _mediaPacketCallback = (IntPtr mediaPacket, IntPtr userData) =>
1231             {
1232                 MediaPacket packet = MediaPacket.From(mediaPacket);
1233
1234                 MediaPacketPreviewEventArgs eventArgs = new MediaPacketPreviewEventArgs(packet);
1235                 _mediaPacketPreview?.Invoke(this, eventArgs);
1236             };
1237
1238             int ret = Interop.Camera.SetMediaPacketPreviewCallback(_handle, _mediaPacketCallback, IntPtr.Zero);
1239             if (ret != (int)CameraError.None)
1240             {
1241                 CameraErrorFactory.ThrowException(ret, "Setting media packet preview callback failed");
1242             }
1243         }
1244     }
1245 }
1246