diff --git a/ARVideoKit-Example.xcodeproj/project.pbxproj b/ARVideoKit-Example.xcodeproj/project.pbxproj index f9af394..09551f2 100644 --- a/ARVideoKit-Example.xcodeproj/project.pbxproj +++ b/ARVideoKit-Example.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ FB2E368C1FAE2A510035B8D6 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = FB2E368B1FAE2A510035B8D6 /* LICENSE */; }; + FB9B5D2E1FC49E3E005DDD60 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB9B5D2D1FC49E3E005DDD60 /* MainViewController.swift */; }; FBD3F1E61FB260B000327054 /* ARVideoKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBD3F1E51FB260B000327054 /* ARVideoKit.framework */; }; FBD3F1E71FB260B000327054 /* ARVideoKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FBD3F1E51FB260B000327054 /* ARVideoKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; FBDCC5E71FABDFC600E3184D /* Scene.sks in Resources */ = {isa = PBXBuildFile; fileRef = FBDCC5E51FABDFC500E3184D /* Scene.sks */; }; @@ -15,7 +16,7 @@ FBDCC60D1FABFE6A00E3184D /* SKViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBDCC60C1FABFE6A00E3184D /* SKViewController.swift */; }; FBDCC6401FAC2CD900E3184D /* art.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = FBDCC63F1FAC2CD900E3184D /* art.scnassets */; }; FBE134BA1FAAD3DD00BEC469 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBE134B91FAAD3DD00BEC469 /* AppDelegate.swift */; }; - FBE134BC1FAAD3DD00BEC469 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBE134BB1FAAD3DD00BEC469 /* ViewController.swift */; }; + FBE134BC1FAAD3DD00BEC469 /* SCNViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBE134BB1FAAD3DD00BEC469 /* SCNViewController.swift */; }; FBE134BF1FAAD3DD00BEC469 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FBE134BD1FAAD3DD00BEC469 /* Main.storyboard */; }; FBE134C11FAAD3DD00BEC469 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FBE134C01FAAD3DD00BEC469 /* Assets.xcassets */; }; FBE134C41FAAD3DD00BEC469 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FBE134C21FAAD3DD00BEC469 /* LaunchScreen.storyboard */; }; @@ -37,6 +38,7 @@ /* Begin PBXFileReference section */ FB2E368B1FAE2A510035B8D6 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + FB9B5D2D1FC49E3E005DDD60 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; FBD3F1E51FB260B000327054 /* ARVideoKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ARVideoKit.framework; path = Framework/ARVideoKit.framework; sourceTree = ""; }; FBDCC5E51FABDFC500E3184D /* Scene.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = Scene.sks; sourceTree = ""; }; FBDCC5E61FABDFC500E3184D /* Scene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scene.swift; sourceTree = ""; }; @@ -44,7 +46,7 @@ FBDCC63F1FAC2CD900E3184D /* art.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = art.scnassets; sourceTree = ""; }; FBE134B61FAAD3DD00BEC469 /* ARVideoKit-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ARVideoKit-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; FBE134B91FAAD3DD00BEC469 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - FBE134BB1FAAD3DD00BEC469 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + FBE134BB1FAAD3DD00BEC469 /* SCNViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SCNViewController.swift; sourceTree = ""; }; FBE134BE1FAAD3DD00BEC469 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; FBE134C01FAAD3DD00BEC469 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; FBE134C31FAAD3DD00BEC469 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -92,7 +94,8 @@ FBA0AA0D1FAD9E4B006C481B /* View Controllers */ = { isa = PBXGroup; children = ( - FBE134BB1FAAD3DD00BEC469 /* ViewController.swift */, + FB9B5D2D1FC49E3E005DDD60 /* MainViewController.swift */, + FBE134BB1FAAD3DD00BEC469 /* SCNViewController.swift */, FBDCC60C1FABFE6A00E3184D /* SKViewController.swift */, ); path = "View Controllers"; @@ -230,10 +233,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - FBE134BC1FAAD3DD00BEC469 /* ViewController.swift in Sources */, + FBE134BC1FAAD3DD00BEC469 /* SCNViewController.swift in Sources */, FBE134BA1FAAD3DD00BEC469 /* AppDelegate.swift in Sources */, FBDCC60D1FABFE6A00E3184D /* SKViewController.swift in Sources */, FBDCC5E81FABDFC600E3184D /* Scene.swift in Sources */, + FB9B5D2E1FC49E3E005DDD60 /* MainViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -371,7 +375,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = TB37P94YA8; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", @@ -392,7 +396,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = TB37P94YA8; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", diff --git a/ARVideoKit-Example/Storyboards/Base.lproj/Main.storyboard b/ARVideoKit-Example/Storyboards/Base.lproj/Main.storyboard index 6538553..a9aaab8 100644 --- a/ARVideoKit-Example/Storyboards/Base.lproj/Main.storyboard +++ b/ARVideoKit-Example/Storyboards/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -8,11 +8,79 @@ + + + Avenir-Black + Avenir-Medium + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -121,23 +189,23 @@ - + @@ -154,14 +222,14 @@ + - - + @@ -174,7 +242,7 @@ - + @@ -341,7 +409,7 @@ - + diff --git a/ARVideoKit-Example/View Controllers/MainViewController.swift b/ARVideoKit-Example/View Controllers/MainViewController.swift new file mode 100644 index 0000000..c3dd16b --- /dev/null +++ b/ARVideoKit-Example/View Controllers/MainViewController.swift @@ -0,0 +1,26 @@ +// +// MainViewController.swift +// ARVideoKit-Example +// +// Created by Ahmed Bekhit on 11/21/17. +// Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. +// + +import UIKit + +class MainViewController: UIViewController { + + @IBOutlet var skBtn: UIButton! + @IBOutlet var scnBtn: UIButton! + override func viewDidLoad() { + super.viewDidLoad() + skBtn.layer.cornerRadius = skBtn.bounds.height/2 + scnBtn.layer.cornerRadius = scnBtn.bounds.height/2 + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + +} diff --git a/ARVideoKit-Example/View Controllers/ViewController.swift b/ARVideoKit-Example/View Controllers/SCNViewController.swift similarity index 81% rename from ARVideoKit-Example/View Controllers/ViewController.swift rename to ARVideoKit-Example/View Controllers/SCNViewController.swift index 545a6c1..1d5f70b 100644 --- a/ARVideoKit-Example/View Controllers/ViewController.swift +++ b/ARVideoKit-Example/View Controllers/SCNViewController.swift @@ -11,12 +11,15 @@ import ARKit import ARVideoKit import Photos -class ViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, RecordARDelegate { +class SCNViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, RecordARDelegate { @IBOutlet var sceneView: ARSCNView! @IBOutlet var recordBtn: UIButton! @IBOutlet var pauseBtn: UIButton! + let recordingQueue = DispatchQueue(label: "recordingThread", attributes: .concurrent) + let caprturingQueue = DispatchQueue(label: "capturingThread", attributes: .concurrent) + var recorder:RecordAR? override func viewDidLoad() { @@ -46,7 +49,7 @@ class ViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, Rec recorder?.renderAR = self // Configure the renderer to perform additional image & video processing 👁 - //recorder?.onlyRenderWhileRecording = false + recorder?.onlyRenderWhileRecording = false // Configure ARKit content mode. Default is .auto //recorder?.contentMode = .aspectFit @@ -75,6 +78,12 @@ class ViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, Rec // Pause the view's session sceneView.session.pause() + if recorder?.status == .recording { + recorder?.stopAndExport() + } + recorder?.onlyRenderWhileRecording = true + recorder?.prepare(ARWorldTrackingConfiguration()) + // Switch off the orientation lock for UIViewControllers with AR Scenes recorder?.rest() } @@ -89,7 +98,7 @@ class ViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, Rec override var prefersStatusBarHidden: Bool { return true } - + // MARK: - Exported UIAlert present method func exportMessage(success: Bool, status:PHAuthorizationStatus) { if success { @@ -125,13 +134,17 @@ class ViewController: UIViewController, ARSCNViewDelegate, RenderARDelegate, Rec } //MARK: - Button Action Methods -extension ViewController { +extension SCNViewController { + @IBAction func goBack(_ sender: UIButton) { + self.dismiss(animated: true, completion: nil) + } + @IBAction func capture(_ sender: UIButton) { if sender.tag == 0 { //Photo if recorder?.status == .readyToRecord { - let image = recorder?.photo() - recorder?.export(UIImage: image) { saved, status in + let image = self.recorder?.photo() + self.recorder?.export(UIImage: image) { saved, status in if saved { // Inform user photo has exported successfully self.exportMessage(success: saved, status: status) @@ -141,16 +154,18 @@ extension ViewController { }else if sender.tag == 1 { //Live Photo if recorder?.status == .readyToRecord { - recorder?.livePhoto(export: true) { ready, photo, status, saved in - /* - if ready { - // Do something with the `photo` (PHLivePhotoPlus) - } - */ - - if saved { - // Inform user Live Photo has exported successfully - self.exportMessage(success: saved, status: status!) + caprturingQueue.async { + self.recorder?.livePhoto(export: true) { ready, photo, status, saved in + /* + if ready { + // Do something with the `photo` (PHLivePhotoPlus) + } + */ + + if saved { + // Inform user Live Photo has exported successfully + self.exportMessage(success: saved, status: status!) + } } } } @@ -180,7 +195,9 @@ extension ViewController { sender.setTitle("Stop", for: .normal) pauseBtn.setTitle("Pause", for: .normal) pauseBtn.isEnabled = true - recorder?.record() + recordingQueue.async { + self.recorder?.record() + } }else if recorder?.status == .recording { sender.setTitle("Record", for: .normal) pauseBtn.setTitle("Pause", for: .normal) @@ -200,14 +217,16 @@ extension ViewController { pauseBtn.setTitle("Pause", for: .normal) pauseBtn.isEnabled = false recordBtn.isEnabled = false - recorder?.record(forDuration: 10) { path in - self.recorder?.export(video: path) { saved, status in - DispatchQueue.main.sync { - sender.setTitle("w/Duration", for: .normal) - self.pauseBtn.setTitle("Pause", for: .normal) - self.pauseBtn.isEnabled = false - self.recordBtn.isEnabled = true - self.exportMessage(success: saved, status: status) + recordingQueue.async { + self.recorder?.record(forDuration: 10) { path in + self.recorder?.export(video: path) { saved, status in + DispatchQueue.main.sync { + sender.setTitle("w/Duration", for: .normal) + self.pauseBtn.setTitle("Pause", for: .normal) + self.pauseBtn.isEnabled = false + self.recordBtn.isEnabled = true + self.exportMessage(success: saved, status: status) + } } } } @@ -238,7 +257,7 @@ extension ViewController { } //MARK: - ARVideoKit Delegate Methods -extension ViewController { +extension SCNViewController { func frame(didRender buffer: CVPixelBuffer, with time: CMTime, using rawBuffer: CVPixelBuffer) { // Do some image/video processing. } diff --git a/ARVideoKit-Example/View Controllers/SKViewController.swift b/ARVideoKit-Example/View Controllers/SKViewController.swift index 9b2e818..970b2c2 100644 --- a/ARVideoKit-Example/View Controllers/SKViewController.swift +++ b/ARVideoKit-Example/View Controllers/SKViewController.swift @@ -17,6 +17,9 @@ class SKViewController: UIViewController, ARSKViewDelegate, RenderARDelegate, Re @IBOutlet var recordBtn: UIButton! @IBOutlet var pauseBtn: UIButton! + let recordingQueue = DispatchQueue(label: "recordingThread") + let caprturingQueue = DispatchQueue(label: "capturingThread", attributes: .concurrent) + var recorder:RecordAR? override func viewDidLoad() { @@ -46,7 +49,7 @@ class SKViewController: UIViewController, ARSKViewDelegate, RenderARDelegate, Re recorder?.renderAR = self // Configure the renderer to perform additional image & video processing 👁 - //recorder?.onlyRenderWhileRecording = false + recorder?.onlyRenderWhileRecording = false // Set the UIViewController orientations recorder?.inputViewOrientations = [.landscapeLeft, .landscapeRight, .portrait] @@ -74,6 +77,12 @@ class SKViewController: UIViewController, ARSKViewDelegate, RenderARDelegate, Re // Pause the view's session SKSceneView.session.pause() + if recorder?.status == .recording { + recorder?.stopAndExport() + } + recorder?.onlyRenderWhileRecording = true + recorder?.prepare(ARWorldTrackingConfiguration()) + // Switch off the orientation lock for UIViewControllers with AR Scenes recorder?.rest() } @@ -132,8 +141,8 @@ extension SKViewController { if sender.tag == 0 { //Photo if recorder?.status == .readyToRecord { - let image = recorder?.photo() - recorder?.export(UIImage: image) { saved, status in + let image = self.recorder?.photo() + self.recorder?.export(UIImage: image) { saved, status in if saved { // Inform user photo has exported successfully self.exportMessage(success: saved, status: status) @@ -143,16 +152,18 @@ extension SKViewController { }else if sender.tag == 1 { //Live Photo if recorder?.status == .readyToRecord { - recorder?.livePhoto(export: true) { ready, photo, status, saved in - /* - if ready { - // Do something with the `photo` (PHLivePhotoPlus) - } - */ - - if saved { - // Inform user Live Photo has exported successfully - self.exportMessage(success: saved, status: status!) + caprturingQueue.async { + self.recorder?.livePhoto(export: true) { ready, photo, status, saved in + /* + if ready { + // Do something with the `photo` (PHLivePhotoPlus) + } + */ + + if saved { + // Inform user Live Photo has exported successfully + self.exportMessage(success: saved, status: status!) + } } } } @@ -182,7 +193,9 @@ extension SKViewController { sender.setTitle("Stop", for: .normal) pauseBtn.setTitle("Pause", for: .normal) pauseBtn.isEnabled = true - recorder?.record() + recordingQueue.async { + self.recorder?.record() + } }else if recorder?.status == .recording { sender.setTitle("Record", for: .normal) pauseBtn.setTitle("Pause", for: .normal) @@ -202,14 +215,16 @@ extension SKViewController { pauseBtn.setTitle("Pause", for: .normal) pauseBtn.isEnabled = false recordBtn.isEnabled = false - recorder?.record(forDuration: 10) { path in - self.recorder?.export(video: path) { saved, status in - DispatchQueue.main.sync { - sender.setTitle("w/Duration", for: .normal) - self.pauseBtn.setTitle("Pause", for: .normal) - self.pauseBtn.isEnabled = false - self.recordBtn.isEnabled = true - self.exportMessage(success: saved, status: status) + recordingQueue.async { + self.recorder?.record(forDuration: 10) { path in + self.recorder?.export(video: path) { saved, status in + DispatchQueue.main.sync { + sender.setTitle("w/Duration", for: .normal) + self.pauseBtn.setTitle("Pause", for: .normal) + self.pauseBtn.isEnabled = false + self.recordBtn.isEnabled = true + self.exportMessage(success: saved, status: status) + } } } }