[iOS 10] iOS 10以降のAVFoundationでの撮影方法

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

AVFoundation

こんにちは!
モバイルアプリサービス部の田中孝明です。

iOSアプリで写真を撮る場合、UIImagePickerControllerを用いる方法がありますが、AR等、他のViewをOverlayしたい場合、できることが限られるためAVFoundationを使ってカメラからの写真データを使って加工することが常套手段でした。

しかし、iOS 9から写真データ取得に使っていたAVCaptureStillImageOutputdeprecatedになり、代わりにiOS 10から追加されたAVCapturePhotoOutputを使うようになりました。

今回はAVCapturePhotoOutputを使った写真データ取得をやってみたいと思います。

AVCaptureSessionの設定

今回利用するクラスはキャプチャに関する入出力を管理するクラスのAVCaptureSessionと、キャプチャした映像をプレビューするAVCaptureVideoPreviewLayerと、そして写真データを取得するAVCapturePhotoOutputです。

private var session: AVCaptureSession?
private var videoPreviewLayer: AVCaptureVideoPreviewLayer?
private var stillImageOutput: AVCapturePhotoOutput?


AVCaptureSessionAVCaptureVideoPreviewLayerを設定します。
こちらはiOS 9までの方法と差異はありません。

session = AVCaptureSession()            
session?.sessionPreset = AVCaptureSessionPresetPhoto
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: session)

guard let _videoPreviewLayer = videoPreviewLayer else { return }

_videoPreviewLayer.masksToBounds = true
_videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill

videoPreviewView.layer.addSublayer(_videoPreviewLayer)

let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
let input = try! AVCaptureDeviceInput(device: device)            
session?.addInput(input)


AVCaptureSessionの出力にAVCaptureStillImageOutputを設定していた処理がAVCapturePhotoOutputに置き換わります。

stillImageOutput = AVCapturePhotoOutput()
session?.addOutput(stillImageOutput)


AVCapturePhotoOutputでの撮影

AVCapturePhotoOutputcapturePhoto(with settings: AVCapturePhotoSettings, delegate: AVCapturePhotoCaptureDelegate)メソッドをコールすることでキャプチャ先から撮影データを取得することができます。
AVCapturePhotoSettingsは撮影データに関する設定が色々できそうですので、別の機会で説明できればと思います!

func takePhoto() {
    let settingsForMonitoring = AVCapturePhotoSettings()
    settingsForMonitoring.flashMode = .auto
    settingsForMonitoring.isAutoStillImageStabilizationEnabled = true
    settingsForMonitoring.isHighResolutionPhotoEnabled = false

    stillImageOutput?.capturePhoto(with: settingsForMonitoring, delegate: self)
}


撮影データの結果に関してはAVCapturePhotoCaptureDelegateのデリゲートメソッドに通知されます。撮影データを加工したり、アルバムに保存したりする場合はこちらで行います。

// MARK: - AVCapturePhotoCaptureDelegate
extension ViewController: AVCapturePhotoCaptureDelegate {

    func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {

        // did receive photo data
    }
}


まとめ

AVFoundationを使ったカメラアプリは歴史が古く、独自でライブラリを組まれている方も多いと思います。
AVCaptureStillImageOutputdeprecatedになったタイミングでSwift 3.0への移行も兼ねて新設するのもいいのではないでしょうか?

参考文献

AVCapturePhotoOutput - Beyond the Basics
AVCapturePhotoOutput
AVCapturePhotoSettings