Zopfcode

かつてない好奇心をあなたに。

NikonのカメラをWebカメラにする方法(もちろんマルチOSで)

がなかったので、自分で開発した。その後発表された公式アプリやSparkoCamとの差についてはこちらを参照。

tl;dr

f:id:puhitaku:20200727221049j:plain
概観

github.com

  • カメラからライブビュー (LV) を取ってきてOBS経由で仮想カメラにするソフト mtplvcap をGoで書いた
  • PCやスマホからカメラのフォーカス等を制御できるリモコンもある
  • libusbとOBSのおかげで Windows/macOS/Linux 全対応!
  • マジめっちゃ動作確認情報を欲してるので、動いた/動かなかった情報を@puhitakuにガンガン送ってほしい(DM可)

最新リリースと動作確認情報(2020/11/26 現在)

Version 1.1.2リリース。

開発者 puhitaku は新しい機種での動作確認を渇望している。以下の機種以外でもし動いたら是非 Twitter で教えてほしい。

  • D3200(lvisi さんありがとうございます!)
  • D3300(unasuke さんありがとうございます!)
  • D5000(rch850 さんありがとうございます!)
  • D5100(shigureanko さんありがとうございます!)
  • D5300
  • D5500(nasustim さんありがとうございます!)
  • D600(ohtayo さんありがとうございます!)
  • D610(hazlitt さんありがとうございます!)
  • D7000(takashi0314 さんありがとうございます!)
  • D7100(TheMidlander さんありがとうございます!)
  • D7200(br_spike_love さんありがとうございます!)
  • Z6(ShadowXii さんありがとうございます!)
  • Z7(zacheadams さんありがとうございます!)

類似ソフトウェアとの比較

Nikon公式のWebカメラ化アプリ「Webcam Utility」(以下、WU)やSparkoCam(以下、SC)との違いは以下の通り。(情報は2020年11月26日現在)

mtplvcap WU SC
OS Win, Mac, Linux Win(MacはTBA) Win
課金 Free Free Paid
PCからの撮影設定 Yes No Yes
機種 D3200, D3300, D5000, D5100, D5300, D5500, D600, D610, D7000, D7100, D7200, Z6, Z7 他随時追加中*1 D5, D6, D500, D750, D780, D810, D850, D3500, D5300, D5500, D5600, D7200, D7500, Z5, Z6, Z6 II, Z7, Z7 II, Z50 D3, D3s, D3X, D300, D300s, D4, D4s, D5, D500, D5000, D5100, D5200, D5300, D5500, D5600, D6, D600, D610, D700, D750, D780, D7000, D7100, D7200, D7500, D800, D810, D810A, D800E, D850, D90, Df, 1 V3, Z6, Z7, Z50

Webcam Utility は Beta 版でほぼ最新の機種のみへの対応を発表した。その後2020年11月4日に正式版がリリースされたが、依然として一部の機種にしか対応していない。mtplvcap は Webcam Utility がサポートする機種を完全サポートし、さらに広い範囲の機種へ対応することを目指している。

使い方

日本語のREADMEを書いておいたのでそれを参照してください。

経緯

昨今のアレにより手持ちの一眼をWebカメラにするのが流行っている。CanonのWebカメラソフトはBetaながらMacとWindowsに対応してきたし、SIGMA fpはなんとUVCに対応している。 Sonyも2020年8月現在Windowsのみながら公式対応を発表した*2。しかしどうもそれ以外のベンダーは対応がしょっぱい。Nikon*3ユーザーな僕は、家で寂しく指をくわえるしかなかった。

4月以降はインカメが最高なPixel 3で快適にビデオ通話できてたし、一眼をわざわざ使う理由は正直ないのだが、

やっぱり…一眼で撮れたら嬉しいよね…。

ということで、開発に踏み切った。

日頃はほぼMac + ヘッドレスなLinuxの構成なので、Macで写したい。既存手法で出ているv002 Camera Live謎の海外ソフト頑張る方法だと、Macのみ・Windowsのみの対応となり汎用性がない。ソフトでライブビューを表示してそのウインドウをキャプチャするなんていう記事もあるけど、ゲーム配信じゃないんだし…とてもエレガントとはいえない。

ではどうやって画を取ってきて仮想カメラに流し込むか?その算段はついていた。カメラからMTPで画を取り出し、WebSocketで配信、それをOBSのBrowserSource(OBSにエンベッドされたChromiumの画面をソースにできるやつ)で表示してOBSの仮想カメラに流すというものだ。

MTPとはMedia Transfer Protocolの略で、デバイスの制御とファイルのやり取りを網羅しているプロトコルだ。ベネッセ個人情報流出事件で用いられたテクニックはMTPと言えば思い出す人もいるかもしれない。USB Mass Storageとは異なるのでWindows以外では扱いにくくよく厄介者扱いされるが、機能的にはMass Storageよりも豊富なため携帯プレーヤーなどではデファクトスタンダードとなっている。

開発

要件は以下のように決めた。

  • Windows/macOS/Linux全対応
    • 昨今のカメラベンダーの対応に業を煮やしていたので
  • Goで書く
    • cgoが
    • リンクが楽
    • ランタイムがいらない
  • USB部分と仮想カメラ部分はOS間で差異があるためlibusbとOBSに任せる

色々探していると、これまたドンピシャなOSS go-mtpfs を発見した。AndroidなどのMTPデバイスとlibusb経由で低レベル通信をしつつ、FUSEを使ってマウントするものだ。

github.com

USBの低レベル通信とWebサーバーによる配信を1プロセスでやるにあたって、Go + libusbで書きたいと思っていたので、まさに願ったり叶ったり。macOSでデバイスの初期化が上手くいかない問題はあったもののGoLandのデバッガーのお陰でスムーズに解決し、forkした。

まず取り掛かったのはライブビューの開始。MTPではuint16の命令番号的なのを送りつけることで動作を命令することができる。例えば、ライブビューの開始は0x9201が対応している。これを送りつけたり応答をパースしたりする部分はgo-mtpfsの力を借りる。

次に取り掛かったのはライブビューの画の取得。ここでちょっと心拍数が上がってくる。これもまたライブビューの開始と同様に 0x9203 を送りつけるとキャプチャできる。

この画像をOBSのBrowserSourceで表示するには、フロントエンドを用意して、画像シーケンスを配信する必要がある。これはWebSocketでサクッと解決できた。

そしてそして、お待ちかねのOBS + Zoomの結合も難なく成功!やったー!

ひとまずのマイルストーンを達成したので、LinuxとWindowsでも動作確認。結論から言うと、WindowsのWSL 1では動作しなかったが、MinGW (MSYS2) では楽勝で動かすことが出来た。やはり年の功というか、歴史が長いだけあってのことか。MinGWだとネイティブのexeが出てきてくれるので、環境を用意する障壁がWSLよりも圧倒的に低い。これは超嬉しかった。

この後、紆余曲折を挟みつつも*4、ISOや絞りも変えることができた。

画像が安定して撮れるようになったところで、リモコンの実装に着手した。

リモコンはBootstrap + jQueryで書いた古式ゆかしいフロントエンド*5で、絞り・ISO・オートフォーカス(一定間隔でAFさせるのも設定可)・フレームレート制限を設定できる。カメラのダイヤルでモードをAUTOにすれば自動で輝度が調整されるので、それで十分であれば絞りやISOを手で変更する必要はない*6

f:id:puhitaku:20200727234015p:plain
リモコン on Mac

./mtplvcap -host 0.0.0.0 という風に外からのアクセスもListenするようにすれば、スマホからでも操作できる。

f:id:puhitaku:20200727234042j:plain
リモコン on Android

まとめ

当初はD5300とD3300でしか確認できていなかった動作も、ユーザーの皆さんのおかげで今では13機種まで増えた。あなたにもぜひお手元のNikonカメラで動作を確認してみて欲しい。

なお、MTPで通信をするカメラであれば、原理上他メーカーでも対応が可能なはずだ。やり方としては、USBのVendor IDとProduct IDを見て動作を振り分ける方法を想定している。今はまだこの仕組みはないが、もしMTPで通信すると判明しているカメラがあって、私に貸していただけるならば実装を引き受けることも可能かもしれない。

*1:現在動作確認ができているもののみを挙げている

*2:対応機種も幅広くて好感が持てる

*3:当初は非公式かつWinのみの仮想カメラソフトを公式が紹介する始末で、最近WindowsとmacOSにのみ対応したNikon Webcam Uitlityを公開した。

*4:Arrayなどを内含できるDevice Propertyなる可変な構造体があり、例えばISO値はこれで送られてくる。Goは可変な構造体は扱いにくくたいていreflect祭りになる。この割と複雑なエンコード・デコード処理が実装されておらず、go-mtpfsのコードを手で紐解く必要があった。

*5:いわゆるモダンさはないけど、これでいい。当然node.jsなどに触れることもないので、超シンプルになってくれるのが最高。

*6:現在はカメラの動作モードを見に行く処理がないので、AUTOモードで絞りやISOを変更しようとするとAccessDeniedが返ってくることに注意