scoplan.camera 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/package.json +18 -0
  2. package/plugin.xml +119 -0
  3. package/src/android/AutoFitSurfaceView.java +66 -0
  4. package/src/android/CCropActivity.java +17 -0
  5. package/src/android/CDrawActivity.java +16 -0
  6. package/src/android/CTextActivity.java +17 -0
  7. package/src/android/CameraEventListener.java +8 -0
  8. package/src/android/CameraFragment.java +635 -0
  9. package/src/android/CameraSeekBarListener.java +105 -0
  10. package/src/android/CameraUtils.java +94 -0
  11. package/src/android/CustomI.java +37 -0
  12. package/src/android/FakeR.java +31 -0
  13. package/src/android/ImageCameraAvailableListener.java +65 -0
  14. package/src/android/OnImageCaptureListener.java +11 -0
  15. package/src/android/PhotoEditorActivity.java +128 -0
  16. package/src/android/PhotoEditorMenu.java +111 -0
  17. package/src/android/PhotoEditorMesureCustomActivity.java +218 -0
  18. package/src/android/PhotoEditorStore.java +50 -0
  19. package/src/android/ScoplanCamera.java +98 -0
  20. package/src/android/gradle/scoplanCamera.gradle +9 -0
  21. package/src/android/libs/ds-photo-editor-sdk-v9.aar +0 -0
  22. package/src/android/res/drawable/back_arrow.xml +5 -0
  23. package/src/android/res/drawable/camsicon.png +0 -0
  24. package/src/android/res/drawable/custom_spinner.xml +14 -0
  25. package/src/android/res/drawable/delete_img.png +0 -0
  26. package/src/android/res/drawable/draw_img.png +0 -0
  27. package/src/android/res/drawable/flash.png +0 -0
  28. package/src/android/res/drawable/flash_on.png +0 -0
  29. package/src/android/res/drawable/mesure.png +0 -0
  30. package/src/android/res/drawable/mesure_bar.xml +19 -0
  31. package/src/android/res/drawable/shape_back.xml +12 -0
  32. package/src/android/res/drawable/shape_cancel.xml +12 -0
  33. package/src/android/res/drawable/shape_rectangle.xml +4 -0
  34. package/src/android/res/layout/fragment_camera.xml +157 -0
  35. package/src/android/res/layout/fragment_photo_editor_menu.xml +122 -0
  36. package/src/ios/AVCamPhotoCaptureDelegate.h +20 -0
  37. package/src/ios/AVCamPhotoCaptureDelegate.m +244 -0
  38. package/src/ios/AVCamPreviewView.h +18 -0
  39. package/src/ios/AVCamPreviewView.m +33 -0
  40. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDK +0 -0
  41. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Assets.car +0 -0
  42. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/0dZ-3o-Xdu-view-Uan-aZ-nTR.nib/objects-11.0+.nib +0 -0
  43. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/0dZ-3o-Xdu-view-Uan-aZ-nTR.nib/objects-13.0+.nib +0 -0
  44. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/0dZ-3o-Xdu-view-Uan-aZ-nTR.nib/runtime.nib +0 -0
  45. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/DSDrawViewController.nib/objects-11.0+.nib +0 -0
  46. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/DSDrawViewController.nib/objects-13.0+.nib +0 -0
  47. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/DSDrawViewController.nib/runtime.nib +0 -0
  48. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/DSPhotoEditor.nib/objects-11.0+.nib +0 -0
  49. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/DSPhotoEditor.nib/objects-13.0+.nib +0 -0
  50. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/DSPhotoEditor.nib/runtime.nib +0 -0
  51. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/Info.plist +0 -0
  52. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/Okc-Jl-tk5-view-siV-MN-Zgc.nib/objects-11.0+.nib +0 -0
  53. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/Okc-Jl-tk5-view-siV-MN-Zgc.nib/objects-13.0+.nib +0 -0
  54. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDK.storyboardc/Okc-Jl-tk5-view-siV-MN-Zgc.nib/runtime.nib +0 -0
  55. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Base.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  56. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/Info.plist +0 -0
  57. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/ar.lproj/DSPhotoEditorSDK.strings +57 -0
  58. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/ar.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  59. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/de.lproj/DSPhotoEditorSDK.strings +57 -0
  60. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/de.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  61. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/es.lproj/DSPhotoEditorSDK.strings +57 -0
  62. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/es.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  63. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/fr.lproj/DSPhotoEditorSDK.strings +57 -0
  64. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/fr.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  65. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/id.lproj/DSPhotoEditorSDK.strings +57 -0
  66. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/id.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  67. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/it.lproj/DSPhotoEditorSDK.strings +57 -0
  68. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/it.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  69. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/ja.lproj/DSPhotoEditorSDK.strings +57 -0
  70. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/ja.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  71. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/ko.lproj/DSPhotoEditorSDK.strings +57 -0
  72. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/ko.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  73. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/ms.lproj/DSPhotoEditorSDK.strings +57 -0
  74. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/ms.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  75. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/pt-PT.lproj/DSPhotoEditorSDK.strings +57 -0
  76. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/pt-PT.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  77. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/ru.lproj/DSPhotoEditorSDK.strings +57 -0
  78. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/ru.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  79. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/th.lproj/DSPhotoEditorSDK.strings +57 -0
  80. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/th.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  81. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/tr.lproj/DSPhotoEditorSDK.strings +57 -0
  82. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/tr.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  83. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/vi.lproj/DSPhotoEditorSDK.strings +57 -0
  84. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/vi.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  85. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/zh-Hans.lproj/DSPhotoEditorSDK.strings +57 -0
  86. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/zh-Hans.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  87. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/zh-Hant.lproj/DSPhotoEditorSDK.strings +57 -0
  88. package/src/ios/DSPhotoEditorSDK.framework/DSPhotoEditorSDKResourceBundle.bundle/zh-Hant.lproj/DSPhotoEditorSDKLocalizable.strings +0 -0
  89. package/src/ios/DSPhotoEditorSDK.framework/Headers/DSPhotoEditorSDK.h +18 -0
  90. package/src/ios/DSPhotoEditorSDK.framework/Headers/DSPhotoEditorViewController.h +112 -0
  91. package/src/ios/DSPhotoEditorSDK.framework/Info.plist +0 -0
  92. package/src/ios/DSPhotoEditorSDK.framework/License.md +70 -0
  93. package/src/ios/DSPhotoEditorSDK.framework/Modules/module.modulemap +6 -0
  94. package/src/ios/DSPhotoEditorSDK.framework/framework_version.txt +5 -0
  95. package/src/ios/DSPhotoEditorSDK.framework/strip-frameworks.sh +80 -0
  96. package/src/ios/Resources/Overlay.png +0 -0
  97. package/src/ios/Resources/Overlay@2x.png +0 -0
  98. package/src/ios/Resources/back_arrows.png +0 -0
  99. package/src/ios/Resources/ds_btn_calc.png +0 -0
  100. package/src/ios/Resources/ds_btn_crop.png +0 -0
  101. package/src/ios/Resources/ds_btn_del.png +0 -0
  102. package/src/ios/Resources/ds_btn_draw.png +0 -0
  103. package/src/ios/Resources/ds_btn_text.png +0 -0
  104. package/src/ios/Resources/measure_0.png +0 -0
  105. package/src/ios/Resources/measure_1.png +0 -0
  106. package/src/ios/Resources/measure_10.png +0 -0
  107. package/src/ios/Resources/measure_11.png +0 -0
  108. package/src/ios/Resources/measure_2.png +0 -0
  109. package/src/ios/Resources/measure_3.png +0 -0
  110. package/src/ios/Resources/measure_4.png +0 -0
  111. package/src/ios/Resources/measure_5.png +0 -0
  112. package/src/ios/Resources/measure_6.png +0 -0
  113. package/src/ios/Resources/measure_7.png +0 -0
  114. package/src/ios/Resources/measure_8.png +0 -0
  115. package/src/ios/Resources/measure_9.png +0 -0
  116. package/src/ios/Resources/no.png +0 -0
  117. package/src/ios/Resources/ok.png +0 -0
  118. package/src/ios/Resources/toward_arrows.png +0 -0
  119. package/src/ios/ScoplanCamera.h +18 -0
  120. package/src/ios/ScoplanCamera.m +179 -0
  121. package/src/ios/ScoplanCamera.storyboard +115 -0
  122. package/src/ios/UICustomPickerController.h +11 -0
  123. package/src/ios/UICustomPickerController.m +119 -0
  124. package/src/ios/UIImagePickerDelegate.h +11 -0
  125. package/src/ios/UIImagePickerDelegate.m +161 -0
  126. package/src/ios/UIScoplanCamera.h +20 -0
  127. package/src/ios/UIScoplanCamera.m +1098 -0
  128. package/src/ios/bottomPhotoEditor.xib +222 -0
  129. package/src/ios/camsicons.xcassets/Contents.json +6 -0
  130. package/src/ios/camsicons.xcassets/cameraicon.imageset/Contents.json +21 -0
  131. package/src/ios/camsicons.xcassets/cameraicon.imageset/camsicon.png +0 -0
  132. package/src/ios/camsicons.xcassets/image000001.imageset/Contents.json +21 -0
  133. package/src/ios/camsicons.xcassets/image000001.imageset/image0000002.png +0 -0
  134. package/src/ios/camsicons.xcassets/image0000010.imageset/Contents.json +21 -0
  135. package/src/ios/camsicons.xcassets/image0000010.imageset/image0000010.png +0 -0
  136. package/src/ios/camsicons.xcassets/image0000011.imageset/Contents.json +21 -0
  137. package/src/ios/camsicons.xcassets/image0000011.imageset/image0000011.png +0 -0
  138. package/src/ios/camsicons.xcassets/image0000012.imageset/Contents.json +21 -0
  139. package/src/ios/camsicons.xcassets/image0000012.imageset/image0000012.png +0 -0
  140. package/src/ios/camsicons.xcassets/image0000013.imageset/Contents.json +21 -0
  141. package/src/ios/camsicons.xcassets/image0000013.imageset/image0000013.png +0 -0
  142. package/src/ios/camsicons.xcassets/image0000014.imageset/Contents.json +21 -0
  143. package/src/ios/camsicons.xcassets/image0000014.imageset/image0000014.png +0 -0
  144. package/src/ios/camsicons.xcassets/image0000015.imageset/Contents.json +21 -0
  145. package/src/ios/camsicons.xcassets/image0000015.imageset/image0000015.png +0 -0
  146. package/src/ios/camsicons.xcassets/image0000016.imageset/Contents.json +21 -0
  147. package/src/ios/camsicons.xcassets/image0000016.imageset/image0000016.png +0 -0
  148. package/src/ios/camsicons.xcassets/image0000017.imageset/Contents.json +21 -0
  149. package/src/ios/camsicons.xcassets/image0000017.imageset/image0000017.png +0 -0
  150. package/src/ios/camsicons.xcassets/image0000018.imageset/Contents.json +21 -0
  151. package/src/ios/camsicons.xcassets/image0000018.imageset/image0000018.png +0 -0
  152. package/src/ios/camsicons.xcassets/image0000019.imageset/Contents.json +21 -0
  153. package/src/ios/camsicons.xcassets/image0000019.imageset/image0000019.png +0 -0
  154. package/src/ios/camsicons.xcassets/image000002.imageset/Contents.json +21 -0
  155. package/src/ios/camsicons.xcassets/image000002.imageset/image0000001.png +0 -0
  156. package/src/ios/camsicons.xcassets/image000003.imageset/Contents.json +21 -0
  157. package/src/ios/camsicons.xcassets/image000003.imageset/image0000003.png +0 -0
  158. package/src/ios/camsicons.xcassets/image000004.imageset/Contents.json +21 -0
  159. package/src/ios/camsicons.xcassets/image000004.imageset/image0000004.png +0 -0
  160. package/src/ios/camsicons.xcassets/image000005.imageset/Contents.json +21 -0
  161. package/src/ios/camsicons.xcassets/image000005.imageset/image0000005.png +0 -0
  162. package/src/ios/camsicons.xcassets/image000006.imageset/Contents.json +21 -0
  163. package/src/ios/camsicons.xcassets/image000006.imageset/image0000006.png +0 -0
  164. package/src/ios/camsicons.xcassets/image000007.imageset/Contents.json +21 -0
  165. package/src/ios/camsicons.xcassets/image000007.imageset/image0000007.png +0 -0
  166. package/src/ios/camsicons.xcassets/image000008.imageset/Contents.json +21 -0
  167. package/src/ios/camsicons.xcassets/image000008.imageset/image0000008.png +0 -0
  168. package/src/ios/camsicons.xcassets/image000009.imageset/Contents.json +21 -0
  169. package/src/ios/camsicons.xcassets/image000009.imageset/image0000009.png +0 -0
  170. package/src/ios/multicam.xib +113 -0
  171. package/www/ScoplanCamera.js +5 -0
@@ -0,0 +1,1098 @@
1
+ //
2
+ // UIScoplanCamera.m
3
+ // My happy client
4
+ //
5
+ // Created by Adriela on 30/04/2018.
6
+ //
7
+ @import Photos;
8
+
9
+ #import <Foundation/Foundation.h>
10
+ #import "UIScoplanCamera.h"
11
+ #import "ScoplanCamera.h"
12
+ #import "AVCamPhotoCaptureDelegate.h"
13
+ #import "AVCamPreviewView.h"
14
+ #import <CoreMotion/CoreMotion.h>
15
+
16
+ static void * SessionRunningContext = &SessionRunningContext;
17
+ static AVCaptureVideoOrientation curOr;
18
+
19
+ typedef NS_ENUM( NSInteger, AVCamSetupResult ) {
20
+ AVCamSetupResultSuccess,
21
+ AVCamSetupResultCameraNotAuthorized,
22
+ AVCamSetupResultSessionConfigurationFailed
23
+ };
24
+
25
+ typedef NS_ENUM( NSInteger, AVCamCaptureMode ) {
26
+ AVCamCaptureModePhoto = 0,
27
+ AVCamCaptureModeMovie = 1
28
+ };
29
+
30
+ typedef NS_ENUM( NSInteger, AVCamLivePhotoMode ) {
31
+ AVCamLivePhotoModeOn,
32
+ AVCamLivePhotoModeOff
33
+ };
34
+
35
+ typedef NS_ENUM( NSInteger, AVCamDepthDataDeliveryMode ) {
36
+ AVCamDepthDataDeliveryModeOn,
37
+ AVCamDepthDataDeliveryModeOff
38
+ };
39
+
40
+ @interface AVCaptureDeviceDiscoverySession (Utilities)
41
+
42
+ - (NSInteger)uniqueDevicePositionsCount;
43
+
44
+ @end
45
+
46
+ @implementation AVCaptureDeviceDiscoverySession (Utilities)
47
+
48
+ - (NSInteger)uniqueDevicePositionsCount
49
+ {
50
+ NSMutableArray<NSNumber *> *uniqueDevicePositions = [NSMutableArray array];
51
+
52
+ for ( AVCaptureDevice *device in self.devices ) {
53
+ if ( ! [uniqueDevicePositions containsObject:@(device.position)] ) {
54
+ [uniqueDevicePositions addObject:@(device.position)];
55
+ }
56
+ }
57
+
58
+ return uniqueDevicePositions.count;
59
+ }
60
+
61
+ @end
62
+
63
+ @interface UIScoplanCamera () <AVCaptureFileOutputRecordingDelegate>
64
+ @property (strong, nonatomic) IBOutlet UIView *rootView;
65
+ @property (strong, nonatomic) IBOutlet UIImageView *imageview;
66
+ @property (strong, nonatomic) IBOutlet UIButton *okbutton;
67
+ @property (strong, nonatomic) IBOutlet UIView *blackbottom;
68
+ @property (strong, nonatomic) IBOutlet UIImageView *progress;
69
+
70
+ // Session management.
71
+ @property (nonatomic, weak) IBOutlet AVCamPreviewView *previewView;
72
+ @property (nonatomic, weak) IBOutlet UISegmentedControl *captureModeControl;
73
+
74
+ @property (nonatomic) AVCamSetupResult setupResult;
75
+ @property (nonatomic) dispatch_queue_t sessionQueue;
76
+ @property (nonatomic) AVCaptureSession *session;
77
+ @property (nonatomic, getter=isSessionRunning) BOOL sessionRunning;
78
+ @property (nonatomic) AVCaptureDeviceInput *videoDeviceInput;
79
+
80
+ // Device configuration.
81
+ @property (nonatomic, weak) IBOutlet UIButton *cameraButton;
82
+ //@property (nonatomic, weak) IBOutlet UILabel *cameraUnavailableLabel;
83
+ @property (nonatomic) AVCaptureDeviceDiscoverySession *videoDeviceDiscoverySession;
84
+
85
+ // Capturing photos.
86
+ @property (nonatomic, weak) IBOutlet UIButton *photoButton;
87
+ //@property (nonatomic, weak) IBOutlet UIButton *livePhotoModeButton;
88
+ @property (nonatomic) AVCamLivePhotoMode livePhotoMode;
89
+ //@property (nonatomic, weak) IBOutlet UILabel *capturingLivePhotoLabel;
90
+ //@property (nonatomic, weak) IBOutlet UIButton *depthDataDeliveryButton;
91
+ @property (nonatomic) AVCamDepthDataDeliveryMode depthDataDeliveryMode;
92
+
93
+ @property (nonatomic) AVCapturePhotoOutput *photoOutput;
94
+ @property (nonatomic) NSMutableDictionary<NSNumber *, AVCamPhotoCaptureDelegate *> *inProgressPhotoCaptureDelegates;
95
+ @property (nonatomic) NSInteger inProgressLivePhotoCapturesCount;
96
+
97
+ // Recording movies.
98
+ //@property (nonatomic, weak) IBOutlet UIButton *recordButton;
99
+ //@property (nonatomic, weak) IBOutlet UIButton *resumeButton;
100
+
101
+ @property (nonatomic, strong) AVCaptureMovieFileOutput *movieFileOutput;
102
+ @property (nonatomic) UIBackgroundTaskIdentifier backgroundRecordingID;
103
+
104
+ @end
105
+
106
+ @implementation UIScoplanCamera
107
+
108
+ #pragma mark View Controller Life Cycle
109
+
110
+ - (void) setMCam:(ScoplanCamera *)mCam{
111
+ mCamera = mCam;
112
+ }
113
+
114
+ - (void)insertImgUrl:(NSString*)url{
115
+ dispatch_async(dispatch_get_main_queue(), ^{
116
+ [_okbutton setTitle: @"OK" forState: UIControlStateNormal];
117
+ [_photoButton setHidden:FALSE];
118
+ [_progress stopAnimating];
119
+ [_progress setHidden:TRUE];
120
+ });
121
+ [mCamera insertPicture:url];
122
+ }
123
+
124
+ - (NSInteger)getOrientation{
125
+ return curOr;
126
+ }
127
+
128
+ - (void)viewDidLoad
129
+ {
130
+ [super viewDidLoad];
131
+
132
+ // Disable UI. The UI is enabled if and only if the session starts running.
133
+ // self.cameraButton.enabled = NO;
134
+ // self.recordButton.enabled = NO;
135
+ self.photoButton.enabled = NO;
136
+ NSMutableArray * framesLoader = [[NSMutableArray alloc] initWithCapacity:18];
137
+ for (int i = 1; i < 20; i++) {
138
+ NSString * imageName = [NSString stringWithFormat:@"image00000%d.png",i];
139
+ UIImage * img = [UIImage imageNamed:imageName];
140
+ [framesLoader addObject:img];
141
+ }
142
+ self.progress.animationImages = framesLoader;
143
+ self.progress.animationDuration = 1.0f;
144
+ self.progress.animationRepeatCount = 0;
145
+ //self.livePhotoModeButton.enabled = NO;
146
+ self.captureModeControl.enabled = YES;
147
+ //self.depthDataDeliveryButton.enabled = NO;
148
+
149
+ // Create the AVCaptureSession.
150
+ self.session = [[AVCaptureSession alloc] init];
151
+
152
+ // Create a device discovery session.
153
+ NSArray<AVCaptureDeviceType> *deviceTypes = @[AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeBuiltInDualCamera];
154
+ self.videoDeviceDiscoverySession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
155
+ /*
156
+ Remove the AVCaptureMovieFileOutput from the session because movie recording is
157
+ not supported with AVCaptureSessionPresetPhoto. Additionally, Live Photo
158
+ capture is not supported when an AVCaptureMovieFileOutput is connected to the session.
159
+ */
160
+
161
+ // Set up the preview view.
162
+ self.previewView.session = self.session;
163
+
164
+ // Communicate with the session and other session objects on this queue.
165
+ self.sessionQueue = dispatch_queue_create( "session queue", DISPATCH_QUEUE_SERIAL );
166
+
167
+ self.setupResult = AVCamSetupResultSuccess;
168
+
169
+ [self.session beginConfiguration];
170
+ [self.session removeOutput:self.movieFileOutput];
171
+ if([self.session canSetSessionPreset:AVCaptureSessionPresetPhoto]){
172
+ self.session.sessionPreset = AVCaptureSessionPresetPhoto;
173
+ }
174
+
175
+ self.movieFileOutput = nil;
176
+
177
+ if ( self.photoOutput.livePhotoCaptureSupported ) {
178
+ self.photoOutput.livePhotoCaptureEnabled = YES;
179
+
180
+ dispatch_async( dispatch_get_main_queue(), ^{
181
+ //self.livePhotoModeButton.enabled = YES;
182
+ //self.livePhotoModeButton.hidden = NO;
183
+ } );
184
+ }
185
+
186
+ if ( self.photoOutput.depthDataDeliverySupported ) {
187
+ self.photoOutput.depthDataDeliveryEnabled = YES;
188
+
189
+ dispatch_async( dispatch_get_main_queue(), ^{
190
+ //self.depthDataDeliveryButton.hidden = NO;
191
+ //self.depthDataDeliveryButton.enabled = YES;
192
+ } );
193
+ }
194
+
195
+ //[testButn addTarget:self action:@selector(staypressed:) forControlEvents:UIControlEventTouchUpInside];
196
+ UIPinchGestureRecognizer* pinchGst = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchForZoom:)];
197
+ [self.previewView addGestureRecognizer:pinchGst];
198
+ [self.session commitConfiguration];
199
+
200
+ /*
201
+ Setup the capture session.
202
+ In general it is not safe to mutate an AVCaptureSession or any of its
203
+ inputs, outputs, or connections from multiple threads at the same time.
204
+
205
+ Why not do all of this on the main queue?
206
+ Because -[AVCaptureSession startRunning] is a blocking call which can
207
+ take a long time. We dispatch session setup to the sessionQueue so
208
+ that the main queue isn't blocked, which keeps the UI responsive.
209
+ */
210
+ dispatch_async( self.sessionQueue, ^{
211
+ [self configureSession];
212
+ } );
213
+
214
+ }
215
+
216
+ - (void)pinchForZoom:(UIPinchGestureRecognizer *)pinchRecognizer{
217
+ static CGFloat zoomFactorBegin = .0;
218
+ if ( UIGestureRecognizerStateBegan == pinchRecognizer.state ) {
219
+ zoomFactorBegin = self.videoDeviceInput.device.videoZoomFactor;
220
+
221
+ } else if (UIGestureRecognizerStateChanged == pinchRecognizer.state) {
222
+ NSError *error = nil;
223
+ if ([self.videoDeviceInput.device lockForConfiguration:&error]) {
224
+
225
+ CGFloat desiredZoomFactor = zoomFactorBegin * pinchRecognizer.scale;
226
+ CGFloat zoomFactor = MAX(1.0, MIN(desiredZoomFactor, self.videoDeviceInput.device.activeFormat.videoMaxZoomFactor));
227
+ [self.videoDeviceInput.device rampToVideoZoomFactor:zoomFactor withRate:3.0];
228
+
229
+ [self.videoDeviceInput.device unlockForConfiguration];
230
+ } else {
231
+ NSLog(@"error: %@", error);
232
+ }
233
+ }
234
+ }
235
+
236
+
237
+ - (void)viewWillAppear:(BOOL)animated
238
+ {
239
+ [super viewWillAppear:animated];
240
+ cm = [[CMMotionManager alloc] init];
241
+ cm.deviceMotionUpdateInterval=0.5f;
242
+ if([cm isDeviceMotionAvailable])
243
+ [cm startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]
244
+ withHandler:^(CMDeviceMotion *data, NSError *error) {
245
+ if(fabs(data.gravity.x)>fabs(data.gravity.y)){
246
+ //NSLog(@"LANSCAPE");
247
+ if(data.gravity.x>=0){
248
+ //NSLog(@"LEFT");
249
+ curOr = AVCaptureVideoOrientationLandscapeLeft;
250
+ }
251
+ else{
252
+ //NSLog(@"RIGHT");
253
+ curOr = AVCaptureVideoOrientationLandscapeRight;
254
+ }
255
+
256
+ }
257
+ else{
258
+ //NSLog(@"PORTRAIT");
259
+ if(data.gravity.y>=0){
260
+ //NSLog(@"DOWN");
261
+ curOr = AVCaptureVideoOrientationPortraitUpsideDown;
262
+ }
263
+ else{
264
+ //NSLog(@"UP");
265
+ curOr = AVCaptureVideoOrientationPortrait;
266
+ }
267
+
268
+ }
269
+
270
+ }];
271
+ AVCaptureVideoPreviewLayer *previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
272
+ previewLayer.frame = _rootView.bounds;
273
+ previewLayer.videoGravity = AVLayerVideoGravityResizeAspect;
274
+ [_rootView.layer addSublayer:previewLayer];
275
+ _blackbottom.layer.zPosition = 1;
276
+ _photoButton.imageView.layer.zPosition = 1;
277
+ _photoButton.layer.zPosition = 1;
278
+ _imageview.layer.zPosition = 1;
279
+ _okbutton.layer.zPosition = 1;
280
+ _progress.layer.zPosition = 1;
281
+ [_progress setHidden:TRUE];
282
+ dispatch_async( self.sessionQueue, ^{
283
+ switch ( self.setupResult )
284
+ {
285
+ case AVCamSetupResultSuccess:
286
+ {
287
+ // Only setup observers and start the session running if setup succeeded.
288
+ [self addObservers];
289
+ [self.session startRunning];
290
+ self.sessionRunning = self.session.isRunning;
291
+ break;
292
+ }
293
+ case AVCamSetupResultCameraNotAuthorized:
294
+ {
295
+ dispatch_async( dispatch_get_main_queue(), ^{
296
+ NSString *message = NSLocalizedString( @"AVCam doesn't have permission to use the camera, please change privacy settings", @"Alert message when the user has denied access to the camera" );
297
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"AVCam" message:message preferredStyle:UIAlertControllerStyleAlert];
298
+ UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"OK", @"Alert OK button" ) style:UIAlertActionStyleCancel handler:nil];
299
+ [alertController addAction:cancelAction];
300
+ // Provide quick access to Settings.
301
+ UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"Settings", @"Alert button to open Settings" ) style:UIAlertActionStyleDefault handler:^( UIAlertAction *action ) {
302
+ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
303
+ }];
304
+ [alertController addAction:settingsAction];
305
+ [self presentViewController:alertController animated:YES completion:nil];
306
+ } );
307
+ break;
308
+ }
309
+ case AVCamSetupResultSessionConfigurationFailed:
310
+ {
311
+ dispatch_async( dispatch_get_main_queue(), ^{
312
+ NSString *message = NSLocalizedString( @"Unable to capture media", @"Alert message when something goes wrong during capture session configuration" );
313
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"AVCam" message:message preferredStyle:UIAlertControllerStyleAlert];
314
+ UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"OK", @"Alert OK button" ) style:UIAlertActionStyleCancel handler:nil];
315
+ [alertController addAction:cancelAction];
316
+ [self presentViewController:alertController animated:YES completion:nil];
317
+ } );
318
+ break;
319
+ }
320
+ }
321
+ } );
322
+ }
323
+
324
+ - (void) setPhotodata:(AVCamPhotoCaptureDelegate*)photoCaptureDelegate{
325
+ UIImage *imgdata = [[UIImage alloc]initWithData:[photoCaptureDelegate getPhotodata]];
326
+ }
327
+
328
+ - (void)viewDidDisappear:(BOOL)animated
329
+ {
330
+ dispatch_async( self.sessionQueue, ^{
331
+ if ( self.setupResult == AVCamSetupResultSuccess ) {
332
+ [self.session stopRunning];
333
+ [self removeObservers];
334
+ }
335
+ } );
336
+
337
+ [super viewDidDisappear:animated];
338
+ }
339
+
340
+ - (BOOL)shouldAutorotate
341
+ {
342
+ // Disable autorotation of the interface when recording is in progress.
343
+ return ! self.movieFileOutput.isRecording;
344
+ }
345
+
346
+ - (UIInterfaceOrientationMask)supportedInterfaceOrientations
347
+ {
348
+ return UIInterfaceOrientationMaskPortrait;
349
+ }
350
+
351
+ - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
352
+ {
353
+ [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
354
+
355
+ UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
356
+
357
+ if ( UIDeviceOrientationIsPortrait( deviceOrientation ) || UIDeviceOrientationIsLandscape( deviceOrientation ) ) {
358
+ self.previewView.videoPreviewLayer.connection.videoOrientation = (AVCaptureVideoOrientation)deviceOrientation;
359
+ }
360
+ }
361
+
362
+ #pragma mark Session Management
363
+
364
+ // Call this on the session queue.
365
+ - (void)configureSession
366
+ {
367
+ if ( self.setupResult != AVCamSetupResultSuccess ) {
368
+ return;
369
+ }
370
+
371
+ NSError *error = nil;
372
+
373
+ [self.session beginConfiguration];
374
+
375
+ /*
376
+ We do not create an AVCaptureMovieFileOutput when setting up the session because the
377
+ AVCaptureMovieFileOutput does not support movie recording with AVCaptureSessionPresetPhoto.
378
+ */
379
+ self.session.sessionPreset = AVCaptureSessionPresetPhoto;
380
+
381
+ // Add video input.
382
+
383
+ // Choose the back dual camera if available, otherwise default to a wide angle camera.
384
+ AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInDualCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionBack];
385
+ if ( ! videoDevice ) {
386
+ // If the back dual camera is not available, default to the back wide angle camera.
387
+ videoDevice = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionBack];
388
+
389
+ // In some cases where users break their phones, the back wide angle camera is not available. In this case, we should default to the front wide angle camera.
390
+ if ( ! videoDevice ) {
391
+ videoDevice = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionFront];
392
+ }
393
+ }
394
+ AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
395
+ if ( ! videoDeviceInput ) {
396
+ NSLog( @"Could not create video device input: %@", error );
397
+ self.setupResult = AVCamSetupResultSessionConfigurationFailed;
398
+ [self.session commitConfiguration];
399
+ return;
400
+ }
401
+ if ( [self.session canAddInput:videoDeviceInput] ) {
402
+ [self.session addInput:videoDeviceInput];
403
+ self.videoDeviceInput = videoDeviceInput;
404
+
405
+ dispatch_async( dispatch_get_main_queue(), ^{
406
+ /*
407
+ Why are we dispatching this to the main queue?
408
+ Because AVCaptureVideoPreviewLayer is the backing layer for AVCamPreviewView and UIView
409
+ can only be manipulated on the main thread.
410
+ Note: As an exception to the above rule, it is not necessary to serialize video orientation changes
411
+ on the AVCaptureVideoPreviewLayer’s connection with other session manipulation.
412
+
413
+ Use the status bar orientation as the initial video orientation. Subsequent orientation changes are
414
+ handled by -[AVCamCameraViewController viewWillTransitionToSize:withTransitionCoordinator:].
415
+ */
416
+ UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
417
+ AVCaptureVideoOrientation initialVideoOrientation = AVCaptureVideoOrientationPortrait;
418
+ if ( statusBarOrientation != UIInterfaceOrientationUnknown ) {
419
+ initialVideoOrientation = (AVCaptureVideoOrientation)statusBarOrientation;
420
+ }
421
+
422
+ self.previewView.videoPreviewLayer.connection.videoOrientation = initialVideoOrientation;
423
+ } );
424
+ }
425
+ else {
426
+ NSLog( @"Could not add video device input to the session" );
427
+ self.setupResult = AVCamSetupResultSessionConfigurationFailed;
428
+ [self.session commitConfiguration];
429
+ return;
430
+ }
431
+
432
+ // Add photo output.
433
+ AVCapturePhotoOutput *photoOutput = [[AVCapturePhotoOutput alloc] init];
434
+ if ( [self.session canAddOutput:photoOutput] ) {
435
+ [self.session addOutput:photoOutput];
436
+ self.photoOutput = photoOutput;
437
+
438
+ self.photoOutput.highResolutionCaptureEnabled = YES;
439
+ self.photoOutput.livePhotoCaptureEnabled = self.photoOutput.livePhotoCaptureSupported;
440
+ self.photoOutput.depthDataDeliveryEnabled = self.photoOutput.depthDataDeliverySupported;
441
+
442
+ self.livePhotoMode = self.photoOutput.livePhotoCaptureSupported ? AVCamLivePhotoModeOn : AVCamLivePhotoModeOff;
443
+ self.depthDataDeliveryMode = self.photoOutput.depthDataDeliverySupported ? AVCamDepthDataDeliveryModeOn : AVCamDepthDataDeliveryModeOff;
444
+
445
+
446
+ self.inProgressPhotoCaptureDelegates = [NSMutableDictionary dictionary];
447
+ self.inProgressLivePhotoCapturesCount = 0;
448
+ }
449
+ else {
450
+ NSLog( @"Could not add photo output to the session" );
451
+ self.setupResult = AVCamSetupResultSessionConfigurationFailed;
452
+ [self.session commitConfiguration];
453
+ return;
454
+ }
455
+
456
+ self.backgroundRecordingID = UIBackgroundTaskInvalid;
457
+
458
+ [self.session commitConfiguration];
459
+ }
460
+
461
+ - (IBAction)resumeInterruptedSession:(id)sender
462
+ {
463
+ dispatch_async( self.sessionQueue, ^{
464
+ /*
465
+ The session might fail to start running, e.g., if a phone or FaceTime call is still
466
+ using audio or video. A failure to start the session running will be communicated via
467
+ a session runtime error notification. To avoid repeatedly failing to start the session
468
+ running, we only try to restart the session running in the session runtime error handler
469
+ if we aren't trying to resume the session running.
470
+ */
471
+ [self.session startRunning];
472
+ self.sessionRunning = self.session.isRunning;
473
+ if ( ! self.session.isRunning ) {
474
+ dispatch_async( dispatch_get_main_queue(), ^{
475
+ NSString *message = NSLocalizedString( @"Unable to resume", @"Alert message when unable to resume the session running" );
476
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"AVCam" message:message preferredStyle:UIAlertControllerStyleAlert];
477
+ UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"OK", @"Alert OK button" ) style:UIAlertActionStyleCancel handler:nil];
478
+ [alertController addAction:cancelAction];
479
+ [self presentViewController:alertController animated:YES completion:nil];
480
+ } );
481
+ }
482
+ else {
483
+ dispatch_async( dispatch_get_main_queue(), ^{
484
+ //self.resumeButton.hidden = YES;
485
+ } );
486
+ }
487
+ } );
488
+ }
489
+
490
+ - (IBAction)toggleCaptureMode:(UISegmentedControl *)captureModeControl
491
+ {
492
+ if ( captureModeControl.selectedSegmentIndex == AVCamCaptureModePhoto ) {
493
+ //self.recordButton.enabled = NO;
494
+
495
+ dispatch_async( self.sessionQueue, ^{
496
+ /*
497
+ Remove the AVCaptureMovieFileOutput from the session because movie recording is
498
+ not supported with AVCaptureSessionPresetPhoto. Additionally, Live Photo
499
+ capture is not supported when an AVCaptureMovieFileOutput is connected to the session.
500
+ */
501
+ [self.session beginConfiguration];
502
+ [self.session removeOutput:self.movieFileOutput];
503
+ self.session.sessionPreset = AVCaptureSessionPresetPhoto;
504
+
505
+ self.movieFileOutput = nil;
506
+
507
+ if ( self.photoOutput.livePhotoCaptureSupported ) {
508
+ self.photoOutput.livePhotoCaptureEnabled = YES;
509
+
510
+ dispatch_async( dispatch_get_main_queue(), ^{
511
+ //self.livePhotoModeButton.enabled = YES;
512
+ //self.livePhotoModeButton.hidden = NO;
513
+ } );
514
+ }
515
+
516
+ if ( self.photoOutput.depthDataDeliverySupported ) {
517
+ self.photoOutput.depthDataDeliveryEnabled = YES;
518
+
519
+ dispatch_async( dispatch_get_main_queue(), ^{
520
+ //self.depthDataDeliveryButton.hidden = NO;
521
+ //self.depthDataDeliveryButton.enabled = YES;
522
+ } );
523
+ }
524
+
525
+ [self.session commitConfiguration];
526
+ } );
527
+ }
528
+ else if ( captureModeControl.selectedSegmentIndex == AVCamCaptureModeMovie ) {
529
+ //self.livePhotoModeButton.hidden = YES;
530
+ //self.depthDataDeliveryButton.hidden = YES;
531
+
532
+ dispatch_async( self.sessionQueue, ^{
533
+ AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
534
+
535
+ if ( [self.session canAddOutput:movieFileOutput] )
536
+ {
537
+ [self.session beginConfiguration];
538
+ [self.session addOutput:movieFileOutput];
539
+ self.session.sessionPreset = AVCaptureSessionPresetHigh;
540
+ AVCaptureConnection *connection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
541
+ if ( connection.isVideoStabilizationSupported ) {
542
+ connection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
543
+ }
544
+ [self.session commitConfiguration];
545
+
546
+ self.movieFileOutput = movieFileOutput;
547
+
548
+ dispatch_async( dispatch_get_main_queue(), ^{
549
+ //self.recordButton.enabled = YES;
550
+ } );
551
+ }
552
+ } );
553
+ }
554
+ }
555
+
556
+ #pragma mark Device Configuration
557
+
558
+ - (IBAction)changeCamera:(id)sender
559
+ {
560
+ self.cameraButton.enabled = NO;
561
+ //self.recordButton.enabled = NO;
562
+ self.photoButton.enabled = NO;
563
+ //self.livePhotoModeButton.enabled = NO;
564
+ self.captureModeControl.enabled = NO;
565
+
566
+ dispatch_async( self.sessionQueue, ^{
567
+ AVCaptureDevice *currentVideoDevice = self.videoDeviceInput.device;
568
+ AVCaptureDevicePosition currentPosition = currentVideoDevice.position;
569
+
570
+ AVCaptureDevicePosition preferredPosition;
571
+ AVCaptureDeviceType preferredDeviceType;
572
+
573
+ switch ( currentPosition )
574
+ {
575
+ case AVCaptureDevicePositionUnspecified:
576
+ case AVCaptureDevicePositionFront:
577
+ preferredPosition = AVCaptureDevicePositionBack;
578
+ preferredDeviceType = AVCaptureDeviceTypeBuiltInDualCamera;
579
+ break;
580
+ case AVCaptureDevicePositionBack:
581
+ preferredPosition = AVCaptureDevicePositionFront;
582
+ preferredDeviceType = AVCaptureDeviceTypeBuiltInWideAngleCamera;
583
+ break;
584
+ }
585
+
586
+ NSArray<AVCaptureDevice *> *devices = self.videoDeviceDiscoverySession.devices;
587
+ AVCaptureDevice *newVideoDevice = nil;
588
+
589
+ // First, look for a device with both the preferred position and device type.
590
+ for ( AVCaptureDevice *device in devices ) {
591
+ if ( device.position == preferredPosition && [device.deviceType isEqualToString:preferredDeviceType] ) {
592
+ newVideoDevice = device;
593
+ break;
594
+ }
595
+ }
596
+
597
+ // Otherwise, look for a device with only the preferred position.
598
+ if ( ! newVideoDevice ) {
599
+ for ( AVCaptureDevice *device in devices ) {
600
+ if ( device.position == preferredPosition ) {
601
+ newVideoDevice = device;
602
+ break;
603
+ }
604
+ }
605
+ }
606
+
607
+ if ( newVideoDevice ) {
608
+ AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:newVideoDevice error:NULL];
609
+
610
+ [self.session beginConfiguration];
611
+
612
+ // Remove the existing device input first, since using the front and back camera simultaneously is not supported.
613
+ [self.session removeInput:self.videoDeviceInput];
614
+
615
+ if ( [self.session canAddInput:videoDeviceInput] ) {
616
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:currentVideoDevice];
617
+
618
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:newVideoDevice];
619
+
620
+ [self.session addInput:videoDeviceInput];
621
+ self.videoDeviceInput = videoDeviceInput;
622
+ }
623
+ else {
624
+ [self.session addInput:self.videoDeviceInput];
625
+ }
626
+
627
+ AVCaptureConnection *movieFileOutputConnection = [self.movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
628
+ if ( movieFileOutputConnection.isVideoStabilizationSupported ) {
629
+ movieFileOutputConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
630
+ }
631
+
632
+ /*
633
+ Set Live Photo capture and depth data delivery if it is supported. When changing cameras, the
634
+ `livePhotoCaptureEnabled` and `depthDataDeliveryEnabled` properties of the AVCapturePhotoOutput gets set to NO when
635
+ a video device is disconnected from the session. After the new video device is
636
+ added to the session, re-enable Live Photo capture and depth data delivery if they are supported.
637
+ */
638
+ self.photoOutput.livePhotoCaptureEnabled = self.photoOutput.livePhotoCaptureSupported;
639
+ self.photoOutput.depthDataDeliveryEnabled = self.photoOutput.depthDataDeliverySupported;
640
+
641
+ [self.session commitConfiguration];
642
+ }
643
+
644
+ dispatch_async( dispatch_get_main_queue(), ^{
645
+ self.cameraButton.enabled = YES;
646
+ //self.recordButton.enabled = self.captureModeControl.selectedSegmentIndex == AVCamCaptureModeMovie;
647
+ self.photoButton.enabled = YES;
648
+ // self.livePhotoModeButton.enabled = YES;
649
+ // self.captureModeControl.enabled = YES;
650
+ // self.depthDataDeliveryButton.enabled = self.photoOutput.isDepthDataDeliveryEnabled;
651
+ // self.depthDataDeliveryButton.hidden = !self.photoOutput.depthDataDeliverySupported;
652
+ } );
653
+ } );
654
+ }
655
+
656
+ - (IBAction)focusAndExposeTap:(UIGestureRecognizer *)gestureRecognizer
657
+ {
658
+ CGPoint devicePoint = [self.previewView.videoPreviewLayer captureDevicePointOfInterestForPoint:[gestureRecognizer locationInView:gestureRecognizer.view]];
659
+ [self focusWithMode:AVCaptureFocusModeAutoFocus exposeWithMode:AVCaptureExposureModeAutoExpose atDevicePoint:devicePoint monitorSubjectAreaChange:YES];
660
+ }
661
+
662
+ - (void)focusWithMode:(AVCaptureFocusMode)focusMode exposeWithMode:(AVCaptureExposureMode)exposureMode atDevicePoint:(CGPoint)point monitorSubjectAreaChange:(BOOL)monitorSubjectAreaChange
663
+ {
664
+ dispatch_async( self.sessionQueue, ^{
665
+ AVCaptureDevice *device = self.videoDeviceInput.device;
666
+ NSError *error = nil;
667
+ if ( [device lockForConfiguration:&error] ) {
668
+ /*
669
+ Setting (focus/exposure)PointOfInterest alone does not initiate a (focus/exposure) operation.
670
+ Call set(Focus/Exposure)Mode() to apply the new point of interest.
671
+ */
672
+ if ( device.isFocusPointOfInterestSupported && [device isFocusModeSupported:focusMode] ) {
673
+ device.focusPointOfInterest = point;
674
+ device.focusMode = focusMode;
675
+ }
676
+
677
+ if ( device.isExposurePointOfInterestSupported && [device isExposureModeSupported:exposureMode] ) {
678
+ device.exposurePointOfInterest = point;
679
+ device.exposureMode = exposureMode;
680
+ }
681
+
682
+ device.subjectAreaChangeMonitoringEnabled = monitorSubjectAreaChange;
683
+ [device unlockForConfiguration];
684
+ }
685
+ else {
686
+ NSLog( @"Could not lock device for configuration: %@", error );
687
+ }
688
+ } );
689
+ }
690
+
691
+ #pragma mark Capturing Photos
692
+
693
+ - (IBAction)backtowebview:(id)sender {
694
+ [mCamera dismissCam];
695
+ }
696
+ - (IBAction)capturePhoto:(id)sender
697
+ {
698
+ /*
699
+ Retrieve the video preview layer's video orientation on the main queue before
700
+ entering the session queue. We do this to ensure UI elements are accessed on
701
+ the main thread and session configuration is done on the session queue.
702
+ */
703
+ [_photoButton setHidden:TRUE];
704
+ [_progress setHidden:FALSE];
705
+ [_progress startAnimating];
706
+ dispatch_async( self.sessionQueue, ^{
707
+ // Update the photo output's connection to match the video orientation of the video preview layer.
708
+ AVCaptureConnection *photoOutputConnection = [self.photoOutput connectionWithMediaType:AVMediaTypeVideo];
709
+ photoOutputConnection.videoOrientation = curOr;
710
+
711
+ AVCapturePhotoSettings *photoSettings;
712
+ // Capture HEIF photo when supported, with flash set to auto and high resolution photo enabled.
713
+ if ( [self.photoOutput.availablePhotoCodecTypes containsObject:AVVideoCodecTypeHEVC] ) {
714
+ photoSettings = [AVCapturePhotoSettings photoSettingsWithFormat:@{ AVVideoCodecKey : AVVideoCodecTypeHEVC }];
715
+ }
716
+ else {
717
+ photoSettings = [AVCapturePhotoSettings photoSettings];
718
+ }
719
+
720
+ if ( self.videoDeviceInput.device.isFlashAvailable ) {
721
+ photoSettings.flashMode = AVCaptureFlashModeAuto;
722
+ }
723
+ photoSettings.highResolutionPhotoEnabled = YES;
724
+ if ( photoSettings.availablePreviewPhotoPixelFormatTypes.count > 0 ) {
725
+ photoSettings.previewPhotoFormat = @{ (NSString *)kCVPixelBufferPixelFormatTypeKey : photoSettings.availablePreviewPhotoPixelFormatTypes.firstObject };
726
+ }
727
+ if ( self.livePhotoMode == AVCamLivePhotoModeOn && self.photoOutput.livePhotoCaptureSupported ) { // Live Photo capture is not supported in movie mode.
728
+ NSString *livePhotoMovieFileName = [NSUUID UUID].UUIDString;
729
+ NSString *livePhotoMovieFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[livePhotoMovieFileName stringByAppendingPathExtension:@"mov"]];
730
+ photoSettings.livePhotoMovieFileURL = [NSURL fileURLWithPath:livePhotoMovieFilePath];
731
+ }
732
+
733
+ if ( self.depthDataDeliveryMode == AVCamDepthDataDeliveryModeOn && self.photoOutput.isDepthDataDeliverySupported ) {
734
+ photoSettings.depthDataDeliveryEnabled = YES;
735
+ } else {
736
+ photoSettings.depthDataDeliveryEnabled = NO;
737
+ }
738
+
739
+ // Use a separate object for the photo capture delegate to isolate each capture life cycle.
740
+ AVCamPhotoCaptureDelegate *photoCaptureDelegate = [[AVCamPhotoCaptureDelegate alloc] initWithRequestedPhotoSettings:photoSettings willCapturePhotoAnimation:^{
741
+ dispatch_async( dispatch_get_main_queue(), ^{
742
+ self.previewView.videoPreviewLayer.opacity = 0.0;
743
+ [UIView animateWithDuration:0.25 animations:^{
744
+ self.previewView.videoPreviewLayer.opacity = 1.0;
745
+ }];
746
+ } );
747
+ } livePhotoCaptureHandler:^( BOOL capturing ) {
748
+ /*
749
+ Because Live Photo captures can overlap, we need to keep track of the
750
+ number of in progress Live Photo captures to ensure that the
751
+ Live Photo label stays visible during these captures.
752
+ */
753
+ dispatch_async( self.sessionQueue, ^{
754
+ if ( capturing ) {
755
+ self.inProgressLivePhotoCapturesCount++;
756
+ }
757
+ else {
758
+ self.inProgressLivePhotoCapturesCount--;
759
+ }
760
+
761
+ NSInteger inProgressLivePhotoCapturesCount = self.inProgressLivePhotoCapturesCount;
762
+ dispatch_async( dispatch_get_main_queue(), ^{
763
+ if ( inProgressLivePhotoCapturesCount > 0 ) {
764
+ //self.capturingLivePhotoLabel.hidden = NO;
765
+ }
766
+ else if ( inProgressLivePhotoCapturesCount == 0 ) {
767
+ //self.capturingLivePhotoLabel.hidden = YES;
768
+ }
769
+ else {
770
+ NSLog( @"Error: In progress live photo capture count is less than 0" );
771
+ }
772
+ } );
773
+ } );
774
+ } completionHandler:^( AVCamPhotoCaptureDelegate *photoCaptureDelegate ) {
775
+ // When the capture is complete, remove a reference to the photo capture delegate so it can be deallocated.
776
+ dispatch_async( self.sessionQueue, ^{
777
+ self.inProgressPhotoCaptureDelegates[@(photoCaptureDelegate.requestedPhotoSettings.uniqueID)] = nil;
778
+ } );
779
+ }];
780
+
781
+ /*
782
+ The Photo Output keeps a weak reference to the photo capture delegate so
783
+ we store it in an array to maintain a strong reference to this object
784
+ until the capture is completed.
785
+ */
786
+ self.inProgressPhotoCaptureDelegates[@(photoCaptureDelegate.requestedPhotoSettings.uniqueID)] = photoCaptureDelegate;
787
+ [photoCaptureDelegate setUICam:self];
788
+ [self.photoOutput capturePhotoWithSettings:photoSettings delegate:photoCaptureDelegate];
789
+ } );
790
+ }
791
+
792
+ - (IBAction)toggleLivePhotoMode:(UIButton *)livePhotoModeButton
793
+ {
794
+ dispatch_async( self.sessionQueue, ^{
795
+ self.livePhotoMode = ( self.livePhotoMode == AVCamLivePhotoModeOn ) ? AVCamLivePhotoModeOff : AVCamLivePhotoModeOn;
796
+ AVCamLivePhotoMode livePhotoMode = self.livePhotoMode;
797
+
798
+ dispatch_async( dispatch_get_main_queue(), ^{
799
+ if ( livePhotoMode == AVCamLivePhotoModeOn ) {
800
+ //[self.livePhotoModeButton setTitle:NSLocalizedString( @"Live Photo Mode: On", @"Live photo mode button on title" ) forState:UIControlStateNormal];
801
+ }
802
+ else {
803
+ //[self.livePhotoModeButton setTitle:NSLocalizedString( @"Live Photo Mode: Off", @"Live photo mode button off title" ) forState:UIControlStateNormal];
804
+ }
805
+ } );
806
+ } );
807
+ }
808
+
809
+ - (IBAction)toggleDepthDataDeliveryMode:(UIButton *)depthDataDeliveryButton
810
+ {
811
+ dispatch_async( self.sessionQueue, ^{
812
+ self.depthDataDeliveryMode = ( self.depthDataDeliveryMode == AVCamDepthDataDeliveryModeOn ) ? AVCamDepthDataDeliveryModeOff : AVCamDepthDataDeliveryModeOn;
813
+ AVCamDepthDataDeliveryMode depthDataDeliveryMode = self.depthDataDeliveryMode;
814
+
815
+ dispatch_async( dispatch_get_main_queue(), ^{
816
+ if ( depthDataDeliveryMode == AVCamDepthDataDeliveryModeOn ) {
817
+ //[self.depthDataDeliveryButton setTitle:NSLocalizedString( @"Depth Data Delivery: On", @"Depth Data mode button on title" ) forState:UIControlStateNormal];
818
+ }
819
+ else {
820
+ //[self.depthDataDeliveryButton setTitle:NSLocalizedString( @"Depth Data Delivery: Off", @"Depth Data mode button off title" ) forState:UIControlStateNormal];
821
+ }
822
+ } );
823
+ } );
824
+ }
825
+
826
+ #pragma mark Recording Movies
827
+
828
+ - (IBAction)toggleMovieRecording:(id)sender
829
+ {
830
+ /*
831
+ Disable the Camera button until recording finishes, and disable
832
+ the Record button until recording starts or finishes.
833
+
834
+ See the AVCaptureFileOutputRecordingDelegate methods.
835
+ */
836
+ self.cameraButton.enabled = NO;
837
+ //self.recordButton.enabled = NO;
838
+ self.captureModeControl.enabled = NO;
839
+
840
+ /*
841
+ Retrieve the video preview layer's video orientation on the main queue
842
+ before entering the session queue. We do this to ensure UI elements are
843
+ accessed on the main thread and session configuration is done on the session queue.
844
+ */
845
+ AVCaptureVideoOrientation videoPreviewLayerVideoOrientation = self.previewView.videoPreviewLayer.connection.videoOrientation;
846
+
847
+ dispatch_async( self.sessionQueue, ^{
848
+ if ( ! self.movieFileOutput.isRecording ) {
849
+ if ( [UIDevice currentDevice].isMultitaskingSupported ) {
850
+ /*
851
+ Setup background task.
852
+ This is needed because the -[captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:]
853
+ callback is not received until AVCam returns to the foreground unless you request background execution time.
854
+ This also ensures that there will be time to write the file to the photo library when AVCam is backgrounded.
855
+ To conclude this background execution, -[endBackgroundTask:] is called in
856
+ -[captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:] after the recorded file has been saved.
857
+ */
858
+ self.backgroundRecordingID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
859
+ }
860
+
861
+ // Update the orientation on the movie file output video connection before starting recording.
862
+ AVCaptureConnection *movieFileOutputConnection = [self.movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
863
+ movieFileOutputConnection.videoOrientation = videoPreviewLayerVideoOrientation;
864
+
865
+ // Use HEVC codec if supported
866
+ if ( [self.movieFileOutput.availableVideoCodecTypes containsObject:AVVideoCodecTypeHEVC] ) {
867
+ [self.movieFileOutput setOutputSettings:@{ AVVideoCodecKey : AVVideoCodecTypeHEVC } forConnection:movieFileOutputConnection];
868
+ }
869
+
870
+ // Start recording to a temporary file.
871
+ NSString *outputFileName = [NSUUID UUID].UUIDString;
872
+ NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[outputFileName stringByAppendingPathExtension:@"mov"]];
873
+ [self.movieFileOutput startRecordingToOutputFileURL:[NSURL fileURLWithPath:outputFilePath] recordingDelegate:self];
874
+ }
875
+ else {
876
+ [self.movieFileOutput stopRecording];
877
+ }
878
+ } );
879
+ }
880
+
881
+ - (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections
882
+ {
883
+ // Enable the Record button to let the user stop the recording.
884
+ dispatch_async( dispatch_get_main_queue(), ^{
885
+ //self.recordButton.enabled = YES;
886
+ //[self.recordButton setTitle:NSLocalizedString( @"Stop", @"Recording button stop title" ) forState:UIControlStateNormal];
887
+ });
888
+ }
889
+
890
+ - (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
891
+ {
892
+ /*
893
+ Note that currentBackgroundRecordingID is used to end the background task
894
+ associated with this recording. This allows a new recording to be started,
895
+ associated with a new UIBackgroundTaskIdentifier, once the movie file output's
896
+ `recording` property is back to NO — which happens sometime after this method
897
+ returns.
898
+
899
+ Note: Since we use a unique file path for each recording, a new recording will
900
+ not overwrite a recording currently being saved.
901
+ */
902
+ UIBackgroundTaskIdentifier currentBackgroundRecordingID = self.backgroundRecordingID;
903
+ self.backgroundRecordingID = UIBackgroundTaskInvalid;
904
+
905
+ dispatch_block_t cleanUp = ^{
906
+ if ( [[NSFileManager defaultManager] fileExistsAtPath:outputFileURL.path] ) {
907
+ [[NSFileManager defaultManager] removeItemAtPath:outputFileURL.path error:NULL];
908
+ }
909
+
910
+ if ( currentBackgroundRecordingID != UIBackgroundTaskInvalid ) {
911
+ [[UIApplication sharedApplication] endBackgroundTask:currentBackgroundRecordingID];
912
+ }
913
+ };
914
+
915
+ BOOL success = YES;
916
+
917
+ if ( error ) {
918
+ NSLog( @"Movie file finishing error: %@", error );
919
+ success = [error.userInfo[AVErrorRecordingSuccessfullyFinishedKey] boolValue];
920
+ }
921
+ if ( success ) {
922
+ // Check authorization status.
923
+ [PHPhotoLibrary requestAuthorization:^( PHAuthorizationStatus status ) {
924
+ if ( status == PHAuthorizationStatusAuthorized ) {
925
+ // Save the movie file to the photo library and cleanup.
926
+ [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
927
+ PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
928
+ options.shouldMoveFile = YES;
929
+ PHAssetCreationRequest *creationRequest = [PHAssetCreationRequest creationRequestForAsset];
930
+ [creationRequest addResourceWithType:PHAssetResourceTypeVideo fileURL:outputFileURL options:options];
931
+ } completionHandler:^( BOOL success, NSError *error ) {
932
+ if ( ! success ) {
933
+ NSLog( @"Could not save movie to photo library: %@", error );
934
+ }
935
+ cleanUp();
936
+ }];
937
+ }
938
+ else {
939
+ cleanUp();
940
+ }
941
+ }];
942
+ }
943
+ else {
944
+ cleanUp();
945
+ }
946
+
947
+ // Enable the Camera and Record buttons to let the user switch camera and start another recording.
948
+ dispatch_async( dispatch_get_main_queue(), ^{
949
+ // Only enable the ability to change camera if the device has more than one camera.
950
+ self.cameraButton.enabled = ( self.videoDeviceDiscoverySession.uniqueDevicePositionsCount > 1 );
951
+ //self.recordButton.enabled = YES;
952
+ self.captureModeControl.enabled = YES;
953
+ //[self.recordButton setTitle:NSLocalizedString( @"Record", @"Recording button record title" ) forState:UIControlStateNormal];
954
+ });
955
+ }
956
+
957
+ #pragma mark KVO and Notifications
958
+
959
+ - (void)addObservers
960
+ {
961
+ [self.session addObserver:self forKeyPath:@"running" options:NSKeyValueObservingOptionNew context:SessionRunningContext];
962
+
963
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:self.videoDeviceInput.device];
964
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:self.session];
965
+
966
+ /*
967
+ A session can only run when the app is full screen. It will be interrupted
968
+ in a multi-app layout, introduced in iOS 9, see also the documentation of
969
+ AVCaptureSessionInterruptionReason. Add observers to handle these session
970
+ interruptions and show a preview is paused message. See the documentation
971
+ of AVCaptureSessionWasInterruptedNotification for other interruption reasons.
972
+ */
973
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionWasInterrupted:) name:AVCaptureSessionWasInterruptedNotification object:self.session];
974
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionInterruptionEnded:) name:AVCaptureSessionInterruptionEndedNotification object:self.session];
975
+ }
976
+
977
+ - (void)removeObservers
978
+ {
979
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
980
+
981
+ [self.session removeObserver:self forKeyPath:@"running" context:SessionRunningContext];
982
+ }
983
+
984
+ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
985
+ {
986
+ if ( context == SessionRunningContext ) {
987
+ BOOL isSessionRunning = [change[NSKeyValueChangeNewKey] boolValue];
988
+
989
+ dispatch_async( dispatch_get_main_queue(), ^{
990
+ // Only enable the ability to change camera if the device has more than one camera.
991
+ self.cameraButton.enabled = isSessionRunning && ( self.videoDeviceDiscoverySession.uniqueDevicePositionsCount > 1 );
992
+ //self.recordButton.enabled = isSessionRunning && ( self.captureModeControl.selectedSegmentIndex == AVCamCaptureModeMovie );
993
+ self.photoButton.enabled = isSessionRunning;
994
+ self.captureModeControl.enabled = isSessionRunning;
995
+ //self.livePhotoModeButton.enabled = isSessionRunning && livePhotoCaptureEnabled;
996
+ //self.livePhotoModeButton.hidden = ! ( isSessionRunning && livePhotoCaptureSupported );
997
+ //self.depthDataDeliveryButton.enabled = isSessionRunning && depthDataDeliveryEnabled ;
998
+ //self.depthDataDeliveryButton.hidden = ! ( isSessionRunning && depthDataDeliverySupported );
999
+ } );
1000
+ }
1001
+ else {
1002
+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
1003
+ }
1004
+ }
1005
+
1006
+ - (void)subjectAreaDidChange:(NSNotification *)notification
1007
+ {
1008
+ CGPoint devicePoint = CGPointMake( 0.5, 0.5 );
1009
+ [self focusWithMode:AVCaptureFocusModeContinuousAutoFocus exposeWithMode:AVCaptureExposureModeContinuousAutoExposure atDevicePoint:devicePoint monitorSubjectAreaChange:NO];
1010
+ }
1011
+
1012
+ - (void)sessionRuntimeError:(NSNotification *)notification
1013
+ {
1014
+ NSError *error = notification.userInfo[AVCaptureSessionErrorKey];
1015
+ NSLog( @"Capture session runtime error: %@", error );
1016
+
1017
+ /*
1018
+ Automatically try to restart the session running if media services were
1019
+ reset and the last start running succeeded. Otherwise, enable the user
1020
+ to try to resume the session running.
1021
+ */
1022
+ if ( error.code == AVErrorMediaServicesWereReset ) {
1023
+ dispatch_async( self.sessionQueue, ^{
1024
+ if ( self.isSessionRunning ) {
1025
+ [self.session startRunning];
1026
+ self.sessionRunning = self.session.isRunning;
1027
+ }
1028
+ else {
1029
+ dispatch_async( dispatch_get_main_queue(), ^{
1030
+ //self.resumeButton.hidden = NO;
1031
+ } );
1032
+ }
1033
+ } );
1034
+ }
1035
+ else {
1036
+ //self.resumeButton.hidden = NO;
1037
+ }
1038
+ }
1039
+
1040
+ - (void)sessionWasInterrupted:(NSNotification *)notification
1041
+ {
1042
+ /*
1043
+ In some scenarios we want to enable the user to resume the session running.
1044
+ For example, if music playback is initiated via control center while
1045
+ using AVCam, then the user can let AVCam resume
1046
+ the session running, which will stop music playback. Note that stopping
1047
+ music playback in control center will not automatically resume the session
1048
+ running. Also note that it is not always possible to resume, see -[resumeInterruptedSession:].
1049
+ */
1050
+ BOOL showResumeButton = NO;
1051
+
1052
+ AVCaptureSessionInterruptionReason reason = [notification.userInfo[AVCaptureSessionInterruptionReasonKey] integerValue];
1053
+ NSLog( @"Capture session was interrupted with reason %ld", (long)reason );
1054
+
1055
+ if ( reason == AVCaptureSessionInterruptionReasonAudioDeviceInUseByAnotherClient ||
1056
+ reason == AVCaptureSessionInterruptionReasonVideoDeviceInUseByAnotherClient ) {
1057
+ showResumeButton = YES;
1058
+ }
1059
+ else if ( reason == AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableWithMultipleForegroundApps ) {
1060
+ // Simply fade-in a label to inform the user that the camera is unavailable.
1061
+ //self.cameraUnavailableLabel.alpha = 0.0;
1062
+ //self.cameraUnavailableLabel.hidden = NO;
1063
+ [UIView animateWithDuration:0.25 animations:^{
1064
+ //self.cameraUnavailableLabel.alpha = 1.0;
1065
+ }];
1066
+ }
1067
+
1068
+ if ( showResumeButton ) {
1069
+ // Simply fade-in a button to enable the user to try to resume the session running.
1070
+ //self.resumeButton.alpha = 0.0;
1071
+ //self.resumeButton.hidden = NO;
1072
+ [UIView animateWithDuration:0.25 animations:^{
1073
+ //self.resumeButton.alpha = 1.0;
1074
+ }];
1075
+ }
1076
+ }
1077
+
1078
+ - (void)sessionInterruptionEnded:(NSNotification *)notification
1079
+ {
1080
+ NSLog( @"Capture session interruption ended" );
1081
+
1082
+ // if ( ! self.resumeButton.hidden ) {
1083
+ // [UIView animateWithDuration:0.25 animations:^{
1084
+ // self.resumeButton.alpha = 0.0;
1085
+ // } completion:^( BOOL finished ) {
1086
+ // self.resumeButton.hidden = YES;
1087
+ // }];
1088
+ // }
1089
+ // if ( ! self.cameraUnavailableLabel.hidden ) {
1090
+ // [UIView animateWithDuration:0.25 animations:^{
1091
+ // self.cameraUnavailableLabel.alpha = 0.0;
1092
+ // } completion:^( BOOL finished ) {
1093
+ // self.cameraUnavailableLabel.hidden = YES;
1094
+ // }];
1095
+ // }
1096
+ }
1097
+
1098
+ @end