Visit The School

Easily Record Video In A Swift iOS App

Alexander Paterson
|
Posted about 1 year ago
|
8 minutes
Easily Record Video In A Swift iOS App
The SCRecorder cocoapod makes a difficult task surprisingly easy

Full code can be found here.

If you've ever tried recording audio or video from the device's camera in an iOS app, you've probably had a bad time. As always, though, somebody else's open-source code can make your life a lot easier.

Here, I'm going to show you how to use a cocoapod called SCRecorder. It's a wonderful module but it's lacking proper documentation and I couldn't find an example that uses Swift. The app we'll build will simply record videos, play them back, and save them to the camera roll. 

Just a heads up: you're going to need to be able to run this on an actual iOS device to test it out.

Installing SCRecorder

First create a new Xcode project; just a simple single-view application. Then, create a file in the root of this application called Podfile. Give it the following contents.

platform :ios, '7.0'
use_frameworks!
pod 'SCRecorder'

The next step is to boot up a new Terminal session, move into the project directory, then run the command: pod install. If this doesn't work because you don't have cocoapods installed already, run the comand gem install cocoapods. The pod install command will install SCRecorder, and create a .xcworkspace file for us; open this file from finder, or with the command open *.xcworkspace. You must use this instead of the .xcodeproj file from now on.

Pod install trace

Setting Up Our View

Now in Main.storyboard, add a UIView in the default view controller with the following constraints (you should change the dimensions of the view controller for this):

New UIView

This UIView will preview the video as it records.

I'll also add four buttons, one label, and one UIView as follows. You should be able to figure out the constraints for yourself (center the buttons, and the UIView is 60pt wide/tall). The extra UIView will be where we can watch the video we have recorded.

Add Buttons

Next, we need to add some IBActions and IBOutlets to ViewController.swift. These should all be pretty self explanatory. The first UIView outlet listed below is the larger one.

New actions and outlets

Recording Video

We need to import SCRecorder at the top of ViewController.swift. We also need to add a couple of properties to this class; an instance of SCRecorder I'll call recorder, and an instance of SCRecordSession I'll call session. The SCRecordSession stores the video data, and the SCRecorder appends recording data to it.

import UIKit
import SCRecorder

class ViewController: UIViewController {
    
    let session = SCRecordSession()
    let recorder = SCRecorder()
    //...

We'll configure these in viewDidLoad and viewDidLayoutSubviews now:

override func viewDidLoad() {
    super.viewDidLoad()
    
    if (!recorder.startRunning()) {
        debugPrint("Recorder error: ", recorder.error)
    }
    
    recorder.session = session
    recorder.device = AVCaptureDevicePosition.Front
    recorder.videoConfiguration.size = CGSizeMake(800,800)
    recorder.delegate = self
}


override func viewDidLayoutSubviews() {
    recorder.previewView = previewView
}

The recorder.previewView setting will cause the live camera feed to show in our aptly named previewView outlet. You'll be getting an error now about ViewController not conforming to SCRecorderDelegate. We'll fix this with an extension so that our code stays neat. While we're at it, we'll write some code that controls the timer shown on the screen. Add the following below the ViewController class definition:

extension ViewController: SCRecorderDelegate {
    
    func recorder(recorder: SCRecorder, didAppendVideoSampleBufferInSession session: SCRecordSession) {
        updateTimeText(session)
    }
    
    func updateTimeText(session: SCRecordSession) {
        self.timeLabel.text = String(session.duration.seconds)
    }
}

Finally, let's fill in our actions:

@IBAction func recordButtonPress(sender: AnyObject) {
    recorder.record()
}

@IBAction func pauseButtonPress(sender: AnyObject) {
    recorder.pause()
}

@IBAction func backspaceButtonPress(sender: AnyObject) {
    if recorder.isRecording {
        recorder.pause()
        return
    }
    
    session.removeLastSegment()
    updateTimeText(session)
}

With this complete, you can now record video segments, and delete the last one with the backspace button. Currently, the only feedback is the timer, so let's implement some playback.

Playing Video

ViewController needs an SCPlayer property and some setup code in viewDidLayoutSubview, and we need to write the playButtonPress action. There's one problem though:  The code is as follows:

let player = SCPlayer()

@IBAction func playButtonPress(sender: AnyObject) {
    player.play()
}

override func viewDidLayoutSubviews() {
    recorder.previewView = previewView
    
    player.setItemByAsset(session.assetRepresentingSegments())
    let playerLayer = AVPlayerLayer(player: player)
    let bounds = playbackView.bounds
    playerLayer.frame = bounds
    playbackView.layer.addSublayer(playerLayer)
}

This was very laggy on my phone though, having the two videos on the screen at once; sometimes the playback video wouldn't appear. You might want to comment out the first line of viewDidLayoutSubviews while playing around.

You should have a pretty neat app at this point. Now let's save the video you record

Saving Videos

Add an extra button to ViewController with a corresponding IBAction called saveButtonPress. The code for saveButtonPress is as follows:

@IBAction func saveButtonPress(sender: AnyObject) {
    session.mergeSegmentsUsingPreset(AVAssetExportPresetHighestQuality) { (url, error) in
        if (error == nil) {
            url?.saveToCameraRollWithCompletion({ (path, error) in
                debugPrint(path, error)
            })
        } else {
            debugPrint(error)
        }
    }
}

And that's our video-recording app done; that easy. For more details about SCRecorder, check out the github repository.



ALEXANDER
PATERSON