先週は、3D動画をストリーミング再生する方法についてご紹介致しました。
今週は、三週間ほど前に記事にしていた性能改善について、ある程度結果が出たので、その報告を行います。
性能を改善する際に、ネックになっていた場所は、以下2点です。
・通信速度が 4fps しか出ない
・THETAから送られてくる画像を保存する速度が、秒間10枚程度しか出ない
また、上述のボトルネックがあるため、画質を落としているという状況でした。
どちらの性能も引き上げることができないと、満足のいく結果となりません。
■通信速度の改善
元々は、サーバに「node.js」、クライアント側は「C++」を利用して通信を行っていましたが、調査したところ、以前の記事でも紹介した通り、httpサーバの「nginx」のアップロードが速いと判断できたため、こちらを利用してみます。
「nginx」のアップロードが速い理由は2つあり、1つは「nginx」自体がC言語ベースで作成されていること。
もう1つは、「nginx」のプロセス自体で、ファイルのアップロード処理を完結させることができることです。
特に後者は、秒間大量のファイルをアップロードする本システムの仕組みを高速化するのに効果的であると判断しました。
この時の構成は、サーバは前述のとおり「nginx」、クライアント側は「Java」で、アップロード処理については「HttpURLConnection」を利用して自作します。
<測定結果>
サーバ | クライアント | アップロード枚数 |
---|---|---|
node.js | C++ | JPEG圧縮率80で、4枚/秒 |
nginx | Java | JPEG圧縮率95で、15枚/秒 |
※THETAから送信されてくる画像は15FPSです
■画像保存速度の改善
THETAから送られてきた画像を、USBライブラリを利用して取得しているのですが、元々は、TextureViewに描画されたデータを元に、画像保存処理を行っていました。
しかし、さらに調査を行ったところ、このUSBライブラリには、受信した画像データをそのままバイナリデータとして受け取れるIFがあることがわかりました。
当然、IF経由でバイナリデータを直接受け取る方が速いと考え、そのデータを元に画像の保存処理を行うように修正します。
<測定結果>
保存方法 | 保存枚数 |
---|---|
TextureViewのデータを画像として保存 | JPEG圧縮率80で、10枚/秒 |
USBライブラリから受信したバイナリデータを画像として保存 | JPEG圧縮率95で、15枚/秒 |
※THETAから送信されてくる画像は15FPSです
■改善結果
上述の2つの改善を行うことで、15FPS分の画像を、問題なくアップロードできるようになりました。
■画質について
これから音声を組み合わせること、仕組み的に大量の画像が必要となるため、できれば画像1枚のサイズは小さいほうが好ましいです。
実際に測定してみて、通信速度や、画像保存速度については、JPEG画像の圧縮率を95まで引き上げても問題なく動作することがわかりましたが、上述の理由から圧縮率を色々変更して、実際に3Dパノラマ動画として再生してみました。
この結果、品質的には圧縮率80まで落としても、問題ないように感じました。
このため、今回のシステムでは、圧縮率80を採択することとします。
※圧縮率75まで落とすと、明らかに品質が劣化します
■動画作成に利用するffmpegコマンドについて
画質の改善として、Android端末からサーバへ送信する画像については問題のない品質となりましたが、実際の動画品質を決定する際は、ffmpegコマンドに指定するパラメータも重要になります。
ffmpeg 自体でも画像や音声に対して圧縮処理を行うため、元の画像の品質がいくら高くても、ffpmeg側で高圧縮設定にしてしまうと、結局品質が悪くなります。
どういう設定値が良いかは、色々な値で実際に動画を作成してみて、見比べる以外に方法はありません。
私の方で確認したところ、品質固定モードの26迄であれば、3Dパノラマ画像を見るのに問題のない品質かなと感じました。
<改善後の構成図>
■これ以上の改善が必要となるかどうかについて
今、THETAとAndroid端末は、USBで接続しています。
この場合、THETAから送信されてくる画像サイズは、「1280×720」固定です。
しかも、この数値は3Dパノラマ表示にする前の状態なので、実際に人間が見られるように画面に表示する場合は、さらに解像度が低くなってしまいます。
このため、もっと大きい画面で見たい、ということになった場合は、元の画像サイズが決まっている以上、品質向上には限界があります。
これについて改善を行う場合、THETAとAndroid端末を、HDMIで接続する方法が考えられます。
といっても、Androidには基本、USBコネクタしか無いので、HDMIの入力を、USBに変換する必要があります。
HDMIからUSBへの変換には、別途コンバーターが必要となりますが、既に製品自体は複数存在しますので、THETA(HDMI)⇒コンバーター⇒Android(USB)、というように接続することはできそうです。
※ただし、コンバーター自体は、結構いい値段します
もし、HDMI接続で画像を取得できれば、このときTHETAから送信されてくる画像サイズは、「1920×1080」まで一気にアップします。
ただ、そうなると画像保存や通信速度について、今と同じロジックでは満足のいく速度にならない可能性があります。
今後、USB接続からHDMI接続に切り替えるかどうかも含め、必要と判断した場合には、更なる改善を行ってまいります。
最後までご覧いただき、ありがとうございました。
弊社では全国各地の請負い(ご自宅)で作業協力頂ける、フリーランスエンジニアの方を常時探しております。
ご興味ある方は、お気軽にお問い合わせ下さい。