Codable Tech Blog

iPhoneアプリケーション開発と AWS(Amazon Web Service)活用に関する記事を配信

AVFoundationを利用してカメラが取り込んだデータを表示する

ユースケース

iOSでは写真を撮影するためのフレームワークとしてiOSでは「UIImagePickerController」が用意されています。単純にカメラの機能を利用したいだけであればUIImagePickerControllerを利用するだけで充分です。しかし、UIImagePickerControllerではカメラに対するカスタマイズがあまり出来ません。カメラ機能に対して柔軟なカスタマイズを行いたいならAVFoundationフレームワークの使用を検討する必要があります。ただし、AVFoundationはUIImagePickerControllerと比較して非常に複雑な開発工程を踏む必要があります。

AVFoundationの構成

AVFoundationフレームワークは大きく2つに分かれます。ビデオまわりのAPIとオーディオに関係するAPIです。今回はビデオまわりのAPIのみを確認していきます。

AVFoundationを利用してカメラが写している風景を表示するために必要なクラス

AVFoundationを利用したカメラ映像の描画を行うためには以下に示す4つのクラスをうまく組み合わせて利用する必要があります。
f:id:codable:20171030102925p:plain

上図はAV Foundationプログラミングより引用

AVCaptureSession

キャプチャセッションはデバイスの入力と出力の橋渡しを行うクラスです。入力されたデータをどこに出力するのかを管理してくれます。

AVCaptureDeviceInput

AVCaptureDeviceInputはカメラなどの物理デバイスのインターフェースを提供してくれるクラスです。

AVCaptureXXXOutput

キャプチャセッションからの出力をキャプチャするために利用するクラスです。

AVCapturePreviewLayer

カメラがキャプチャしているものを表示するためのクラスです。

サンプルコード

以上のクラスを組み合わせてカメラが取り込んだデータを表示するができます。以下のコードはこれらのクラスを組み合わせてカメラが写している映像を表示するためのサンプルコードです。

class ViewController: UIViewController {

    var previewLayer: AVCaptureVideoPreviewLayer?

    enum CameraError : Error {
        case noCamerasAvailable
    }
    
    func defaultDevice() throws -> AVCaptureDevice{
        if let device = AVCaptureDevice.default(.builtInDualCamera, for: .video, position: .back) {
            return device
        } else if let device =  AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back){
            return device
        } else {
            throw CameraError.noCamerasAvailable
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 1. capture sessionの生成
        let session:AVCaptureSession = AVCaptureSession()
    
        do{
            // 2. カメラデバイスの取得
            let cameraDevice:AVCaptureDevice = try defaultDevice()
            
            // 3. カメラデバイスからDeviceInputの作成
            let cameraInput:AVCaptureDeviceInput = try AVCaptureDeviceInput(device:cameraDevice)

            // 4. セッションにDeviceInputを接続
            if session.canAddInput(cameraInput){
                session.addInput(cameraInput)
            }
            
            // 5. イメージをキャプチャするためのAVCaputureOutputを作成
            let imageOutput:AVCapturePhotoOutput = AVCapturePhotoOutput()

            // 6. セッションにOutputを接続
            if session.canAddOutput(imageOutput){
                session.addOutput(imageOutput)
            }
            
            // 7. セッションを開始してデータ転送を開始する
            session.startRunning()
        }catch{
            print(error)
        }
        
        //セッションに流れているデータを表示する
        //カメラデバイスから取り込んだデータを表示する時はAVCaptureVideoPreviewLayerを使用する
        self.previewLayer = AVCaptureVideoPreviewLayer(session: session)
        self.previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
        self.previewLayer?.connection?.videoOrientation = .portrait
        self.previewLayer?.frame = view.frame
        self.view.layer.addSublayer(self.previewLayer!)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

Github URL

github.com