📹

AVFoundationを使用してビデオ撮影アプリを開発する

6 min read


AVFoundationを使用してビデオ撮影アプリを開発する方法について書きます。前回の記事で開発した写真撮影機能アプリに対して、ビデオ撮影機能を追加する形で解説していきます。iPhoneのカメラを立ち上げて画面にカメラの映像を表示するまでの処理は上記記事で解説していますので必要に応じてご参照ください。本記事のサンプルコードは以下に置いています。

https://github.com/NAOYA-MAEDA-DEV/AVFoundation-Camera-App

アクセス権の確認

前回の記事でアプリからカメラやマイクといったiPhoneのデバイス、フォトライブラリや連絡先といったユーザデータへアクセスする時は、Info.plistの編集アクセス権の確認を行う処理をコードで記述する必要があると解説しました。今回はビデオ撮影にiPhoneのマイクを使用しますので、Info.plistの編集アクセス権の確認を追記しています。

Info.plistの編集

iPhoneのマイクを使用するために以下の項目を追加します。

  • マイクへのアクセス権 (Privacy - Microphone Usage Description)

アクセス権の確認

以下のコードではiPhoneのカメラ、フォトライブラリ、iPhoneのマイクへのアクセス権を確認するアラートを表示しています。

CameraViewController.swift
private func checkPermission() {
    // カメラ
    switch AVCaptureDevice.authorizationStatus(for: .video) {
    case .authorized:
        break
    case .notDetermined:
        AVCaptureDevice.requestAccess(for: .video, completionHandler: { granted in
            if !granted {
              self.setupResult = .notAuthorized
            }
        })
    default:
        self.setupResult = .notAuthorized
        break
    }
    // フォトライブラリ
    switch PHPhotoLibrary.authorizationStatus() {
    case .authorized:
        break
    case .notDetermined:
        PHPhotoLibrary.requestAuthorization({ photoAuthStatus in
            if photoAuthStatus ==  PHAuthorizationStatus.authorized {
            }
        })
    default :
        break
    }
    // マイク
    switch AVCaptureDevice.authorizationStatus(for: .audio) {
    case .authorized:
        break
                
    case .notDetermined:
        self.sessionQueue.suspend()
        AVCaptureDevice.requestAccess(for: .audio, completionHandler: { granted in
            if !granted {
             }
             self.sessionQueue.resume()
        })
                
    default:
        break
    }
}

カメラの再設定

ビデオ撮影に必要な設定項目は前回の記事「カメラ設定とカメラ映像の表示」で実施したことに加えて以下の5つです。

  1. iPhoneのマイク(AVCaptureDevice)を取得
  2. AVCaptureDeviceを使用してAVCaptureDeviceInputを生成
  3. AVCaptureSessionAVCaptureDeviceInputをセット
  4. AVCaptureSessionAVCaptureOutput(AVCaptureMovieFileOutput)をセット
  5. AVCaptureSessionからAVCapturephotoOutputを削除

前回の記事で写真撮影を行うためにAVCaptureSessionに対して入力ソースはiPhoneのバックカメラ、出力タイプは写真をセットしていました。ビデオ撮影を行うために入力ソースはiPhoneのバックカメラに加えてiPhoneのマイク、出力タイプはムービー(AVCaptureMovieFileOutput)をセットします。また、写真出力タイプ(AVCapturePhotoOutput)は不要になるので、removeOutputメソッドでAVCaptureSessionから取り除きます。

CameraViewController.swift
private func chageVideoMode() {
    self.captureSession.beginConfiguration()
    // 1. iPhoneのマイク(AVCaptureDevice)を取得
    if let audioDevice = AVCaptureDevice.default(for: .audio) {
        do {
	    // 2. AVCaptureDeviceを使用してAVCaptureDeviceInputを生成
            let input = try AVCaptureDeviceInput(device: audioDevice)
	    // 3. AVCaptureSessionにAVCaptureDeviceInputをセット
            if self.captureSession.canAddInput(input) {
                self.captureSession.addInput(input)
                self.audioDeviceInput = input
            }
        } catch {
            print("Error input audio device to capture session : \(error)")
        }
    }
    // 4. AVCaptureSessionにAVCaptureOutputをセット
    if self.captureSession.canAddOutput(self.movieFileOutput) {
        self.captureSession.addOutput(self.movieFileOutput)
    }
    // 5. AVCaptureSessionからphotoOutputを削除
    self.captureSession.removeOutput(self.photoOutput)
    self.captureSession.commitConfiguration()
}

AVCaptureSessionの入力と出力を変更する時は、変更前にbeginConfiguration()、変更完了後にcommitConfiguration()を必ず実行する必要があります。

ビデオ撮影の開始

AVCaptureMovieFileOutputstartRecordingメソッドを実行するとビデオ撮影が開始します。startRecordingメソッドの引数にビデオを一時的に保存するパスと、ビデオの保存が完了した時にコールされるデリゲートメソッドの移譲先を指定します。移譲先はselfつまり以下のコードを記述したViewControllerを指定しています。

CameraViewController.swift
let tempDirectory: URL = URL(fileURLWithPath: NSTemporaryDirectory())
let fileURL: URL = tempDirectory.appendingPathComponent("sample.mov")
self.movieFileOutput.startRecording(to: fileURL, recordingDelegate: self)

ビデオ撮影で使用するデリゲートメソッド

ビデオ撮影開始から終了までの間にいくつかのデリゲートメソッドがコールされますが、使用するデリゲートメソッドは以下の1つです。

  • fileOutput(_:didFinishRecordingTo:from:error:)

前項でデリゲートの移譲先をselfに指定しました。上記デリゲートメソッドをViewController内に記述する為に、移譲先のViewControllerAVCaptureFileOutputRecordingDelegateプロトコルに準拠する必要があります。

ビデオ撮影のハンドリング処理

ビデオ撮影の終了

AVCaptureMovieFileOutputstopRecordingメソッドを実行するとビデオ撮影が終了します。

CameraViewController.swift
self.movieFileOutput.stopRecording()

撮影したビデオの保存

ビデオの出力が完了したタイミングで、デリゲートメソッドfileOutput(_:didFinishRecordingTo:from:error:)がコールされます。引数のurlは撮影したビデオが保存されているパスです。PHPhotoLibrary.shared().performChangesメソッドを使用してフォトライブラリにビデオを保存しています。

CameraViewController.swift
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
    PHPhotoLibrary.shared().performChanges({
        PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: outputFileURL)
    }) { _, error in
        if let error = error {
            print(error)
        }
    }
}

5. おまけ

キャプチャセッションをビデオ撮影向けに変更した後に、再び写真撮影を行いたい時は以下の様にキャプチャセッションを再構築することで写真撮影を行うことができる様になります。

CameraViewController.swift
private func chagePhotoMode() {
    self.captureSession.beginConfiguration()
    if let input = self.audioDeviceInput {
        self.captureSession.removeInput(input)
    }
    if self.captureSession.canAddOutput(self.photoOutput) {
        self.captureSession.addOutput(self.photoOutput)
    }
    self.captureSession.removeOutput(self.movieFileOutput)
    self.captureSession.commitConfiguration()
}

以上でビデオ撮影機能の実装は完了です。次回はLive Photos撮影機能について解説します。

Discussion

ログインするとコメントできます