うさぎ駆動開発

UWP, Xamarin.Macを中心によしなしごとを書いていきます。

AVFoundation で FaceTime カメラからキャプチャする

今時の Macbook には FaceTime カメラがついているので,ちょっと試しました。

リポジトリはこちら。

github.com

環境

  • macOS Sierra 10.12 16A320
  • Xcode 8 8A218a
  • Xamarin Studio 6.1 b5436
  • Xamarin.Mac 2.10.0.99

プロジェクト

Xamarin.Mac Cocoa Appを作成して,Viewをひとつ追加,xib ファイルは使わないので削除。 f:id:ailen0ada:20160913220147p:plain

ここでは LiveView.cs として,このように実装。

背景色の設定などはまあどうでもよく,最低限 Layout() をオーバーライドして内包するレイヤーの描画領域を追従させること。

Xcode

Main.storyboard を開き,適当にコントロールを配置する。 f:id:ailen0ada:20160913220617p:plain

CustomView のベースクラスを NSView から作成しておいた LiveView に変更し,さらに CoreAnimationLayer の指定をしておく。 これでビュー内にレイヤーが作成されるので,このレイヤーにビデオストリームをサブレイヤーとしてパスするのが大まかな流れとなる。

ビューほか3つのボタンは ViewController.h にアクセサを生やしておく。

ViewController

ViewWillAppear をオーバーライドし,

  1. バイスの探索と接続
  2. プレビュー用のレイヤーを作成

を行っていく。

バイスの探索と接続

接続されているカメラデバイスは,

AVCaptureDevice[] device = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video)

で取得できる。これをポップアップボタンに項目として追加すれば複数接続されているときにデバイスの選択ができるが,FirstOrDefault でお茶を濁すことに。

バイスが見つかったら,これを入力ソースとしてセッションに設定する。

var session = new AVCaptureSession();
var input = new AVCaptureDeviceInput(device, null);
session.AddInput(input);

さらに後々JPEG画像として切り出したいので,出力ソースも設定しておく。

var imageOutput = new AVCaptureStillImageOutput();
imageOutput.OutputSettings = NSDictionary.FromObjectAndKey(AVVideo.CodecJPEG, AVVideo.CodecKey);
session.AddOutput(output);

プレビューレイヤー

レイヤーは AVCaptureVideoPreviewLayer というそのままな名前のものが存在する。これに先ほど作成したセッションを接続すればよい。

previewLayer = new AVCaptureVideoPreviewLayer(session);
previewLayer.VideoGravity = AVLayerVideoGravity.ResizeAspect;
LiveView.Layer.AddSublayer(previewLayer);

あとはボタンのクリック時に session.StartRunning() すればプレビューが表示される。まあ簡単。 f:id:ailen0ada:20160913221928p:plain

画像のキャプチャ

セッションに登録した出力ソースから AVCaptureConnection を取り出し,スチルイメージバッファを取得すればよい。 CoreMedia.CMSampleBuffer として取り出したバッファを,JPEGバイト列に変換するメソッドが提供されている。

まとめ

カメラからのキャプチャは非常に簡単。ではこれをどう料理するかはまた次回。