📹

【iOS】AVFoundationを使用して動画撮影機能を実装する

に公開
2

AVFoundationのCapture APIを使用して、動画撮影機能を実装する方法について書きます。以下の記事を先にお読みいただくと、本記事の内容をスムーズに理解することができます。
https://zenn.dev/naoya_maeda/articles/6f5c6bec557393

本記事をお読みいただくことで、以下の内容を学ぶことができます。

  • 動画データを出力するキャプチャセッションの設定方法
  • 動画データ撮影を開始・終了・停止・再開する方法
  • デリゲートメソッドを介した動画データの取得方法
  • 動画データを写真アルバムに追加する方法

本記事の内容は、「詳解 AVFoundation Capture」から一部の説明を抜粋した内容になっています。
https://naoya-maeda.booth.pm/items/6760109
アプリがカメラやマイク、写真アルバムへアクセスするために必要なアクセス権を取得する方法については、本記事では割愛しています。「詳解 AVFoundation Capture」の「第2章 アクセス権」または、以下のドキュメントをご参照ください。
https://developer.apple.com/documentation/avfoundation/requesting-authorization-to-capture-and-save-media

キャプチャセッションの設定

入力設定

音声付きの動画データを取得するためには、カメラからの入力を表すAVCaptureDeviceInput オブジェクトに加え、マイクからの入力を表すAVCaptureDeviceInput オブジェクトをAVCaptureSession オブジェクトに追加します。以下のソースコードでは、マイクからの入力を表すAVCaptureDeviceInput オブジェクトを、AVCaptureSession オブジェクトに追加しています。

出力設定

AVCaptureMovieFileOutput は、動画データを出力するためのワークフローを提供するクラスです。
https://developer.apple.com/documentation/avfoundation/avcapturemoviefileoutput

AVCaptureOutput を継承しており、AVCaptureSession オブジェクトに追加することで、AVCaptureFileOutputRecordingDelegate プロトコルで定義されているデリゲートメソッドを介して、撮影した動画データを取得することができます。

AVCaptureSession オブジェクトは、撮影フォーマットを変更することができるAVCaptureSession.Preset 型のsessionPreset プロパティを持っています。
https://developer.apple.com/documentation/avfoundation/avcapturesession/sessionpreset

撮影フォーマットを表すAVCaptureSession.Preset オブジェクトは、スタティックプロパティとしていくつかのプリセットが用意されています。今回は、動画データ撮影向けに、高品質な動画データを出力することができるAVCaptureSession.Preset.high オブジェクトを、sessionPresetプロパティに代入します。以下のソースコードでは、iPhone 背面の広角レンズカメラと、マイクが記録した動画データを出力するキャプチャセッションの設定を行っています。

動画データ撮影の開始・終了

AVCaptureMovieFileOutput オブジェクトのstartRecording(to:recordingDelegate:) メソッドで、動画データ撮影を開始することができます。
https://developer.apple.com/documentation/avfoundation/avcapturefileoutput/startrecording(to:recordingdelegate:)

to 引数には、出力する動画データの書き出し先のドキュメントフォルダパスを表すURL オブジェクトを指定します。recordingDelegate 引数には、AVCaptureFileOutputRecordingDelegate プロトコルに準拠するオブジェクトを指定します。AVCaptureFileOutputRecordingDelegate プロトコルで定義されているデリゲートメソッドについては後述しますが、上記のソースコードでは、self を指定しています。AVCaptureFileOutputRecordingDelegate プロトコルに準拠したオブジェクトに、動画データ撮影の開始から完了するまでに呼び出されるデリゲートメソッドを定義します。
startRecording(to:recordingDelegate:) メソッドを実行する前に、AVCaptureMovieFileOutput オブジェクトのisRecording プロパティを確認します。
https://developer.apple.com/documentation/avfaudio/avaudiorecorder/isrecording

isRecording は、動画データ撮影中かどうかを表すBool 値が代入されているプロパティです。isRecording プロパティがfalse であることを確認した後に、startRecording(to:recordingDelegate:) メソッドを実行します。

また、AVCaptureMovieFileOutput オブジェクトのstopRecording() メソッドで、動画データ撮影を終了することができます。
https://developer.apple.com/documentation/avfoundation/avcapturefileoutput/stoprecording()

isRecording プロパティがtrue であることを確認した後に、stopRecording() メソッドを実行します。

プロトコルへの準拠

startRecording(to:recordingDelegate:) メソッドのrecordingDelegate 引数に、動画データ撮影の開始から完了するまでに呼び出されるデリゲートメソッドの委譲先を指定しました。今回は、移譲先にself を指定したので、startRecording(to:recordingDelegate:) メソッドを実行するクラス自身にデリゲートメソッドを定義します。デリゲートメソッドを定義するために、selfAVCaptureFileOutputRecordingDelegate プロトコルに準拠させます。

動画データの取得

fileOutput(_:didFinishRecordingTo:from:error:) は、AVCaptureFileOutputRecordingDelegate プロトコルで定義されているデリゲートメソッドです。
https://developer.apple.com/documentation/avfoundation/avcapturefileoutputrecordingdelegate/fileoutput(_:didfinishrecordingto:from:error:)

動画データが出力される時に呼び出されます。outputFileURL 引数には、動画データが書き込まれているドキュメントフォルダパスを表すURL オブジェクトが代入されています。

動画データを写真アルバムへ追加

動画データを写真アルバムへ追加する処理は、fileOutput(_:didFinishRecordingTo:from:error:) メソッド内で行います。静止画データや動画データ (以降、アセットデータ)を写真アルバムに追加する処理は、PhotoKitフレームワークのAPIを使用します。PhotoKitは、写真アルバムを操作するためのAPIが定義されているフレームワークです。写真アルバムに変更を加える時は、PHPhotoLibraryperformChanges(_:) メソッドを実行します。
https://developer.apple.com/documentation/photos/phphotolibrary/performchanges(_:completionhandler:)

performChanges(_:) は、第一引数に指定した写真アルバムに変更を加える処理を、PhotoKitにリクエストするメソッドです。

第一引数には、写真アルバムを操作する処理をクロージャで記述します。写真アルバムに対する変更は、PHAssetCreationRequest オブジェクトのメソッドで行います。PHAssetCreationRequest は、写真アルバムに対する変更をPhotoKitにリクエストすることができるメソッドを持つクラスです。
https://developer.apple.com/documentation/Photos/PHAssetCreationRequest

PHAssetCreationRequest オブジェクトは、forAsset() メソッドで取得することができます。
https://developer.apple.com/documentation/photos/phassetcreationrequest/forasset()

特定のドキュメントフォルダパスに書き込まれているアセットデータを写真アルバムに追加する時は、PHAssetCreationRequest オブジェクトのaddResource(with:fileURL:options:) メソッドを実行します。
https://developer.apple.com/documentation/photos/phassetcreationrequest/addresource(with:fileurl:options:)

addResource(with:fileURL:options:) は、特定のドキュメントフォルダパスに書き込まれているアセットデータを、写真アルバムに追加することをPhotoKit にリクエストするメソッドです。

with 引数には、写真アルバムに追加するアセットのタイプを、PHAssetResourceType オブジェクトで指定します。今回は、動画データを写真アルバムに追加するので、上記のソースコードでは、with 引数に.video を指定しています。fileURL 引数には、動画データが書き込まれているドキュメントフォルダパスを表すURL オブジェクトを指定します。上記のソースコードでは、fileOutput(_:didFinishRecordingTo:from:error:) メソッドのoutputFileURL 引数を指定しています。options 引数には、PHAssetResourceCreationOptions オブジェクトを指定します。PHAssetResourceCreationOptions は、アセットデータを写真アルバムに追加する時の追加処理オプションを設定することができるクラスです。
https://developer.apple.com/documentation/photos/phassetresourcecreationoptions

ドキュメントフォルダパスに配置されている動画データを写真アルバムに追加した後に、元の動画データが不要な時は、PHAssetResourceCreationOptions オブジェクトのshouldMoveFile プロパティにtrue を代入します。shouldMoveFile プロパティにtrue を代入したPHAssetResourceCreationOptions オブジェクトをoptions 引数に指定することで、元の動画データが写真アルバムに移動してから、動画データを写真アルバムに追加する処理が行われます。つまり、元の動画データが配置されていたドキュメントフォルダパスには動画データが存在しなくなり、端末のストレージを節約することができます。

以下のソースコードでは、撮影した動画データを写真アルバムに追加しています。

次回は、Live Photos撮影機能を実装する方法について解説します。
https://zenn.dev/naoya_maeda/articles/84b227a00531cc

参考資料

・詳解 AVFoundation Capture
https://naoya-maeda.booth.pm/items/6760109

・Setting Up a Capture Session, Apple Developer Documentation
https://developer.apple.com/documentation/avfoundation/setting-up-a-capture-session

Discussion

tomotomo

アプリ制作の参考になりました。ありがとうございます。
「前回の記事」と書かれているリンクが403エラーになるので、間違っているかと思います。

Naoya MaedaNaoya Maeda

ご指摘ありがとうございます!リンクミス部分を修正致しました。