ARKit · · 8 min read

Recording ARKit Videos & Animated GIFs Using ARVideoKit

Recording ARKit Videos & Animated GIFs Using ARVideoKit

Mobile augmented reality has been a trend recently and it’s been implemented in many applications to provide more interactive, fun experiences to share with people. Hence, major augmented reality frameworks, such as ARKit, enable developers to easily implement complex computer vision features into their apps and make AR a reality on mobile 😉.

However, ARKit and similar frameworks do not simplify the process of recording videos with augmented reality components, although users LOVE sharing their funny experiences while using augmented reality features (referring to face filters & trends like the AR hot dog), which led developers to go with alternative solutions such as screen record or screenshots.

In this tutorial, we will demonstrate how to record videos and GIFs that contain augmented reality components without the use of screen record or screenshots. To do so, we will be using a framework built specifically to simplify the process of rendering and recording ARKit videos, called ARVideoKit. This framework is built using Apple’s ARKit, AVFoundation, Metal and CoreMedia to take away the complex parts of rendering an ARSCNView or ARSKView content with the device’s camera stream.

Let’s Get Started!

To begin, we will first download the latest release of ARVideoKit by going to the repository releases page and download Framework.zip file.

Download ARVideoKit

Then we will create a new ARKit project on Xcode. For this tutorial, we are creating ARKit + SpriteKit project.

Create Xcode Project

When the project is created, Xcode will automatically generate a sample SpriteKit code to use. Although it’s good for a demo, but we will modify it a little bit to add our user interface, video recorder, GIF recorder, and display more different emojis 😇!

Adding the Framework

We will start off by adding ARVideoKit to our project! To add the framework properly, do the following steps:

  1. Create a folder in your project folder called Frameworks.
  2. Copy the downloaded ARVideoKit.framework into the Frameworks folder
  3. copy_framework

  4. Drag ARVideoKit.framework into your project target’s embedded binaries. Make sure to check “Copy items if needed”.
  5. add-arkitvideo-framework

Now let’s configure the framework in our application delegate, by taking the following steps:

  1. Import ARVideoKit in AppDelegate.swift by adding the following statement:
  2. import ARVideoKit
    
  3. Add the following method in AppDelegate.swift class to allow recording videos & GIFs in different orientations.
  4. func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return ViewAR.orientation
    }
    

Your application delegate file should look like this:

import UIKit
import ARVideoKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }

    
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return ViewAR.orientation
    }

}

Adding User Interface

We will build the user interface programmatically instead of using Interface Builder. To keep things simple, we will create 3 simple buttons: Record/Stop, Pause/Resume, and Capture GIFs.

To do that, declare the following properties in ViewController class:

// Recorder UIButton. This button will start and stop a video recording.
var recorderButton:UIButton = {
    let btn = UIButton(type: .system)
    btn.setTitle("Record", for: .normal)
    btn.setTitleColor(.black, for: .normal)
    btn.backgroundColor = .white
    btn.frame = CGRect(x: 0, y: 0, width: 110, height: 60)
    btn.center = CGPoint(x: UIScreen.main.bounds.width/2, y: UIScreen.main.bounds.height*0.90)
    btn.layer.cornerRadius = btn.bounds.height/2
    btn.tag = 0
    return btn
}()

// Pause UIButton. This button will pause a video recording.
var pauseButton:UIButton = {
    let btn = UIButton(type: .system)
    btn.setTitle("Pause", for: .normal)
    btn.setTitleColor(.black, for: .normal)
    btn.backgroundColor = .white
    btn.frame = CGRect(x: 0, y: 0, width: 60, height: 60)
    btn.center = CGPoint(x: UIScreen.main.bounds.width*0.15, y: UIScreen.main.bounds.height*0.90)
    btn.layer.cornerRadius = btn.bounds.height/2
    btn.alpha = 0.3
    btn.isEnabled = false
    return btn
}()

// GIF UIButton. This button will capture a GIF image.
var gifButton:UIButton = {
    let btn = UIButton(type: .system)
    btn.setTitle("GIF", for: .normal)
    btn.setTitleColor(.black, for: .normal)
    btn.backgroundColor = .white
    btn.frame = CGRect(x: 0, y: 0, width: 60, height: 60)
    btn.center = CGPoint(x: UIScreen.main.bounds.width*0.85, y: UIScreen.main.bounds.height*0.90)
    btn.layer.cornerRadius = btn.bounds.height/2
    return btn
}()

Next, add the buttons as subviews of the View Controller. Insert the following lines of code in the viewDidLoad() method:

self.view.addSubview(recorderButton)
self.view.addSubview(pauseButton)
self.view.addSubview(gifButton)

In order to handle the button actions, we then create three action methods:

// Record and stop method
@objc func recorderAction(sender:UIButton) {
        
}
// Pause and resume method  
@objc func pauseAction(sender:UIButton) {
    
}
// Capture GIF method
@objc func gifAction(sender:UIButton) {

}

Now, back in viewDidLoad(), add buttons’ targets and connect them to the methods created above:

recorderButton.addTarget(self, action: #selector(recorderAction(sender:)), for: .touchUpInside)
pauseButton.addTarget(self, action: #selector(pauseAction(sender:)), for: .touchUpInside)
gifButton.addTarget(self, action: #selector(gifAction(sender:)), for: .touchUpInside)

Before we moving to the next section, let’s run the app and see what you’ve built so far. If you’ve followed me correctly, you will have a simple ARKit app with three buttons on screen. Remember that you have to test the app on a real device instead of the simulator.

arkit-demo-withbutton

Implementing the ARVideoKit Framework

Now it’s time to enable the recording feature! We will implement the ARVideoKit framework into ViewController.swift. The very first step is to import the framework:

import ARVideoKit

Next, create a variable of the type RecordAR. RecordAR is an ARView sub-class that renders an ARSCNView or ARSKView content with the device’s camera stream to generate a video, photo, live photo or GIF.

var recorder: RecordAR?

In the viewDidLoad() method, initialize RecordAR with ARSKView and specify the supported orientations:

// Initialize with SpriteKit scene
recorder = RecordAR(ARSpriteKit: sceneView)

// Specifiy supported orientations
recorder?.inputViewOrientations = [.portrait, .landscapeLeft, .landscapeRight]

To prepare the recorder, insert the following statement in the viewWillAppear(_ animated: Bool) method:

recorder?.prepare(configuration)

Lastly, to “rest” the recorder when the view disappears, insert the following line of code in the viewWillDisappear(_ animated: Bool) method:

recorder?.rest()

Developing the Record/Stop and Pause/Resume Functions

Now that the preparation of the RecordAR variable is ready, let’s move on to the implementation of record and stop features.

For the recording action method, update the method like this:

@objc func recorderAction(sender:UIButton) {
    
    if recorder?.status == .readyToRecord {
        // Start recording
        recorder?.record()
        
        // Change button title
        sender.setTitle("Stop", for: .normal)
        sender.setTitleColor(.red, for: .normal)
        
        // Enable Pause button
        pauseButton.alpha = 1
        pauseButton.isEnabled = true
        
        // Disable GIF button
        gifButton.alpha = 0.3
        gifButton.isEnabled = false
    }else if recorder?.status == .recording || recorder?.status == .paused {
        // Stop recording and export video to camera roll
        recorder?.stopAndExport()
        
        // Change button title
        sender.setTitle("Record", for: .normal)
        sender.setTitleColor(.black, for: .normal)
        
        // Enable GIF button
        gifButton.alpha = 1
        gifButton.isEnabled = true
        
        // Disable Pause button
        pauseButton.alpha = 0.3
        pauseButton.isEnabled = false
    }
    
}

In the block of code above, we are checking if the video recorder status is ready to record. The app would start recording a video of your ARKit scene. Otherwise, if the recorder is currently recording or paused, the app would stop the video recorder and export the fully rendered video to the camera roll.

Next, we will implement the pause/resume feature into the pauseAction(sender:UIButton) method, by update the pauseAction method like this:

@objc func pauseAction(sender:UIButton) {
    if recorder?.status == .recording {
        // Pause recording
        recorder?.pause()
        
        // Change button title
        sender.setTitle("Resume", for: .normal)
        sender.setTitleColor(.blue, for: .normal)
    } else if recorder?.status == .paused {
        // Resume recording
        recorder?.record()
        
        // Change button title
        sender.setTitle("Pause", for: .normal)
        sender.setTitleColor(.black, for: .normal)
    }
}

The block of code above is pretty straight forward. We first check if the recorder is currently in the recording state. Then the app will pause the video when the user selects the pause button. Otherwise, it resumes recording.

Now we have something to test! Before running the application on your iOS device, we need to make sure to add the usage description of the camera, microphone, and photo library in the app’s Info.plist.

To do so, add the following to the plist source code:

NSCameraUsageDescription
AR Camera
NSPhotoLibraryAddUsageDescription
Export AR Media
NSPhotoLibraryUsageDescription
Export AR Media
NSMicrophoneUsageDescription
Audiovisual Recording

Alternatively, you can add the properties using the Property Editor:

infoPlistUsage

Now let’s run it!!! 📲🎊 Tap to record button and start recording your AR video.

Capture GIFs

Finally, let’s implement the GIFs function so that you can capture animated GIFs. Update the gifAction method like this:

    @objc func gifAction(sender:UIButton) {
        self.gifButton.isEnabled = false
        self.gifButton.alpha = 0.3
        self.recorderButton.isEnabled = false
        self.recorderButton.alpha = 0.3

        recorder?.gif(forDuration: 1.5, export: true) { _, _, _ , exported in
            if exported {
                DispatchQueue.main.sync {
                    self.gifButton.isEnabled = true
                    self.gifButton.alpha = 1.0
                    self.recorderButton.isEnabled = true
                    self.recorderButton.alpha = 1.0
                }
            }
        }
    }

Modifying the SpriteKit Content

In this final part we will modify the SpriteKit content to show some different emojis in the AR space 🤗🤓🧐🔥.

We will first create a variable that returns a random emoji from an array of emojis. By using the C-based arc4random_uniform() function, we will be able to retrieve a random number from 0 to the count of the array.

To do so, create the following variable as a global variable (place it after gifButton) in the ViewController class:

var randoMoji: String {
    let emojis = ["👾", "🤓", "🔥", "😜", "😇", "🤣", "🤗", "🧐", "🛰", "🚀"]
    return emojis[Int(arc4random_uniform(UInt32(emojis.count)))]
}

Next, edit the view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? method like this:

func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
    // Create and configure a node for the anchor added to the view's session.
    let labelNode = SKLabelNode(text: randoMoji)
    labelNode.horizontalAlignmentMode = .center
    labelNode.verticalAlignmentMode = .center
    return labelNode;
}

We just replace the static text of the SKLabelNode with the newly created randoMoji.

That’s it! Have Fun

You can now run the application on your device and use it to record ARKit videos and GIFs! To download the full project, you can download it on GitHub.

ARKit+SpriteKit-GIF

What do you thing about this tutorial? Please leave me comment below and share your thought.

Read next