Virtual Webcamを作れるcoremediaio-dal-minimal-exampleをビルドして動かしてみた

一時期、Mac版のZoomがVirtualCameraInputを読めなくなっていた時期に少し調べてて、試す前にZoomが復活したのでそのままになっていたところ、真鍋大度さんが実装してたのでまたちょっと気になって調べてみた。

<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">openFrameworksのTextureをWebCamとして認識するaddon,  ofxGL2Webcamを作ったのでこれを使いたいところ。 Syphon経由ではないところがミソ。 <a href="https://t.co/NICu4C85TG">pic.twitter.com/NICu4C85TG</a></p>&mdash; Daito Manabe (@daitomanabe) <a href="https://twitter.com/daitomanabe/status/1295703035595722752?ref_src=twsrc%5Etfw">August 18, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# CoreMediaIO-DAL-Example

まずはこれに行き着いたけど、なんとかビルドと実行はできたものの、僕が何か誤解してるのか、VirtualInputは作られなかった。
https://github.com/lvsti/CoreMediaIO-DAL-Example

<details><summary>ビルドと実行を通すまでのメモはこの中に</summary><div>


DLしてSampleをビルド
ld: can't open -sectcreate file: /Users/nariakiiwatani/Downloads/CoreMediaIO-DAL-Example-master/BuildSystem/XcodeProjects/../../Sources/Extras/CoreMediaIO/DeviceAbstractionLayer/Devices/Sample/KernelExtension/ntsc2vuy720x480.yuv
clang: error: linker command failed with exit code 1 (use -v to see invocation)

データがないっぽい

https://github.com/lvsti/CoreMediaIO-DAL-Example/issues/7

リポジトリから削除したとのことなので、書いてある通りここからオリジナルのサンプルをDL（画面左上あたり）
https://developer.apple.com/library/archive/samplecode/CoreMediaIO/Introduction/Intro.html

ビルド通った。
他ターゲットもビルドしていく
SampleVcamAssistantで実行時エラー

"/Library/CoreMediaIO/Plug-Ins/DAL/SampleVCam.plugin/Contents/Resources/ntsc2vuy720x480.yuv"がない

見てみたけどそもそも/Library/CoreMediaIO/Plug-Ins/DAL/にSampleVCam.pluginがない

SampleVCam.pluginのビルド設定をみる

BuildResultsフォルダにビルドされるようだが、Libraryにコピーするのはどこでやってる？

Deployment -> Installation Directoryにそれらしき設定があった

このリンク先によるとInstallationはxcodebuild install時にされるもの？
https://stackoverflow.com/questions/636810/mac-osx-xcode-installation-directory

`xcodebuild -project [xcodeprojへのパス] install`を実行

`** INSTALL SUCCEEDED **` やった

でもやっぱり/Library/CoreMediaIO/Plug-Ins/DAL/にSampleVCam.pluginは作られてない

`sudo xcodebuild ~~~`してみてもだめ

おそるおそる手動でコピーしてみると
SampleVCam Assistantのビルドでエラー
error: unable to open output file '/Users/nariakiiwatani/Downloads/CoreMediaIO-DAL-Example-master/BuildResults/Sample.build/Debug/SampleVCam Assistant.build/Objects-normal/x86_64/CACFArray.o': 'Operation not permitted'

クリーンアップしたら通った。実行できた。
しかしQuickTimeでもZoomでも認識されていないよう。
いったん掘るのを止める
</div></details>

# coremediaio-dal-minimal-example

これを見つけたので試してみる
https://github.com/johnboiles/coremediaio-dal-minimal-example

READMEにある通りにやれば動いた。

> To try this out:

> - Build it in Xcode
> - Find CMIOMinimalSample.plugin in Xcode's 'Products' folder
> - Right click CMIOMinimalSample.plugin and choose 'Show in Finder'
> - Copy the plugin bundle to /Library/CoreMediaIO/Plug-Ins/DAL/
> - Open QuickTime
> - Watch the logs in Console.app for any logs prefixed with CMIOMS

> You may also need to change the codesigning to use your own personal developer identity.

せっかくなので記録しておく。

### Xcodeでビルド

`CMIOMinimalSample.xcodeproj`をXcodeで開いてビルド。
ビルドターゲットは`CMIOMinimalSample`ひとつしかないのでそれでOK。
未サインイン状態だったのでCodesignのエラーが出たが、Signingを設定したら通った。
![スクリーンショット 2020-08-19 22.12.07のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16556/65c0e47d-f601-235b-be5a-0454b3d1e752.png)

ちなみにこれはApple Developer Membershipのライセンスを買っているアカウント。
無料アカウントでも通るのかは未確認。

### `CMIOMinimalSample.plugin`を探す

ビルドが通るとProductsのところにpluginファイルが表示されるので、それを選択して、画面右のインスペクタで矢印をクリックすればFinderで表示される
![スクリーンショット 2020-08-19 22.16.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16556/8c147a74-6425-0c76-d225-cf4d79cb9220.png)

### `CMIOMinimalSample.plugin`を`/Library/CoreMediaIO/Plug-Ins/DAL/`へコピー

Finderでの操作でOK

### `QuickTime`を起動して`Console.app`でログを確認

これはやってみたけど該当するログが確認できなかった。

### 動作確認

QuickTimeの新規ムービー収録で入力ソースに`CMIOMinimalSample Device`が表示されていればOK
![スクリーンショット 2020-08-19 22.22.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16556/a187f6e3-7ca9-3fd7-72fa-82a2aac91bd0.png)

ちなみにZoomでは認識されなかった。

## これから

サンプルは動いたので、あとはここに望みのデータを表示する仕組みを作ればいろいろ遊べそう。
ソース読んだ感じだと、（非常に簡潔なソースで助かります。。。）

- [PlugInInterface.mm](https://github.com/johnboiles/coremediaio-dal-minimal-example/blob/master/CMIOMinimalSample/PlugInInterface.mm)でInit/Start/Stop/CopyBufferQueueとかのイベントを外から受け取り
- [Stream.h](https://github.com/johnboiles/coremediaio-dal-minimal-example/blob/master/CMIOMinimalSample/Stream.h)の各関数を駆動
- 起動（？）している間`Stream::fillFrame`が呼ばれ続けることになるので、ここで`self.queue`に最新の画像のバッファを渡しておけば
- `Stream::copyBufferQueueWithAlteredProc`で`PlugInInterface`の要求に応じて最新の画像が出せる

という感じかと想像される。

VirtualCameraである以上、このサンプルのようにプラグイン内部で画像を生成しててもしょうがなくて、やっぱり外部から画像を入力できるような仕組みにしたい。
大度さんは`xmq:tcp`で渡すようにしてるらしい。

<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr">It&#39;s DAL plugin. I recommend to check this example.  <a href="https://t.co/DNqvNNZNy5">https://t.co/DNqvNNZNy5</a>  the openFrameworks app sends texture data to DAL plugin via zmq:tcp :) <a href="https://t.co/jJzC5OYXNt">https://t.co/jJzC5OYXNt</a></p>&mdash; Daito Manabe (@daitomanabe) <a href="https://twitter.com/daitomanabe/status/1295941325389348864?ref_src=twsrc%5Etfw">August 19, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

で、僕が今作るなら何を使うかなーと考えるとやっぱりNDIなんだけど、それ公式ツールの`NDI Virtual Input`で良くね？Zoomでも読めるし。
と気づいたところでモチベーションが落ち、でもせめてやった記録くらいは残しておこうかな・・・と思った次第で書いている記事です。

# 最後に

手前味噌ですが[ofxNDI](https://github.com/nariakiiwatani/ofxNDI)とNDI Virtual Inputを併用すると、自分で書いたoFアプリの出力をVirtual Webcamに渡すことができます。
ちなみにNDIでオーディオも送れます。

zmqでもNDIでもですが、ネットワーク経由でVirtual Inputに画像を渡せるというのは遊びがいがありそうですね。