6
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【AVFoundation】リアルタイムキャプチャの基本

Last updated at Posted at 2020-11-08

#この記事は何か?
iPhoneのカメラからリアルタイムに映像データを得るために使用するAVFoudationについて調べました。

#AVFoundationフレームワーク
主に、4つのグループに分けて捉えることができます。

  • セッション
    AVCaptureSessionクラス

  • デバイス
    AVCaptureDeviceクラス

  • 入力
    AVCaptureInputクラス、AVCaptureDeviceInputクラス

  • 出力
    AVCaptureOutputクラス、AVCaptureVideoDataOutputクラス

AVCaptureSessionがデータを整理し、セッションの開始または停止の指示を受けます。
セッションには、ひとつ以上の入力を追加します。AVCaptureDeviceInputは、カメラやマイクのためのラッパーです。
セッションからデータを受け取るには、出力も追加する必要があります。
入力と出力が追加されると、セッションは互換性のある入力と出力を自動的に接続します。
AVCaptureSessionでは、各セッションに1つのカメラだけが許容されます。なお、iOS 13で導入されたAVCaptureMultiCamSessionでは、複数の入出力を扱うことが可能になりました。

##AVCaptureSessionクラス

定義
class AVCaptureSession : NSObject

キャプチャ動作を管理し、入力デバイスからキャプチャ出力へのデータの流れを調整(コーディネート)するオブジェクト。

リアルタイムにキャプチャをするには、AVCaptureSession型のインスタンスに、適切な入力と出力を追加します。

オーディオを録音するためにキャプチャデバイスを設定するコードの例
// キャプチャセッションを作成して、標準のオーティオデバイスを設定する
let captureSession = AVCaptureSession()
guard let audioDevice = AVCaptureDevice.default(for: .audio) else { return } 

do {
    // オーディオデバイスをラップして、「キャプチャデバイスの入力」にする
    // 可能であれば、その入力をセッションに追加する
    let audioInput = try AVCaptureDeviceInput(device: audioDevice)
    if captureSession.canAddInput(audioInput) {
        captureSession.addInput(audioInput)
    }
} catch {
    // オーディオデバイスを「キャプチャデバイスの入力」にできなかった場合のエラー処理
}

入力から出力へのデータの流れを開始するにはstartRunning()メソッドを呼び出します。また、停止するにはstopRunning()メソッドを呼び出します。

startRunning()メソッドは、いくらか時間のかかる恐れがあるブロッキング呼び出しなので、メインキューがブロックされないように並列キューでセッションのセットアップを実行する必要があります。こうすることで、 UIの応答性を維持できます。
実装例についてはAVCam: Building a Camera Appを参照してください。

出力の品質レベル、ビットレート、または他の設定をカスタマイズするには、sessionPresetプロパティを使用します。ほとんどの一般的なキャプチャ設定はセッションプリセットを通して利用可能ですが、いくつかの特殊なオプション(高フレームレートなど)は、AVCaptureDeviceインスタンスにキャプチャフォーマットを直接設定する必要があります。

###addInput(_:)メソッド

定義
func addInput(_ input: AVCaptureInput)

「取得した入力」をセッションに追加します。

このメソッドを使用してセッションに入力を追加できるのは、canAddInput(_:)メソッドがtrueを返した場合のみです。canAddInput(_:)メソッドを呼び出した結果がfalseの場合、このメソッドは例外をスローします。

このメソッドは、セッションの実行中に呼び出すことができます。

###addOutput(_:)メソッド

定義
func addOutput(_ output: AVCaptureOutput)

このメソッドを使用してセッションに出力を追加できるのは、canAddOutput(_:)メソッドがtrueを返した場合のみです。canAddOutput(_:)メソッドを呼び出した結果がfalseの場合、このメソッドは例外をスローします。

このメソッドは、セッションの実行中に呼び出すことができます。

##AVCaptureDeviceクラス

定義
class AVCaptureDevice : NSObject

キャプチャセッションに「オーディオやビデオなどの入力」を提供し、ハードウェア固有のキャプチャ機能向けにコントロールを提供するデバイスです。

AVCaptureDeviceオブジェクトは、物理的なキャプチャデバイスと「そのデバイスに関連付けられたプロパティ」をモデル化したものです。キャプチャデバイスを使用して、基礎となるハードウェアのプロパティを設定します。また、キャプチャデバイスはAVCaptureSessionオブジェクトに「オーディオやビデオなどの入力データ」を提供します。

AVCaptureDeviceクラスのメソッドを使用して、利用可能なデバイスを列挙し、それらの機能を呼び出し、デバイスが出入りするときに通知を受けることができます。キャプチャデバイスのプロパティ(フォーカスモード、露出モードなど)を設定しようとする前に、最初にlockForConfiguration()メソッドを使用してデバイスのロックを取得する必要があります。また、設定しようとしている新しいモードがそのデバイスで有効であることを確認するために、デバイスの機能を問い合わせる必要があります。その後、 unlockForConfiguration()メソッドを使用してプロパティを設定し、ロックを解除します。設定可能なデバイス・プロパティをすべて変更せずに残したい場合は、ロックを保持することができます。しかし、デバイスのロックを不必要に保持すると、デバイスを共有している他のアプリケーションでキャプチャの品質が低下する可能性があり、お勧めできません。

キャプチャ設定のほとんどの一般的な構成は、AVCaptureSessionオブジェクトとその利用可能なプリセットを介して利用できます。しかし、iOSデバイスでは、いくつかの特殊なオプション(高フレームレートなど)は、AVCaptureDeviceインスタンスにキャプチャ形式を直接設定する必要があります。

iOSでは、キャプチャデバイスのactiveFormatプロパティを直接設定すると、セッションのプリセットがinputPriorityに変更されます。この変更を行うと、セッションのトポロジー(配置した入力、出力のこと)を変更した後にstartRunning()メソッドかcommitConfiguration()メソッドを呼び出すと、セッションは自動的にキャプチャフォーマットを設定しなくなります。
macOSでは、変更を行った後もキャプチャセッションは自動的にキャプチャフォーマットを構成することができます。

###lockForConfiguration()メソッド
デバイスのハードウェア設定に対する排他的アクセスを要求します。

宣言
func lockForConfiguration() throws

このメソッドはtry付きで呼び出し、do構文のcatch節でエラーを処理します。デバイスのハードウェア関連の設定を構成しようとする前に、このメソッドを呼び出す必要があります。
デバイスのプロパティを変更したくない場合は、(ロックを解除する代わりに)ロックを維持できます。ただし、不必要にデバイスをロックすると、デバイスを共有している他のアプリで行うキャプチャの品質が低下する恐れがあります。

iOSでは、キャプチャデバイスのactiveFormatプロパティを直接設定すると、セッションのプリセットがinputPriorityに変更されます。この変更を行った場合、セッションのトポロジーを変更した後(つまり、キャプチャの入力と出力を追加、削除、再配置した後)にstartRunning()メソッドかcommitConfiguration()メソッドを呼び出しても、セッションは自動的にキャプチャフォーマットを設定しなくなります。

##AVCaptureInputクラス
キャプチャセッションに入力データを提供するオブジェクトの抽象的なスーパークラスです。

宣言
class AVCaptureInput : NSObject

AVCaptureInputオブジェクトをセッションに関連付けるには、セッションでaddInput(_:)メソッドを呼び出します。
AVCaptureInputオブジェクトは、生成できるデータストリームごとに1つ以上のポート (AVCaptureInput.Portのインスタンス) を持っています。例えば、1つのビデオデータストリームを提示する AVCaptureDeviceオブジェクトにはポートが1つあります。

##AVCaptureDeviceInputクラス

宣言
class AVCaptureDeviceInput : AVCaptureInput

デバイスからセッションにメディアを提供するキャプチャ入力です。

AVCaptureDeviceInputは、AVCaptureDeviceオブジェクトからデータをキャプチャするために使用する AVCaptureInputの具体的なサブクラスです。

##AVCaptureOutputクラス

宣言
class AVCaptureOutput : NSObject

キャプチャセッションで記録したメディアを出力するオブジェクトの抽象的なスーパークラスです。

AVCaptureOutputは、AVCaptureSessionオブジェクトの出力先を記述する抽象的な基底クラスです。
AVCaptureOutputは、ファイルやビデオプレビューなどのキャプチャ出力先をセッション(AVCaptureSessionのインスタンス)に接続するための抽象的なインターフェイスを提供します。キャプチャ出力はAVCaptureInputから受け取るメディアのストリームごとにAVCaptureConnectionオブジェクトで表される「いくつかの接続」を持つことができます。最初にキャプチャ出力が作成されたとき、接続はひとつもありません。セッションに出力を追加すると、セッションは「そのセッションの入力」から出力にメディアデータをマップする接続を作成します。

AVCaptureOutputインスタンスをセッションに追加するには、セッションのaddOutput(_:)メソッドを使用します。

##AVCaptureVideoDataOutputクラス

宣言
class AVCaptureVideoDataOutput : AVCaptureOutput

ビデオを記録して、ビデオフレームを処理するためのアクセスを提供するキャプチャ出力です。

この出力を使用して、キャプチャしたビデオから圧縮または非圧縮のフレームを処理します。
フレームにはcaptureOutput(_:didOutput:from:)デリゲートメソッドを使用してアクセスできます。

###alwaysDiscardsLateVideoFramesプロパティ

宣言
var alwaysDiscardsLateVideoFrames: Bool { get set }

ビデオフレームに遅延があった場合に、フレームを削除するかどうかを示します。

このプロパティがtrueの場合、「既存のフレーム」を扱うディスパッチキューがcaptureOutput(_:didOutput:from:)デリゲートメソッドでブロックしている間に、出力は「キャプチャしたフレーム」を直ちに破棄します。
falseにすると、出力は「新しいフレーム」を破棄する前に「古いフレーム」を処理する猶予をデリゲートに与えますが、アプリケーションのメモリ使用量は結果として大幅に増加する恐れがあります。
デフォルトはtrueです。

###videoSettingsプロパティ

宣言
var videoSettings: [String : Any]! { get set }

出力の圧縮設定です。

この辞書には,videoSettingsで定義された圧縮設定キー,またはCVPixelBufferで定義されたピクセルバッファ属性キーの値が含まれます。現時点では、kCVPixelBufferPixelFormatTypeKeyキーのみがサポートされています。
サポートされているビデオピクセルフォーマット(kCVPixelBufferPixelFormatTypeKey)の値を取得するには、availableVideoPixelFormatTypesを参照してください。また、サポートされているビデオコーデックフォーマット(AVVideoCodecKey)の値を取得するには、availableVideoCodecTypesを参照してください。
デバイスのネイティブフォーマットでサンプルを受信するには、このプロパティを空の辞書に設定します。

###setSampleBufferDelegate(_:queue:)

宣言
func setSampleBufferDelegate(_ sampleBufferDelegate: AVCaptureVideoDataOutputSampleBufferDelegate?, 
                    queue sampleBufferCallbackQueue: DispatchQueue?)

サンプルバッファのデリゲートの設定、コールバックが呼び出されるべきキューを設定します。

キャプチャされたビデオの新しいサンプルバッファは、captureOutput(_:didOutput:from:)メソッドを使用してサンプルバッファのデリゲート先に送信されます。すべてのデリゲートメソッドは、指定されたディスパッチキューで呼び出されます。

新しいフレームがキャプチャされたときにキューがブロックされている場合、それらのフレームは、常にdiscardsLateVideoFramesプロパティの値に基づいて自動的にドロップされます。これにより、同じキューで既存のフレームを処理する際に、処理が入ってくるフレームのレートに追いつけない場合に発生するであろうメモリ使用量の増加を管理する必要がなくなります。

6
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?