Open6

AVKitでカメラとプレビューを扱う

enchanenchan

Infoに許可を取るステートメントを設定しておく

これがないとカメラを利用できない

enchanenchan

セッションの構成と開始

以降、ViewController クラスをメインに話を進める

AVCaptureSession をフィールドとしてもち、viewDidLoad でセッションを構成する

https://github.com/Enchan1207/avkit_camera_capture/blob/5d8862940d5fe021d533dc57a021d5ad77f85c8c/camera_capture/ViewController.swift#L48-L74

以下、ポイント

  • デバイスは特に拘らずデフォルトのものを取得して使用
  • プリセットは high (A preset suitable for capturing high-quality output) を選択
  • 出力はAVCapturePhotoOutput ではなく、AVCaptureVideoDataOutput を使用
    • これによりカメラの出力を直接得ることができる
    • 出力はフィールドで持っておく
  • セッションの構成は begin で始めて commit で抜ける
    • 多分セッションが動いてるなら一回止めた方がいい

構成したセッションは viewWillAppear で開始しておく セッションの開始処理はちょっと重いらしく、メインスレッドで動かすとランタイム警告が出るので注意

https://github.com/Enchan1207/avkit_camera_capture/blob/5d8862940d5fe021d533dc57a021d5ad77f85c8c/camera_capture/ViewController.swift#L39-L45

enchanenchan

カメラ映像の表示と取得

ここまで実装すると、PreviewView にカメラの映像がプレビューされる

プレビューしているフレームは AVCaptureVideoDataOutputSampleBufferDelegatedidOutput メソッドで取得できる:

https://github.com/Enchan1207/avkit_camera_capture/blob/5d8862940d5fe021d533dc57a021d5ad77f85c8c/camera_capture/ViewController.swift#L126-L134

取得したフレーム(CMSampleBuffer)はフィールドに保存しておく
今後の処理的に面倒が起きないよう、フラグ shouldUpdateBuffer が立っていなければ更新しないようにしている

…書いてて気づいたけど CMSampleBuffer 値型じゃないのか 何かしらでコピーとかした方がいいんだろうか?

enchanenchan

フレームから画像を生成

ここが本題

https://github.com/Enchan1207/avkit_camera_capture/blob/5d8862940d5fe021d533dc57a021d5ad77f85c8c/camera_capture/ViewController.swift#L91-L113

変換の流れは以下の通り

  1. バッファ(CMSampleBuffer) -> CIImage
  2. カメラがキャプチャした映像のうち、 PreviewView に表示されている領域を取得
  3. 1で取得した画像を、2で取得した領域に合わせて切り抜く
  4. CIContext により、CGImage に変換
  5. 4で得た CGImage を、向きを考慮して UIImage に変換

ポイントは2と4

プレビューに表示されている領域?

PreviewView がもつ AVCaptureVideoPreviewLayervideoGravity.resizeAspectFill なので、プレビューに表示される領域はカメラがキャプチャしたそれとは異なる:

// TODO: 図入れる