高解像度Motion JPEGストリーミングを低遅延で再生するAssetをプレビュー公開しました。

これは何?

このAssetを使うと、GearVR などで FullHDなどのMotion JPEG ストリーミングを低遅延(おおよそ0.2~0.4秒以内)で再生できます。ということは、THETA SのUSB/HDMIライブビューなんかをRaspberryPiやPC経由でWi-Fiで飛ばしてGearVRで一人称視点で眺める、つまりテレイグジスタンスっぽいことができるかも!です。あるいは、リアルタイム性を活かして、Raspberry Piとラズパイカメラを載せたラジコンから映像を飛ばしてFPV(一人称視点操作)なども可能です。

発端

以前の記事で、Raspberry PiからMotion JPEGでGearVRに配信するということを行いました。

hammmm.hatenablog.com

AVI Player with Playmaker actions というAssetの中のMovie Streamerを利用しましたが、遅延が数秒以上になることと、fpsが低いという問題がありました。

また、HLSでの配信も試しましたが、こちらは遅延が数十秒と、リアルタイム性に大きな問題をかかえていました。

そんなときにのしぷさんの記事

noshipu.hateblo.jp

を拝見して、Motion JPEGのデコード方法がわかったので、これだ!と思ってGearVRで動かそうとしてみましたが、ソースが高解像度の場合、単純な実装では安定動作しないことがわかりました。高画質で低遅延を実現するには、以下の問題をクリアする必要がありました。

  • 遅延(読み取りが遅く、未読み取りのフレームがサーバー側に貯まる問題)
  • 遅延(読み込み済みの後のキューが伸びてしまう問題)
  • ネットワーク読み込み速度の問題
  • メインスレッド負荷の問題

これらに対策を打った結果が今回のAssetになります。結果的にそれなりの規模の実装になってしまいました。ついでにAsset Store掲載を画策しているところです。

のしぷさんと、サンプルプロジェクトを作られた伊藤さん(@warapuriさん)に感謝しています!

特徴

www.youtube.com

  • スレッドを利用して、最大限サーバーの出力に追いつくように実装しています。
  • JPEGデコードはlibjpeg-turboを利用して高速化しています。
  • バックグラウンドスレッドでデコードするようにしています。これにより、メインスレッドに大きな負荷をかけず、スムーズな描画を阻害しません。
  • バッファの再利用により、メモリ使用/確保量もできるだけ抑えるようにしています。

ダウンロードについて

プレビュー版ということで、しばらくの間無料配布いたします。なお、もし商用利用されたいというような場合がありましたらお問い合わせください。

こちらからダウンロードできます。キーは mjpg です。

[Unity] MJStreamingPlayer Asset - BowlRoll

対応プラットフォーム

現状、Android (GearVR) および Windows 32/64bit 対応です。 Unityはちょっと古いですがバージョン5.3.4で確認しています。

利用可能なサーバープログラムの例(確認済み)

組み込み方法

  1. 本Asset (MJStreamingPlayer.unitypackage)をプロジェクトにインポートしてください。
  2. 再生対象マテリアルを持つGameObjectに、MJStreamingPlayerコンポーネントを追加してください。
    • 現在の仕様では、メインのマテリアルが持つメインのテクスチャとして、動画テクスチャがセットされます。
    • 特にこだわりがなければ、シェーダは Unlit/Texture にしてください。デフォルトの Standard シェーダも利用可能です。
  3. MJStreamingPlayerコンポーネントを設定してください。
    • ServerUrl: MJPGストリーミングサーバーのストリーミングURLをセットしてください。
    • PlayAutomatically: 自動で再生開始する場合はONにしてください。OFFの場合は、スクリプトからStartStreaming() を呼ぶ必要があります。
  4. 上記GameObjectが見えるようにCameraを設定し、UnityでPlayしてください。

組み込み例

  • 前項の方法で、以下の記事のプロジェクト(Oculus RiftでTHETA画像を表示)にも組み込めます! hammmm.hatenablog.com

  • 設定例

    WebCamDrawerは無効化して、かわりにMJStreamingPlayerを追加しています。 f:id:hammm:20161214210934p:plain

  • 動作例

    ※ここでは、Unityと同じPCで GMax IP Camera を動かし、THETA S のHDMI出力を FEBON178 経由でUSBウェブカメラ扱いで入力しています。 さらに、Android向けにして、osig, bundle-id等を設定するとGearVRでの動作も可能でした。 f:id:hammm:20161214230528j:plain

動作

  • フレームレートはサーバーが送信する速度および描画速度に依存します。
  • 無駄なデコードを避けるため、表示可能なフレームレート以上のデコードは行わず、スキップします。
  • テクスチャサイズはサーバーが送信するMJPGの画像サイズに依存します。

サーバーURL設定例

  • mjpg_streamerの場合
  • GMax IP Camera (MJPG版)の場合
  • webcamxp 5の場合
  • ホストのIPアドレス、ポート番号の求め方
    • LAN内の場合
      • IPアドレス サーバープログラムを実行しているPCのLAN上でのIPアドレスを取得します。
      • ポート番号 サーバープログラムによって、デフォルトのポート番号は異なります。サーバープログラムのドキュメントを参照してください。
    • インターネット上のサーバーの場合
      • IPアドレス、ポート番号 ネットワークの知識がなければなかなか難しいことですが、mjpegサーバーとなるPCが、グローバルIP経由でアクセスできる状況を作成してください。 上記サーバーにアクセスできるグローバルIPと、サーバープログラムが動作しているポート番号を利用します。

☠ データ通信料金に関するご注意 ☠

本Assetでは、MJPGストリーミング時だけでなく、大容量ファイルが置かれたURLを接続先に指定したケースなど、大量のデータ転送を発生させる可能性があり、特に従量課金制のネットワークをご利用の場合、課金が高額となる恐れがありますのでご注意ください。

今後の修正点

  • ターゲットマテリアルを変更できる機能は早々に実装するつもりです。

悩み

Unityで自前のスレッド利用時、まともにプロファイリングできないためにボトルネックがよくわからない、というのが悩みです。Unityのプロファイラは自前ワーカースレッドの負荷を別のスレッドにつけかえて表示してしまう印象があり、あまり役にたたない気がしています。

最後に

是非使ってみてください!