├── .gitignore ├── Cartfile ├── Cartfile.resolved ├── LICENSE ├── Package.swift ├── README.md ├── RxAVFoundation.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── RxAVFoundation.xcscheme ├── RxAVFoundation ├── AVCaptureSession+Rx.swift ├── Global.swift ├── Info.plist ├── RxAVCaptureDataOutputSynchronizerDelegate.swift ├── RxAVCaptureDepthDataOutputDelegate.swift ├── RxAVCaptureMetadataOutputObjectsDelegate.swift ├── RxAVCapturePhotoCaptureDelegate.swift ├── RxAVCaptureVideoDataOutputSampleBufferDelegate.swift └── RxAVFoundation.h └── RxAVFoundationTests ├── Info.plist └── RxAVFoundationTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots/**/*.png 68 | fastlane/test_output 69 | Carthage 70 | -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "ReactiveX/RxSwift" ~> 4.3.1 2 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "ReactiveX/RxSwift" "4.3.1" 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) RxSwiftCommunity 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "RxAVFoundation", 6 | products: [ 7 | .library( 8 | name: "RxAVFoundation", 9 | targets: ["RxAVFoundation"]) 10 | ], 11 | dependencies: [ 12 | .package(url: "https://github.com/ReactiveX/RxSwift", from: "5.0.1") 13 | ], 14 | targets: [ 15 | .target( 16 | name: "RxAVFoundation", 17 | dependencies: ["RxSwift", "RxCocoa"], 18 | path: "RxAVFoundation") 19 | ] 20 | ) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RxAVFoundation 2 | RxAVFoundation (based on RxSwift) 3 | 4 | Basic usage. 5 | 6 | ```swift 7 | var session = AVCaptureSession() 8 | 9 | session 10 | .rx 11 | .configure(captureDevice: captureDevice) // define 'captureDevice' first 12 | 13 | session 14 | .rx 15 | .videoCaptureOutput() 16 | .observeOn(MainScheduler.instance) 17 | .subscribe { [unowned self] (event) in 18 | switch event { 19 | case .next(let captureOutput): 20 | self.processVideo(sampleBuffer: captureOutput.sampleBuffer) // define the method first 21 | case .error(let error): 22 | os_log("error: %@", "\(error)") 23 | case .completed: 24 | break // never happens 25 | } 26 | } 27 | .disposed(by: disposeBag) 28 | 29 | session 30 | .rx 31 | .depthCaptureOutput() 32 | .observeOn(MainScheduler.instance) 33 | .subscribe { [unowned self] (event) in 34 | switch event { 35 | case .next(let captureOutput): 36 | self.processDepth(depthData: captureOutput.depthData) // define the method first 37 | case .error(let error): 38 | os_log("error: %@", "\(error)") 39 | case .completed: 40 | break // never happens 41 | } 42 | } 43 | .disposed(by: disposeBag) 44 | 45 | session 46 | .rx 47 | .outputs 48 | .asObservable() 49 | .flatMap { [unowned self] outputs in 50 | self.session.rx.synchronizerOutput(dataOutputs: outputs) 51 | } 52 | .observeOn(MainScheduler.instance) 53 | .subscribe { [unowned self] (event) in 54 | switch event { 55 | case .next(let synchronizerOutput): 56 | let videoDataOutput = self.session.outputs.filter { $0 is AVCaptureVideoDataOutput }.first! 57 | let depthDataOutput = self.session.outputs.filter { $0 is AVCaptureDepthDataOutput }.first! 58 | // ... 59 | case .error(let error): 60 | os_log("error: %@", "\(error)") 61 | case .completed: 62 | break // never happens 63 | } 64 | } 65 | .disposed(by: disposeBag) 66 | 67 | session 68 | .rx 69 | .startRunning() 70 | ``` 71 | 72 | Carthage setup. 73 | 74 | ``` 75 | github "RxSwiftCommunity/RxAVFoundation" ~> 0.1.0 76 | 77 | ``` 78 | 79 | Copyright (c) RxSwiftCommunity 80 | -------------------------------------------------------------------------------- /RxAVFoundation.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 946A25C522946FDE002B46BA /* RxAVCaptureMetadataOutputObjectsDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 946A25C422946FDE002B46BA /* RxAVCaptureMetadataOutputObjectsDelegate.swift */; }; 11 | 94DC8A83218104690026F49B /* RxAVCapturePhotoCaptureDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94DC8A7E218104680026F49B /* RxAVCapturePhotoCaptureDelegate.swift */; }; 12 | 94DC8A84218104690026F49B /* Global.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94DC8A7F218104690026F49B /* Global.swift */; }; 13 | 94DC8A85218104690026F49B /* RxAVCaptureDepthDataOutputDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94DC8A80218104690026F49B /* RxAVCaptureDepthDataOutputDelegate.swift */; }; 14 | 94DC8A86218104690026F49B /* RxAVCaptureVideoDataOutputSampleBufferDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94DC8A81218104690026F49B /* RxAVCaptureVideoDataOutputSampleBufferDelegate.swift */; }; 15 | 94DC8A87218104690026F49B /* RxAVCaptureDataOutputSynchronizerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94DC8A82218104690026F49B /* RxAVCaptureDataOutputSynchronizerDelegate.swift */; }; 16 | 94DF2750215CA8A400051F68 /* RxAVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 94DF2746215CA8A300051F68 /* RxAVFoundation.framework */; }; 17 | 94DF2755215CA8A400051F68 /* RxAVFoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94DF2754215CA8A400051F68 /* RxAVFoundationTests.swift */; }; 18 | 94DF2757215CA8A400051F68 /* RxAVFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 94DF2749215CA8A300051F68 /* RxAVFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 19 | 94DF2766215CAAAA00051F68 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 94DF2765215CAAAA00051F68 /* RxSwift.framework */; }; 20 | 94DF2768215CB2D900051F68 /* AVCaptureSession+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94DF2767215CB2D900051F68 /* AVCaptureSession+Rx.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 94DF2751215CA8A400051F68 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 94DF273D215CA8A300051F68 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 94DF2745215CA8A300051F68; 29 | remoteInfo = RxAVFoundation; 30 | }; 31 | /* End PBXContainerItemProxy section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 946A25C422946FDE002B46BA /* RxAVCaptureMetadataOutputObjectsDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxAVCaptureMetadataOutputObjectsDelegate.swift; sourceTree = ""; }; 35 | 94DC8A7E218104680026F49B /* RxAVCapturePhotoCaptureDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxAVCapturePhotoCaptureDelegate.swift; sourceTree = ""; }; 36 | 94DC8A7F218104690026F49B /* Global.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Global.swift; sourceTree = ""; }; 37 | 94DC8A80218104690026F49B /* RxAVCaptureDepthDataOutputDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxAVCaptureDepthDataOutputDelegate.swift; sourceTree = ""; }; 38 | 94DC8A81218104690026F49B /* RxAVCaptureVideoDataOutputSampleBufferDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxAVCaptureVideoDataOutputSampleBufferDelegate.swift; sourceTree = ""; }; 39 | 94DC8A82218104690026F49B /* RxAVCaptureDataOutputSynchronizerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxAVCaptureDataOutputSynchronizerDelegate.swift; sourceTree = ""; }; 40 | 94DF2746215CA8A300051F68 /* RxAVFoundation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxAVFoundation.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 94DF2749215CA8A300051F68 /* RxAVFoundation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RxAVFoundation.h; sourceTree = ""; }; 42 | 94DF274A215CA8A300051F68 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43 | 94DF274F215CA8A400051F68 /* RxAVFoundationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RxAVFoundationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 94DF2754215CA8A400051F68 /* RxAVFoundationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxAVFoundationTests.swift; sourceTree = ""; }; 45 | 94DF2756215CA8A400051F68 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | 94DF2765215CAAAA00051F68 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = ../../Carthage/Build/iOS/RxSwift.framework; sourceTree = ""; }; 47 | 94DF2767215CB2D900051F68 /* AVCaptureSession+Rx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVCaptureSession+Rx.swift"; sourceTree = ""; }; 48 | 94DF2769215D476600051F68 /* Cartfile.resolved */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile.resolved; sourceTree = ""; }; 49 | 94DF276A215D476600051F68 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 50 | 94DF276B215D476600051F68 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 51 | 94DF276C215D476600051F68 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | 94DF2743215CA8A300051F68 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | 94DF2766215CAAAA00051F68 /* RxSwift.framework in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | 94DF274C215CA8A400051F68 /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | 94DF2750215CA8A400051F68 /* RxAVFoundation.framework in Frameworks */, 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | /* End PBXFrameworksBuildPhase section */ 72 | 73 | /* Begin PBXGroup section */ 74 | 94DF273C215CA8A300051F68 = { 75 | isa = PBXGroup; 76 | children = ( 77 | 94DF276C215D476600051F68 /* Cartfile */, 78 | 94DF2769215D476600051F68 /* Cartfile.resolved */, 79 | 94DF276A215D476600051F68 /* LICENSE */, 80 | 94DF276B215D476600051F68 /* README.md */, 81 | 94DF2748215CA8A300051F68 /* RxAVFoundation */, 82 | 94DF2753215CA8A400051F68 /* RxAVFoundationTests */, 83 | 94DF2747215CA8A300051F68 /* Products */, 84 | 94DF2764215CAAA900051F68 /* Frameworks */, 85 | ); 86 | sourceTree = ""; 87 | }; 88 | 94DF2747215CA8A300051F68 /* Products */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 94DF2746215CA8A300051F68 /* RxAVFoundation.framework */, 92 | 94DF274F215CA8A400051F68 /* RxAVFoundationTests.xctest */, 93 | ); 94 | name = Products; 95 | sourceTree = ""; 96 | }; 97 | 94DF2748215CA8A300051F68 /* RxAVFoundation */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 94DF2749215CA8A300051F68 /* RxAVFoundation.h */, 101 | 94DF274A215CA8A300051F68 /* Info.plist */, 102 | 94DF2767215CB2D900051F68 /* AVCaptureSession+Rx.swift */, 103 | 94DC8A7F218104690026F49B /* Global.swift */, 104 | 946A25C422946FDE002B46BA /* RxAVCaptureMetadataOutputObjectsDelegate.swift */, 105 | 94DC8A82218104690026F49B /* RxAVCaptureDataOutputSynchronizerDelegate.swift */, 106 | 94DC8A80218104690026F49B /* RxAVCaptureDepthDataOutputDelegate.swift */, 107 | 94DC8A7E218104680026F49B /* RxAVCapturePhotoCaptureDelegate.swift */, 108 | 94DC8A81218104690026F49B /* RxAVCaptureVideoDataOutputSampleBufferDelegate.swift */, 109 | ); 110 | path = RxAVFoundation; 111 | sourceTree = ""; 112 | }; 113 | 94DF2753215CA8A400051F68 /* RxAVFoundationTests */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 94DF2754215CA8A400051F68 /* RxAVFoundationTests.swift */, 117 | 94DF2756215CA8A400051F68 /* Info.plist */, 118 | ); 119 | path = RxAVFoundationTests; 120 | sourceTree = ""; 121 | }; 122 | 94DF2764215CAAA900051F68 /* Frameworks */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 94DF2765215CAAAA00051F68 /* RxSwift.framework */, 126 | ); 127 | name = Frameworks; 128 | sourceTree = ""; 129 | }; 130 | /* End PBXGroup section */ 131 | 132 | /* Begin PBXHeadersBuildPhase section */ 133 | 94DF2741215CA8A300051F68 /* Headers */ = { 134 | isa = PBXHeadersBuildPhase; 135 | buildActionMask = 2147483647; 136 | files = ( 137 | 94DF2757215CA8A400051F68 /* RxAVFoundation.h in Headers */, 138 | ); 139 | runOnlyForDeploymentPostprocessing = 0; 140 | }; 141 | /* End PBXHeadersBuildPhase section */ 142 | 143 | /* Begin PBXNativeTarget section */ 144 | 94DF2745215CA8A300051F68 /* RxAVFoundation */ = { 145 | isa = PBXNativeTarget; 146 | buildConfigurationList = 94DF275A215CA8A400051F68 /* Build configuration list for PBXNativeTarget "RxAVFoundation" */; 147 | buildPhases = ( 148 | 94DF2741215CA8A300051F68 /* Headers */, 149 | 94DF2742215CA8A300051F68 /* Sources */, 150 | 94DF2743215CA8A300051F68 /* Frameworks */, 151 | 94DF2744215CA8A300051F68 /* Resources */, 152 | 94DF2762215CAA4F00051F68 /* Carthage */, 153 | 94DF2763215CAA5200051F68 /* Delete Nested Framework(s) */, 154 | ); 155 | buildRules = ( 156 | ); 157 | dependencies = ( 158 | ); 159 | name = RxAVFoundation; 160 | productName = RxAVFoundation; 161 | productReference = 94DF2746215CA8A300051F68 /* RxAVFoundation.framework */; 162 | productType = "com.apple.product-type.framework"; 163 | }; 164 | 94DF274E215CA8A400051F68 /* RxAVFoundationTests */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = 94DF275D215CA8A400051F68 /* Build configuration list for PBXNativeTarget "RxAVFoundationTests" */; 167 | buildPhases = ( 168 | 94DF274B215CA8A400051F68 /* Sources */, 169 | 94DF274C215CA8A400051F68 /* Frameworks */, 170 | 94DF274D215CA8A400051F68 /* Resources */, 171 | ); 172 | buildRules = ( 173 | ); 174 | dependencies = ( 175 | 94DF2752215CA8A400051F68 /* PBXTargetDependency */, 176 | ); 177 | name = RxAVFoundationTests; 178 | productName = RxAVFoundationTests; 179 | productReference = 94DF274F215CA8A400051F68 /* RxAVFoundationTests.xctest */; 180 | productType = "com.apple.product-type.bundle.unit-test"; 181 | }; 182 | /* End PBXNativeTarget section */ 183 | 184 | /* Begin PBXProject section */ 185 | 94DF273D215CA8A300051F68 /* Project object */ = { 186 | isa = PBXProject; 187 | attributes = { 188 | LastSwiftUpdateCheck = 1000; 189 | LastUpgradeCheck = 1000; 190 | ORGANIZATIONNAME = "Maxim Volgin"; 191 | TargetAttributes = { 192 | 94DF2745215CA8A300051F68 = { 193 | CreatedOnToolsVersion = 10.0; 194 | LastSwiftMigration = 1020; 195 | }; 196 | 94DF274E215CA8A400051F68 = { 197 | CreatedOnToolsVersion = 10.0; 198 | LastSwiftMigration = 1020; 199 | }; 200 | }; 201 | }; 202 | buildConfigurationList = 94DF2740215CA8A300051F68 /* Build configuration list for PBXProject "RxAVFoundation" */; 203 | compatibilityVersion = "Xcode 9.3"; 204 | developmentRegion = en; 205 | hasScannedForEncodings = 0; 206 | knownRegions = ( 207 | en, 208 | ); 209 | mainGroup = 94DF273C215CA8A300051F68; 210 | productRefGroup = 94DF2747215CA8A300051F68 /* Products */; 211 | projectDirPath = ""; 212 | projectRoot = ""; 213 | targets = ( 214 | 94DF2745215CA8A300051F68 /* RxAVFoundation */, 215 | 94DF274E215CA8A400051F68 /* RxAVFoundationTests */, 216 | ); 217 | }; 218 | /* End PBXProject section */ 219 | 220 | /* Begin PBXResourcesBuildPhase section */ 221 | 94DF2744215CA8A300051F68 /* Resources */ = { 222 | isa = PBXResourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | 94DF274D215CA8A400051F68 /* Resources */ = { 229 | isa = PBXResourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | ); 233 | runOnlyForDeploymentPostprocessing = 0; 234 | }; 235 | /* End PBXResourcesBuildPhase section */ 236 | 237 | /* Begin PBXShellScriptBuildPhase section */ 238 | 94DF2762215CAA4F00051F68 /* Carthage */ = { 239 | isa = PBXShellScriptBuildPhase; 240 | buildActionMask = 2147483647; 241 | files = ( 242 | ); 243 | inputFileListPaths = ( 244 | ); 245 | inputPaths = ( 246 | "$(SRCROOT)/Carthage/Build/iOS/RxSwift.framework", 247 | ); 248 | name = Carthage; 249 | outputFileListPaths = ( 250 | ); 251 | outputPaths = ( 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | shellPath = /bin/sh; 255 | shellScript = "/usr/local/bin/carthage copy-frameworks\n"; 256 | }; 257 | 94DF2763215CAA5200051F68 /* Delete Nested Framework(s) */ = { 258 | isa = PBXShellScriptBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | ); 262 | inputFileListPaths = ( 263 | ); 264 | inputPaths = ( 265 | ); 266 | name = "Delete Nested Framework(s)"; 267 | outputFileListPaths = ( 268 | ); 269 | outputPaths = ( 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | shellPath = /bin/sh; 273 | shellScript = "cd \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\nif [[ -d \"Frameworks\" ]]; then\n rm -fr Frameworks\nfi\n"; 274 | }; 275 | /* End PBXShellScriptBuildPhase section */ 276 | 277 | /* Begin PBXSourcesBuildPhase section */ 278 | 94DF2742215CA8A300051F68 /* Sources */ = { 279 | isa = PBXSourcesBuildPhase; 280 | buildActionMask = 2147483647; 281 | files = ( 282 | 94DC8A83218104690026F49B /* RxAVCapturePhotoCaptureDelegate.swift in Sources */, 283 | 94DC8A86218104690026F49B /* RxAVCaptureVideoDataOutputSampleBufferDelegate.swift in Sources */, 284 | 94DF2768215CB2D900051F68 /* AVCaptureSession+Rx.swift in Sources */, 285 | 94DC8A84218104690026F49B /* Global.swift in Sources */, 286 | 94DC8A85218104690026F49B /* RxAVCaptureDepthDataOutputDelegate.swift in Sources */, 287 | 94DC8A87218104690026F49B /* RxAVCaptureDataOutputSynchronizerDelegate.swift in Sources */, 288 | 946A25C522946FDE002B46BA /* RxAVCaptureMetadataOutputObjectsDelegate.swift in Sources */, 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | 94DF274B215CA8A400051F68 /* Sources */ = { 293 | isa = PBXSourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | 94DF2755215CA8A400051F68 /* RxAVFoundationTests.swift in Sources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | /* End PBXSourcesBuildPhase section */ 301 | 302 | /* Begin PBXTargetDependency section */ 303 | 94DF2752215CA8A400051F68 /* PBXTargetDependency */ = { 304 | isa = PBXTargetDependency; 305 | target = 94DF2745215CA8A300051F68 /* RxAVFoundation */; 306 | targetProxy = 94DF2751215CA8A400051F68 /* PBXContainerItemProxy */; 307 | }; 308 | /* End PBXTargetDependency section */ 309 | 310 | /* Begin XCBuildConfiguration section */ 311 | 94DF2758215CA8A400051F68 /* Debug */ = { 312 | isa = XCBuildConfiguration; 313 | buildSettings = { 314 | ALWAYS_SEARCH_USER_PATHS = NO; 315 | CLANG_ANALYZER_NONNULL = YES; 316 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 317 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 318 | CLANG_CXX_LIBRARY = "libc++"; 319 | CLANG_ENABLE_MODULES = YES; 320 | CLANG_ENABLE_OBJC_ARC = YES; 321 | CLANG_ENABLE_OBJC_WEAK = YES; 322 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 323 | CLANG_WARN_BOOL_CONVERSION = YES; 324 | CLANG_WARN_COMMA = YES; 325 | CLANG_WARN_CONSTANT_CONVERSION = YES; 326 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 327 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 328 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 329 | CLANG_WARN_EMPTY_BODY = YES; 330 | CLANG_WARN_ENUM_CONVERSION = YES; 331 | CLANG_WARN_INFINITE_RECURSION = YES; 332 | CLANG_WARN_INT_CONVERSION = YES; 333 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 334 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 335 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 336 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 337 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 338 | CLANG_WARN_STRICT_PROTOTYPES = YES; 339 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 340 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 341 | CLANG_WARN_UNREACHABLE_CODE = YES; 342 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 343 | CODE_SIGN_IDENTITY = "iPhone Developer"; 344 | COPY_PHASE_STRIP = NO; 345 | CURRENT_PROJECT_VERSION = 1; 346 | DEBUG_INFORMATION_FORMAT = dwarf; 347 | ENABLE_STRICT_OBJC_MSGSEND = YES; 348 | ENABLE_TESTABILITY = YES; 349 | GCC_C_LANGUAGE_STANDARD = gnu11; 350 | GCC_DYNAMIC_NO_PIC = NO; 351 | GCC_NO_COMMON_BLOCKS = YES; 352 | GCC_OPTIMIZATION_LEVEL = 0; 353 | GCC_PREPROCESSOR_DEFINITIONS = ( 354 | "DEBUG=1", 355 | "$(inherited)", 356 | ); 357 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 358 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 359 | GCC_WARN_UNDECLARED_SELECTOR = YES; 360 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 361 | GCC_WARN_UNUSED_FUNCTION = YES; 362 | GCC_WARN_UNUSED_VARIABLE = YES; 363 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 364 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 365 | MTL_FAST_MATH = YES; 366 | ONLY_ACTIVE_ARCH = YES; 367 | SDKROOT = iphoneos; 368 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 369 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 370 | VERSIONING_SYSTEM = "apple-generic"; 371 | VERSION_INFO_PREFIX = ""; 372 | }; 373 | name = Debug; 374 | }; 375 | 94DF2759215CA8A400051F68 /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | ALWAYS_SEARCH_USER_PATHS = NO; 379 | CLANG_ANALYZER_NONNULL = YES; 380 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 381 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 382 | CLANG_CXX_LIBRARY = "libc++"; 383 | CLANG_ENABLE_MODULES = YES; 384 | CLANG_ENABLE_OBJC_ARC = YES; 385 | CLANG_ENABLE_OBJC_WEAK = YES; 386 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 387 | CLANG_WARN_BOOL_CONVERSION = YES; 388 | CLANG_WARN_COMMA = YES; 389 | CLANG_WARN_CONSTANT_CONVERSION = YES; 390 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 391 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 392 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 393 | CLANG_WARN_EMPTY_BODY = YES; 394 | CLANG_WARN_ENUM_CONVERSION = YES; 395 | CLANG_WARN_INFINITE_RECURSION = YES; 396 | CLANG_WARN_INT_CONVERSION = YES; 397 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 398 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 399 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 400 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 401 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 402 | CLANG_WARN_STRICT_PROTOTYPES = YES; 403 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 404 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 405 | CLANG_WARN_UNREACHABLE_CODE = YES; 406 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 407 | CODE_SIGN_IDENTITY = "iPhone Developer"; 408 | COPY_PHASE_STRIP = NO; 409 | CURRENT_PROJECT_VERSION = 1; 410 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 411 | ENABLE_NS_ASSERTIONS = NO; 412 | ENABLE_STRICT_OBJC_MSGSEND = YES; 413 | GCC_C_LANGUAGE_STANDARD = gnu11; 414 | GCC_NO_COMMON_BLOCKS = YES; 415 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 416 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 417 | GCC_WARN_UNDECLARED_SELECTOR = YES; 418 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 419 | GCC_WARN_UNUSED_FUNCTION = YES; 420 | GCC_WARN_UNUSED_VARIABLE = YES; 421 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 422 | MTL_ENABLE_DEBUG_INFO = NO; 423 | MTL_FAST_MATH = YES; 424 | SDKROOT = iphoneos; 425 | SWIFT_COMPILATION_MODE = wholemodule; 426 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 427 | VALIDATE_PRODUCT = YES; 428 | VERSIONING_SYSTEM = "apple-generic"; 429 | VERSION_INFO_PREFIX = ""; 430 | }; 431 | name = Release; 432 | }; 433 | 94DF275B215CA8A400051F68 /* Debug */ = { 434 | isa = XCBuildConfiguration; 435 | buildSettings = { 436 | CLANG_ENABLE_MODULES = YES; 437 | CODE_SIGN_IDENTITY = ""; 438 | CODE_SIGN_STYLE = Automatic; 439 | DEFINES_MODULE = YES; 440 | DYLIB_COMPATIBILITY_VERSION = 1; 441 | DYLIB_CURRENT_VERSION = 1; 442 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 443 | FRAMEWORK_SEARCH_PATHS = ( 444 | "$(inherited)", 445 | "$(PROJECT_DIR)/Carthage/Build/iOS", 446 | ); 447 | INFOPLIST_FILE = RxAVFoundation/Info.plist; 448 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 449 | LD_RUNPATH_SEARCH_PATHS = ( 450 | "$(inherited)", 451 | "@executable_path/Frameworks", 452 | "@loader_path/Frameworks", 453 | ); 454 | PRODUCT_BUNDLE_IDENTIFIER = maxvol.RxAVFoundation; 455 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 456 | SKIP_INSTALL = YES; 457 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 458 | SWIFT_VERSION = 5.0; 459 | TARGETED_DEVICE_FAMILY = "1,2"; 460 | }; 461 | name = Debug; 462 | }; 463 | 94DF275C215CA8A400051F68 /* Release */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | CLANG_ENABLE_MODULES = YES; 467 | CODE_SIGN_IDENTITY = ""; 468 | CODE_SIGN_STYLE = Automatic; 469 | DEFINES_MODULE = YES; 470 | DYLIB_COMPATIBILITY_VERSION = 1; 471 | DYLIB_CURRENT_VERSION = 1; 472 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 473 | FRAMEWORK_SEARCH_PATHS = ( 474 | "$(inherited)", 475 | "$(PROJECT_DIR)/Carthage/Build/iOS", 476 | ); 477 | INFOPLIST_FILE = RxAVFoundation/Info.plist; 478 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 479 | LD_RUNPATH_SEARCH_PATHS = ( 480 | "$(inherited)", 481 | "@executable_path/Frameworks", 482 | "@loader_path/Frameworks", 483 | ); 484 | PRODUCT_BUNDLE_IDENTIFIER = maxvol.RxAVFoundation; 485 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 486 | SKIP_INSTALL = YES; 487 | SWIFT_VERSION = 5.0; 488 | TARGETED_DEVICE_FAMILY = "1,2"; 489 | }; 490 | name = Release; 491 | }; 492 | 94DF275E215CA8A400051F68 /* Debug */ = { 493 | isa = XCBuildConfiguration; 494 | buildSettings = { 495 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 496 | CODE_SIGN_STYLE = Automatic; 497 | DEVELOPMENT_TEAM = ""; 498 | INFOPLIST_FILE = RxAVFoundationTests/Info.plist; 499 | LD_RUNPATH_SEARCH_PATHS = ( 500 | "$(inherited)", 501 | "@executable_path/Frameworks", 502 | "@loader_path/Frameworks", 503 | ); 504 | PRODUCT_BUNDLE_IDENTIFIER = maxvol.RxAVFoundationTests; 505 | PRODUCT_NAME = "$(TARGET_NAME)"; 506 | SWIFT_VERSION = 5.0; 507 | TARGETED_DEVICE_FAMILY = "1,2"; 508 | }; 509 | name = Debug; 510 | }; 511 | 94DF275F215CA8A400051F68 /* Release */ = { 512 | isa = XCBuildConfiguration; 513 | buildSettings = { 514 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 515 | CODE_SIGN_STYLE = Automatic; 516 | DEVELOPMENT_TEAM = ""; 517 | INFOPLIST_FILE = RxAVFoundationTests/Info.plist; 518 | LD_RUNPATH_SEARCH_PATHS = ( 519 | "$(inherited)", 520 | "@executable_path/Frameworks", 521 | "@loader_path/Frameworks", 522 | ); 523 | PRODUCT_BUNDLE_IDENTIFIER = maxvol.RxAVFoundationTests; 524 | PRODUCT_NAME = "$(TARGET_NAME)"; 525 | SWIFT_VERSION = 5.0; 526 | TARGETED_DEVICE_FAMILY = "1,2"; 527 | }; 528 | name = Release; 529 | }; 530 | /* End XCBuildConfiguration section */ 531 | 532 | /* Begin XCConfigurationList section */ 533 | 94DF2740215CA8A300051F68 /* Build configuration list for PBXProject "RxAVFoundation" */ = { 534 | isa = XCConfigurationList; 535 | buildConfigurations = ( 536 | 94DF2758215CA8A400051F68 /* Debug */, 537 | 94DF2759215CA8A400051F68 /* Release */, 538 | ); 539 | defaultConfigurationIsVisible = 0; 540 | defaultConfigurationName = Release; 541 | }; 542 | 94DF275A215CA8A400051F68 /* Build configuration list for PBXNativeTarget "RxAVFoundation" */ = { 543 | isa = XCConfigurationList; 544 | buildConfigurations = ( 545 | 94DF275B215CA8A400051F68 /* Debug */, 546 | 94DF275C215CA8A400051F68 /* Release */, 547 | ); 548 | defaultConfigurationIsVisible = 0; 549 | defaultConfigurationName = Release; 550 | }; 551 | 94DF275D215CA8A400051F68 /* Build configuration list for PBXNativeTarget "RxAVFoundationTests" */ = { 552 | isa = XCConfigurationList; 553 | buildConfigurations = ( 554 | 94DF275E215CA8A400051F68 /* Debug */, 555 | 94DF275F215CA8A400051F68 /* Release */, 556 | ); 557 | defaultConfigurationIsVisible = 0; 558 | defaultConfigurationName = Release; 559 | }; 560 | /* End XCConfigurationList section */ 561 | }; 562 | rootObject = 94DF273D215CA8A300051F68 /* Project object */; 563 | } 564 | -------------------------------------------------------------------------------- /RxAVFoundation.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RxAVFoundation.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /RxAVFoundation.xcodeproj/xcshareddata/xcschemes/RxAVFoundation.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /RxAVFoundation/AVCaptureSession+Rx.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AVCaptureSession+Rx.swift 3 | // RxAVFoundation 4 | // 5 | // Created by Maxim Volgin on 27/09/2018. 6 | // Copyright (c) RxSwiftCommunity. All rights reserved. 7 | // 8 | 9 | import os.log 10 | import AVFoundation 11 | #if !RX_NO_MODULE 12 | import RxSwift 13 | import RxCocoa 14 | #endif 15 | 16 | @available(iOS 10.0, *) 17 | extension Reactive where Base: AVCaptureSession { 18 | 19 | public func configure(preset: AVCaptureSession.Preset = .photo, captureDevice: AVCaptureDevice) { 20 | self.configure { session in 21 | session.sessionPreset = preset 22 | let deviceInput = try! AVCaptureDeviceInput(device: captureDevice) 23 | session.addInput(deviceInput) 24 | } 25 | } 26 | 27 | public func startRunning() { 28 | Queue.session.async { 29 | self.base.startRunning() 30 | } 31 | } 32 | 33 | public func stopRunning() { 34 | Queue.session.async { 35 | self.base.stopRunning() 36 | } 37 | } 38 | 39 | public func medatataCaptureOutput(metadataObjectTypes: [AVMetadataObject.ObjectType]) -> Observable { 40 | let metadataOutput = AVCaptureMetadataOutput() 41 | let metadataCaptureDelegate = RxAVCaptureMetadataOutputObjectsDelegate() 42 | let metadataCaptureOutput: Observable = Observable 43 | .create { observer in 44 | metadataCaptureDelegate.observer = observer 45 | 46 | self.configure { session in 47 | if session.canAddOutput(metadataOutput) { 48 | session.addOutput(metadataOutput) 49 | 50 | metadataOutput.metadataObjectTypes = metadataObjectTypes 51 | 52 | } else { 53 | os_log("Could not add metadata output to the session", log: Log.meta, type: .error) 54 | observer.onError(RxAVFoundationError.cannotAddOutput(.meta)) 55 | } 56 | } 57 | 58 | return Disposables.create { 59 | self.configure { session in 60 | session.removeOutput(metadataOutput) 61 | } 62 | } 63 | } 64 | .subscribeOn(Scheduler.session) 65 | // .observeOn(Scheduler.dataOutput) 66 | return metadataCaptureOutput 67 | } 68 | 69 | @available(iOS 11.0, *) 70 | public func photoCaptureOutput(highResolution: Bool = true, depth: Bool = true) -> Observable { 71 | let photoOutput = AVCapturePhotoOutput() 72 | let photoCaptureDelegate = RxAVCapturePhotoCaptureDelegate() 73 | let photoCaptureOutput: Observable = Observable 74 | .create { observer in 75 | photoCaptureDelegate.observer = observer 76 | 77 | self.configure { session in 78 | if session.canAddOutput(photoOutput) { 79 | session.addOutput(photoOutput) 80 | 81 | photoOutput.isHighResolutionCaptureEnabled = highResolution 82 | 83 | if photoOutput.isDepthDataDeliverySupported { 84 | photoOutput.isDepthDataDeliveryEnabled = depth 85 | } 86 | } else { 87 | os_log("Could not add photo data output to the session", log: Log.photo, type: .error) 88 | observer.onError(RxAVFoundationError.cannotAddOutput(.photo)) 89 | } 90 | } 91 | 92 | return Disposables.create { 93 | self.configure { session in 94 | session.removeOutput(photoOutput) 95 | } 96 | } 97 | } 98 | .subscribeOn(Scheduler.session) 99 | // .observeOn(Scheduler.dataOutput) 100 | return photoCaptureOutput 101 | } 102 | 103 | public func videoCaptureOutput(orientation: AVCaptureVideoOrientation = .portrait, settings: [String : Any] = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32BGRA)]) -> Observable { 104 | let videoOutput = AVCaptureVideoDataOutput() 105 | let videoCaptureDelegate = RxAVCaptureVideoDataOutputSampleBufferDelegate() 106 | let videoCaptureOutput: Observable = Observable 107 | .create { observer in 108 | videoCaptureDelegate.observer = observer 109 | 110 | self.configure { session in 111 | videoOutput.videoSettings = settings 112 | videoOutput.setSampleBufferDelegate(videoCaptureDelegate, queue: Queue.dataOutput) 113 | session.addOutput(videoOutput) 114 | videoOutput.connections.first?.videoOrientation = orientation 115 | } 116 | 117 | return Disposables.create { 118 | self.configure { session in 119 | session.removeOutput(videoOutput) 120 | } 121 | } 122 | } 123 | .subscribeOn(Scheduler.session) 124 | // .observeOn(Scheduler.dataOutput) 125 | return videoCaptureOutput 126 | } 127 | 128 | @available(iOS 11.0, *) 129 | public func depthCaptureOutput(filteringEnabled: Bool = true) -> Observable { 130 | let depthOutput = AVCaptureDepthDataOutput() 131 | let depthCaptureDelegate = RxAVCaptureDepthDataOutputDelegate() 132 | let depthCaptureOutput: Observable = Observable 133 | .create { observer in 134 | depthCaptureDelegate.observer = observer 135 | 136 | self.configure { session in 137 | if session.canAddOutput(depthOutput) { 138 | session.addOutput(depthOutput) 139 | depthOutput.setDelegate(depthCaptureDelegate, callbackQueue: Queue.dataOutput) 140 | depthOutput.isFilteringEnabled = filteringEnabled 141 | if let connection = depthOutput.connection(with: .depthData) { 142 | connection.isEnabled = true 143 | } else { 144 | os_log("No AVCaptureConnection", log: Log.depth, type: .error) 145 | observer.onError(RxAVFoundationError.noConnection(.depth)) 146 | } 147 | } else { 148 | os_log("Could not add depth data output to the session", log: Log.depth, type: .error) 149 | observer.onError(RxAVFoundationError.cannotAddOutput(.depth)) 150 | } 151 | } 152 | 153 | return Disposables.create { 154 | self.configure { session in 155 | session.removeOutput(depthOutput) 156 | } 157 | } 158 | } 159 | .subscribeOn(Scheduler.session) 160 | // .observeOn(Scheduler.dataOutput) 161 | return depthCaptureOutput 162 | } 163 | 164 | @available(iOS 11.0, *) 165 | public func synchronizerOutput(dataOutputs: [AVCaptureOutput]) -> Observable { 166 | let outputSynchronizer = AVCaptureDataOutputSynchronizer(dataOutputs: dataOutputs) // TODO [videoDataOutput, depthDataOutput]) 167 | let synchronizerDelegate = RxAVCaptureDataOutputSynchronizerDelegate() 168 | let synchronizerOutput: Observable = Observable 169 | .create { observer in 170 | synchronizerDelegate.observer = observer 171 | 172 | self.configure { session in 173 | outputSynchronizer.setDelegate(synchronizerDelegate, queue: Queue.dataOutput) 174 | } 175 | 176 | return Disposables.create { 177 | // NOOP 178 | } 179 | } 180 | .subscribeOn(Scheduler.session) 181 | // .observeOn(Scheduler.dataOutput) 182 | return synchronizerOutput 183 | } 184 | 185 | public var outputs: Single<[AVCaptureOutput]> { 186 | get { 187 | return Single<[AVCaptureOutput]> 188 | .create { observer -> Disposable in 189 | observer(.success(self.base.outputs)) 190 | return Disposables.create() 191 | } 192 | .subscribeOn(Scheduler.session) 193 | } 194 | } 195 | 196 | // MARK: - private 197 | 198 | private func configure(lambda: (AVCaptureSession) -> Void) { 199 | self.base.beginConfiguration() 200 | lambda(self.base) 201 | self.base.commitConfiguration() 202 | } 203 | 204 | } 205 | -------------------------------------------------------------------------------- /RxAVFoundation/Global.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Global.swift 3 | // RxAVFoundation 4 | // 5 | // Created by Maxim Volgin on 14/10/2018. 6 | // Copyright (c) RxSwiftCommunity. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxSwift 11 | import os.log 12 | 13 | fileprivate let subsystem: String = Bundle.main.bundleIdentifier ?? "" 14 | 15 | @available(iOS 10.0, *) 16 | struct Log { 17 | static let meta = OSLog(subsystem: subsystem, category: "meta") 18 | static let photo = OSLog(subsystem: subsystem, category: "photo") 19 | static let video = OSLog(subsystem: subsystem, category: "video") 20 | static let depth = OSLog(subsystem: subsystem, category: "depth") 21 | static let synch = OSLog(subsystem: subsystem, category: "synch") 22 | } 23 | 24 | fileprivate struct Label { 25 | fileprivate static let session = "\(subsystem) session queue" 26 | fileprivate static let dataOutput = "\(subsystem) video data queue" 27 | fileprivate static let processing = "\(subsystem) photo processing queue" 28 | } 29 | 30 | @available(iOS 10.0, *) 31 | struct Queue { 32 | static let session = DispatchQueue(label: Label.session, attributes: [], autoreleaseFrequency: .workItem) 33 | static let dataOutput = DispatchQueue(label: Label.dataOutput, qos: .userInitiated, attributes: [], autoreleaseFrequency: .workItem) 34 | static let processing = DispatchQueue(label: Label.processing, attributes: [], autoreleaseFrequency: .workItem) 35 | } 36 | 37 | @available(iOS 10.0, *) 38 | struct Scheduler { 39 | static let session = SerialDispatchQueueScheduler(queue: Queue.session, internalSerialQueueName: Label.session) 40 | static let dataOutput = SerialDispatchQueueScheduler(queue: Queue.dataOutput, internalSerialQueueName: Label.dataOutput) 41 | static let processing = SerialDispatchQueueScheduler(queue: Queue.processing, internalSerialQueueName: Label.processing) 42 | } 43 | 44 | public enum RxAVCaptureOutputType: String { 45 | case meta = "meta" 46 | case photo = "photo" 47 | case video = "video" 48 | case depth = "depth" 49 | } 50 | 51 | public enum RxAVFoundationError: Error { 52 | case noConnection(RxAVCaptureOutputType) 53 | case cannotAddOutput(RxAVCaptureOutputType) 54 | } 55 | -------------------------------------------------------------------------------- /RxAVFoundation/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /RxAVFoundation/RxAVCaptureDataOutputSynchronizerDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RxAVCaptureDataOutputSynchronizerDelegate.swift 3 | // RxAVFoundation 4 | // 5 | // Created by Maxim Volgin on 13/10/2018. 6 | // Copyright (c) RxSwiftCommunity. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | #if !RX_NO_MODULE 11 | import RxSwift 12 | import RxCocoa 13 | #endif 14 | 15 | @available(iOS 11.0, *) 16 | public typealias SynchronizerOutput = (synchronizer: AVCaptureDataOutputSynchronizer, synchronizedDataCollection: AVCaptureSynchronizedDataCollection) 17 | 18 | @available(iOS 11.0, *) 19 | final class RxAVCaptureDataOutputSynchronizerDelegate: NSObject, AVCaptureDataOutputSynchronizerDelegate { 20 | 21 | typealias Observer = AnyObserver 22 | 23 | var observer: Observer? 24 | 25 | public func dataOutputSynchronizer(_ synchronizer: AVCaptureDataOutputSynchronizer, didOutput synchronizedDataCollection: AVCaptureSynchronizedDataCollection) { 26 | observer?.on(.next(SynchronizerOutput(synchronizer, synchronizedDataCollection))) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /RxAVFoundation/RxAVCaptureDepthDataOutputDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RxAVCaptureDepthDataOutputDelegate.swift 3 | // RxAVFoundation 4 | // 5 | // Created by Maxim Volgin on 13/10/2018. 6 | // Copyright (c) RxSwiftCommunity. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | #if !RX_NO_MODULE 11 | import RxSwift 12 | import RxCocoa 13 | #endif 14 | 15 | @available(iOS 11.0, *) 16 | public typealias DepthCaptureOutput = (depthDataOutput: AVCaptureDepthDataOutput, depthData: AVDepthData, timestamp: CMTime, connection: AVCaptureConnection) 17 | 18 | @available(iOS 11.0, *) 19 | final class RxAVCaptureDepthDataOutputDelegate: NSObject, AVCaptureDepthDataOutputDelegate { 20 | 21 | typealias Observer = AnyObserver 22 | 23 | var observer: Observer? 24 | 25 | public func depthDataOutput(_ depthDataOutput: AVCaptureDepthDataOutput, didOutput depthData: AVDepthData, timestamp: CMTime, connection: AVCaptureConnection) { 26 | observer?.on(.next(DepthCaptureOutput(depthDataOutput, depthData, timestamp, connection))) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /RxAVFoundation/RxAVCaptureMetadataOutputObjectsDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RxAVCaptureMetadataOutputObjectsDelegate.swift 3 | // RxAVFoundation 4 | // 5 | // Created by Maxim Volgin on 21/05/2019. 6 | // Copyright (c) RxSwiftCommunity. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | #if !RX_NO_MODULE 11 | import RxSwift 12 | import RxCocoa 13 | #endif 14 | 15 | @available(iOS 10.0, *) 16 | public typealias CaptureMetadataOutput = (output: AVCaptureMetadataOutput, metadataObjects: [AVMetadataObject], connection: AVCaptureConnection) 17 | 18 | @available(iOS 10.0, *) 19 | final class RxAVCaptureMetadataOutputObjectsDelegate: NSObject, AVCaptureMetadataOutputObjectsDelegate { 20 | 21 | typealias Observer = AnyObserver 22 | 23 | var observer: Observer? 24 | 25 | public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { 26 | observer?.on(.next(CaptureMetadataOutput(output, metadataObjects, connection))) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /RxAVFoundation/RxAVCapturePhotoCaptureDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RxAVCapturePhotoCaptureDelegate.swift 3 | // RxAVFoundation 4 | // 5 | // Created by Maxim Volgin on 13/10/2018. 6 | // Copyright (c) RxSwiftCommunity. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | #if !RX_NO_MODULE 11 | import RxSwift 12 | import RxCocoa 13 | #endif 14 | 15 | @available(iOS 11.0, *) 16 | public typealias PhotoCaptureOutput = (output: AVCapturePhotoOutput, photo: AVCapturePhoto, error: Error?) 17 | 18 | @available(iOS 11.0, *) 19 | final class RxAVCapturePhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate { 20 | 21 | typealias Observer = AnyObserver 22 | 23 | var observer: Observer? 24 | 25 | public func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { 26 | observer?.on(.next(PhotoCaptureOutput(output, photo, error))) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /RxAVFoundation/RxAVCaptureVideoDataOutputSampleBufferDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RxAVCaptureVideoDataOutputSampleBufferDelegate.swift 3 | // RxAVFoundation 4 | // 5 | // Created by Maxim Volgin on 13/10/2018. 6 | // Copyright (c) RxSwiftCommunity. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | #if !RX_NO_MODULE 11 | import RxSwift 12 | import RxCocoa 13 | #endif 14 | 15 | @available(iOS 10.0, *) 16 | public typealias VideoCaptureOutput = (output: AVCaptureOutput, sampleBuffer: CMSampleBuffer, connection: AVCaptureConnection) 17 | 18 | @available(iOS 10.0, *) 19 | final class RxAVCaptureVideoDataOutputSampleBufferDelegate: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate { 20 | 21 | typealias Observer = AnyObserver 22 | 23 | var observer: Observer? 24 | 25 | public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 26 | observer?.on(.next(VideoCaptureOutput(output, sampleBuffer, connection))) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /RxAVFoundation/RxAVFoundation.h: -------------------------------------------------------------------------------- 1 | // 2 | // RxAVFoundation.h 3 | // RxAVFoundation 4 | // 5 | // Created by Maxim Volgin on 27/09/2018. 6 | // Copyright (c) RxSwiftCommunity. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for RxAVFoundation. 12 | FOUNDATION_EXPORT double RxAVFoundationVersionNumber; 13 | 14 | //! Project version string for RxAVFoundation. 15 | FOUNDATION_EXPORT const unsigned char RxAVFoundationVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /RxAVFoundationTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /RxAVFoundationTests/RxAVFoundationTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RxAVFoundationTests.swift 3 | // RxAVFoundationTests 4 | // 5 | // Created by Maxim Volgin on 27/09/2018. 6 | // Copyright (c) RxSwiftCommunity. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import RxAVFoundation 11 | 12 | class RxAVFoundationTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | --------------------------------------------------------------------------------