[Xamarin.Mac] カメラの映像を表示してみました

2020.12.05

1 はじめに

CX事業本部の平内(SIN)です。

Xamarin.Macを使用すると、C#でネイティブなMacのアプリが作成可能です。 ここでは、私自身がXamarin.Macに入門して学習した事項を覚書として書かせて頂いています。

今回は、カメラの画像を表示してみました。

2 NSCameraUsageDescription

ビデオ入力を使用するためには、利用者の承諾(権限付与)が必要です。

info.plistNSCameraUsageDescriptionを追加して、使用目的などを提示します。

追加後プログラムを実行すると、ポップアップが表示され、利用者への確認となります。

3 画面設計

Interface Builderでの画面設計です。

最初に、ウインドウいっぱいに上下分割のSplit Viewを置きました。そして、上側のビューの高さを固定し、PopupButtonを配置しました。

Outletは、PopUpButton(NSPupUpButton)とVideoView(NSView)という名前で作成しています。

4 AVFoundation

ビデオの処理は、AVFoundationで行います。以前、iOSで色々試してみたのですが、使い方は、変わりませんでした。

AVFoundationでは、大きく分けて3つの入出力があります。 ビデオを画像ファイルなどに保存する場合は、出力も作成する必要がありますが、今回は、表示するだけなので、出力は定義していません。

  • デバイス(AVCaptureDevice)
  • セッション(AVCaptureSession)
  • 出力(AVCaptureOutput)

5 ViewController

ViewControllerで記載したコードです。

起動時に、AVCaptureDevice.DevicesWithMediaType() で、ビデオデバイスの一覧を取得しておいて、選択時点で入力を初期化しています。

キャプチャーは、NSViewLayerに挿入しています。

public partial class ViewController : NSViewController {

    AVCaptureDevice[] devices = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video);

    public override void ViewDidLoad() {
        base.ViewDidLoad();
        PopUpButton.RemoveAllItems();
        foreach(var _device in devices) {
            PopUpButton.AddItem(_device.LocalizedName);
        }
        // 選択時の処理
        PopUpButton.Activated += PopUpButton_Activated;
        // 0番目のデバイスでビデオ表示
        VideoStart(0);
    }

    // 選択時の処理
    private void PopUpButton_Activated(object sender, EventArgs e) {
        var index = ((NSPopUpButton)sender).IndexOfSelectedItem;
        // 選択したデバイスでビデオ表示
        VideoStart(index);
    }

    // 選択したデバイスでビデオ表示
    private void VideoStart(nint index) {
        var session = new AVCaptureSession();

        session.BeginConfiguration();
        var input = AVCaptureDeviceInput.FromDevice(device: devices[index]);
        session.SessionPreset = AVCaptureSession.Preset640x480;
        session.AddInput(input);

        var layer = new AVCaptureVideoPreviewLayer(session);
        layer.VideoGravity = AVLayerVideoGravity.ResizeAspect;
        layer.Frame = View.Bounds;
        VideoView.Layer = new CALayer();
        VideoView.Layer.InsertSublayer(layer, 0);

        session.CommitConfiguration();
        session.StartRunning();
    }

    // ・・・略・・・

6 動作確認

試してみている様子です。 ビデオのサイズは、表示時に、NSViewのサイズで初期化するため、ウインドウのリサイズには追従していません。

7 最後に

今回は、カメラの映像を表示してみました。

概ね、AVFoundationの構造を理解すれば、後は、必要なパラメータを設定するだけで、目的は達成できるでしょう。

少し、Macのアプリになれてきたかも知れませんが・・・・「Swiftで書いた方が早い」というツッコミは、お許し下さい。