こんにちは! テリーです。全国的なリモートワーク生活から半年経ち、1日数回テレカンする生活が当たり前になってきましたね。先日macOSのアップデートを会議30分前に走らせてしまい、会議の開始時刻までに終わらなくて焦るという体験をしました。普段はハイスペックなノートパソコンを使用していますが、アップデートやバッテリー不足など諸々の都合で低スペックなタブレットやスマホを使わざるを得ない状況もあるでしょう。そんな状況にあっても、我が家の片付いていない背景は見せたくありません。OBSもバーチャルカメラも使えない。ぴえん。今回は、このケース「低スペックなタブレットから高負荷映像処理をして今すぐテレカンに参加する」方法の一部をご紹介します。

今回紹介する技術

  • ヘッドレスブラウザ
  • ハードウェアアクセラレーション

ヘッドレスブラウザとは

さて、聞き慣れない言葉「ヘッドレスブラウザ」が唐突に出てきました。これは何でしょうか? 直訳すると「頭がないブラウザ」ですが、実際には「画面をディスプレイに描画しないブラウザ」を指します。JavaScriptが高速・高機能化し、様々なWeb技術が集積されていく中で、ブラウザはもはやOSと呼んでも過言でないほどなんでもできるように進化してきました。Bluetooth、USB、暗号化、WebAssembly、GPGPU、トランスポート、エンコード、デコード、音声処理、ローカルファイルアクセス、DB、などです。こういった高速演算処理、ハードウェアアクセス処理のプラットフォームとして、ヘッドレスブラウザを使用することができます。ハードウェア依存部分はブラウザが吸収してくれるため、OS、CPU、GPUのメーカーをユーザーが意識する必要がありません。

ハードウェアアクセラレーションとは

「ハードウェアアクセラレーション」も聞き慣れない言葉ですね。「CPU以外のものを使って、高速に処理をすること」を指します。特定の機能に特化したハードウェアは、CPUの数十倍もの処理速度を出すことができます。ヘッドレスでない普通のブラウザでは、動画再生と、3Dゲーム描画処理に、Web閲覧者が意識することなく使われています。

映像処理アプリケーション実行環境としてのヘッドレスブラウザ

ヘッドレスブラウザと普通のブラウザとの違いは、画面がディスプレイに表示されないこと以外にもう一つあります。普通のブラウザにはタブ機能があり、他のタブや他のアプリの裏側に回って全体が非表示となった場合に、タイマーイベントが停止し、描画イベントがスキップされるなどの、プログラムの意図とは異なる挙動をすることがあります。Canvasを用いた処理では、requestAnimationFrame関数が一時停止します。ところがヘッドレスブラウザでは、setTimeoutもrequestAnimationFrame関数も常に最高速でイベントが実行されます。それがストリーミング処理やアニメーション処理のようなリアルタイムアプリケーションにはとても都合がよく、デコード、機械学習推論、拡大縮小、描画、エンコードの処理がハードウェアの持つ演算性能を生かして、高速に処理されます。

デモアプリケーション

ヘッドレスブラウザを用いた映像処理のデモアプリケーションを用意しました。映像処理用アプリとカメラ配信用アプリの2つで構成されています。アプリの動作を以下に示します。

  1. ヘッドレスブラウザからAyame Liteのシグナリングサーバに接続し、待機します(Ayame Liteについては後述します)。
  2. タブレットからAyame Liteのシグナリングサーバに接続し、ヘッドレスブラウザとP2P接続します。
  3. タブレットはカメラ映像をヘッドレスブラウザに送ります。
  4. ヘッドレスブラウザは受信した映像から人を検出し、人以外の背景にぼかし加工を加え、Canvasに描画します。
  5. ヘッドレスブラウザはCanvasに描画された映像をタブレットに送信します。
  6. タブレットはヘッドレスブラウザから受信した映像を画面に再生します。

人物検出と背景ぼかし加工の処理はTensorflow.jsを使用し、内部ではハードウェアアクセラレーションありのWebGLが使用されます。背景ぼかし加工についての記事もご覧ください。

必要なもの

  1. カメラ配信用低スペックタブレットとブラウザ(以下タブレット)
  2. 映像処理用高スペックパソコンとChrome(以下パソコン)

本記事では、下記の端末とブラウザを使用します。

端末 OS ブラウザ
1 Fire HD 10 Fire OS 7.3.1.5 Silkブラウザ 84.3.5.4147.125.10
2 MacBook Pro macOS Catalina 10.15.6 Chrome 85.0.4183.102

準備:ヘッドレスブラウザを起動

ヘッドレスブラウザは「画面をディスプレイに描画しないブラウザ」と上で述べました。ディスプレイに描画しない常駐アプリとして起動するための特別なコマンドラインオプションがあります。これをmacOSのターミナルにてaliasとして定義します。

alias google-chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"
alias headless="google-chrome --headless --use-gl=egl --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222"
1行目 alias google-chrome=… macにインストールされるchromeのパスが長いため、linuxのコマンド名と同名のaliasにしている
2行目 alias headless=… chromeをヘッドレスブラウザとして起動するためのオプション数が多く長いため、必ず使用するオプションごとaliasにしている

2行目のコマンドラインオプションが最も重要ですので個別に解説します。

--headless ヘッドレスブラウザモードでchromeを起動するオプション。省略すると通常モードで起動する。
--use-gl=egl ハードウェアアクセラレーションを有効にするオプション。省略するとハードウェアアクセラレーションが有効にならないことがある。
--remote-debugging-address=0.0.0.0 ヘッドレスブラウザの状態を監視するためにLISTENするアドレス。0.0.0.0とすると外部からアクセス許可という意味を持つ。省略すると127.0.0.1を指定したことになり、同一マシン内からのみアクセス可能となる。
--remote-debugging-port=9222 ヘッドレスブラウザの状態を監視するためにLISTENするポート番号。番号は他とかぶらなければお好みでなんでもよい。省略すると状態監視ができない。

aliasを指定したら、下記のコマンドでヘッドレスブラウザに特定のページを表示させます。好きなURLを指定してください。下記の例では、パソコンのGPU機能のステータスを表示するページにアクセスしています。

headless chrome://gpu/

「DevTools listening on ws://0.0.0.0:9222/devtools/browser/…」というメッセージが出ていれば正常に動作しています。しかし、コマンドだけではヘッドレスブラウザが今どうなっているかまったくわかりませんね。そこで普通のブラウザからヘッドレスブラウザの状態を確認することができます。下記のコマンドを実行してください。

google-chrome http://127.0.0.1:9222`curl -s http://127.0.0.1:9222/json | jq -r '.[0].devtoolsFrontendUrl'`

jqコマンドはJSONを解析するためのコマンドです。インストールしていない方はbrewまたはaptでインストールしてください。
このコマンドは3つのコマンドを1つにまとめるワンライナーです。まずhttp://127.0.0.1:9222/jsonにcurlコマンドでアクセスしてJSONを取得します。取得したJSONをjqコマンドで解析し、devtoolsFrontendUrlというキーの値を取得します。最後にホストを先頭に追記して、一連の文字列として整形したのち、普通のブラウザでアクセスします。ここではIPアドレスを127.0.0.1としていますが、LAN内のIPアドレスを指定することも可能です。

すると下記の画面が表示されるでしょう。これはヘッドレスブラウザでハードウェアアクセラレーションが有効になっていることと、画面が800×600で処理されていることがわかります。アドレスバーのすぐ下にもう一つ小さい字のアドレスバーがあります。これがヘッドレスブラウザでアクセスしているURLです。URLを書き換えてEnterキーを押すと、ヘッドレスブラウザの画面も切り替わります。

映像配信

手元の低スペックタブレットのカメラ映像をヘッドレスブラウザに送信する、最も手軽な方法はWebRTCのP2Pです。1対1のためP2Pが適しています。今回のデモではシグナリングサーバとして時雨堂のAyame Liteを使用します。Ayame Liteは登録不要でWebRTCのP2P接続とテスト配信ができる素晴らしいサービスです。

デモアプリの操作手順

  1. ヘッドレスブラウザで、デモページ(映像処理用)にアクセスしてください。
    https://codepen.io/terry_a/pen/wvGXdBN
  2. タブレットで、デモページ(カメラ配信用)にアクセスしてください。初回アクセスの場合は、「codepen.ioから、カメラの使用許可を求められています」というダイアログが出るので、「許可」を押して下さい。
    https://codepen.io/terry_a/pen/MWyXmaa

注意点

  1. 映像処理用/カメラ配信用の各ページにアクセスしたら、JavaScriptのプログラムからroomIdという変数を探して、その値(初期値は「sakunare_bodypix1」になっています)をお好みのユニークな文字列に変更して下さい(両ページとも同じ文字列にします)。Ayame Liteは1対1でしか接続できない仕組みのため、roomIdが他のユーザと重複すると動作しません。同じ理由でデモページを複数立ち上げたまま閉じ忘れた場合も動作しません。
  2. 必ず映像処理用のデモページを先にアクセスしてください。本デモでは、カメラ配信側に待機処理、リトライ処理を入れていません。順番を間違えてしまった場合には、映像処理用のデモページをリロード後、カメラ配信用のデモページをリロードしてください。
  3. カメラ配信用のデモページはタブレットでなくても、ほとんどすべてのスマホおよびブラウザで動作します。iPhone SE(Safari)でも動作確認済みです。

デモアプリの動作

左に未加工のカメラ映像、右に背景がぼやけた映像が写っているでしょうか? なめらかに動いていればデモ成功です。このデモをベースにお好みの映像処理を追加してください。タブレットで受信映像をテレカン相手に送れば、背景ぼかし加工付きのテレカンとなります。リモートから受信した映像をテレカン相手に送る方法については、本記事では省略いたします。

ハードウェアアクセラレーションなしとの比較

ハードウェアアクセラレーションなしだとどのくらい遅いのか体験してみましょう。
ヘッドレスブラウザを起動しているターミナルでCTRL+Cを押し、終了してください。次に下記コマンドでハードウェアアクセラレーションなしでデモページ(映像処理用)を表示します。「--use-gl=egl」を省略しています。

google-chrome --headless --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222 https://codepen.io/terry_a/pen/wvGXdBN

タブレット側のページをリロードすると、私の環境では0.5〜2FPSくらいの速度になりました。この差がハードウェアアクセラレーションの有無です。

まとめ

ヘッドレスブラウザによる映像処理の有用性を感じていただけましたでしょうか? 本記事ではデモコードを短くする目的でたくさんの処理を省略しています。音声処理、再接続処理、待受処理、複数同時入出力、などです。興味がありましたら、ぜひ修正を加えて下さい。

有料サービスのご紹介

WebRTCを利用した会員制ライブ配信サービスを短期間で導入したい方、大規模配信のためのサーバ構築・インフラ運用を専門家に任せたい方は「ImageFlux Live Streaming」をご検討下さい。本記事にあるP2Pではなく、WebRTC SFUという技術を用いて、配信映像をサーバに中継させる仕組みです。1対多の会員制映像配信に特に強みがあり、初期の利用コストが低価格に抑えられます。

参考

Ayame Lite
時雨堂様のAyame Liteのおかげで短いコードでP2Pアプリケーションを実装できました。この場をお借りして感謝申し上げます。