格安で遠隔視点型HMDを作る (AndroidスマホでGstreamer)

## やりたいこと

当方ゲーマーではないのですが、HMD(ヘッドマウントディスプレイ、VRゴーグル)ってどんなんだろう、と少し興味がわきました、（想像ですが、映像にフィルタ掛ければ漫画の中に入れる体験とかできんの？2次元の世界に没入できたら楽しそうだなぁ、とか、）
とはいえVIVEとかMetaとか5万以上かかるしなぁ、貧乏人の自分がいきなり買うのは高そうだなぁ、、

そうだ！余ってるスマホを活用(Gstreamerとか組み込んで)して、VRゴーグル風に2眼分映せば何か感じ取れるんじゃね？

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/24654492-52f8-2be0-466e-4a4f3ab73f46.png">



## 今回使う機材と構成

### 使うハード、ソフト(ライブラリ)
1. 端末A Galaxy S10 (カメラ/映像送信機) ⇒眠ってたAndroid端末その1 
2. 端末B Pixel 6 (VRゴーグルの画面部/映像受信機) ⇒眠ってたAndroid端末その2 
3. ダンボールゴーグル (VRゴーグルの筐体) ⇒前に100均（セリア）で買った 
4. Gstreamer(Android版) https://gstreamer.freedesktop.org/ ⇒今回のキモ 
  ※Android版Gstreamerライブラリのリンク方法や叩き方は割愛、後述の参照[2]のソース等を見てください。基本JNIで叩くだけだけ
<img width="70" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/c770110e-b70c-d4bb-8a6a-b4e5c6158d83.jpeg">　　　<img width="70" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/981f5c55-03c4-bde6-ed45-8be4becb807a.jpeg">　　　<img width="70" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/871be142-22a4-e326-5570-bb5add2b02c5.png">　　　　<img width="140" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/ebe6df52-6af4-48f9-2585-4bb18e4e893b.png">

### 構成とデータの流れ
　端末Aで撮った映像をローカル無線(テザリングネットワーク)上にH264/RTP映像を流し、端末Bで2眼それぞれで表示してVR風に表示させることを目指します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/87caae5c-a0c6-47e9-24cc-f7100c2f176e.png">


## Gstreamerとは
GStreamerとは動画の一連の処理(デマックス、デコード、フィルタ、ストリーム分岐、など)をカスタマイズする事が容易なメディアフレームワーク。予め用意された機能(プラグイン)を'!'(接続子)で繋げる事でパイプラインとして設計し、柔軟にデータ処理をプログラミングする事が出来ます。(参照[1])

### コマンドライン例
~~~~ruby:コマンド (Windows版Gstreamerコマンドで確認)
gst-launch-1.0 -v filesrc location=hoge.mp4 ! qtdemux name=demux  demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
~~~~
#### 解説
ローカルにある"hoge.mp4"をqtdemux(Quicktime形式のデマクス処理)で映像と音声に分岐し、decodebin(自動でコーデック判別して最適なデコーダを選択するもの)でデコードし、autovideosink/autoaudiosink(最適な映像／音声レンダラを自動で提供)で出力
※普通のMP4プレイヤを模擬すると上記のようなパイプライン処理になります


## 今回構成でのGstreamerパイプライン
### 1. 送信側
 カメラで撮った映像を分岐させ、1つめはSurfaceViewへ表示、2つめはh264エンコードしてRTPで送信
※glimagesinkはAndroidのSurfaceView、ahcsrcはAndroidのカメラとリンク可能なエレメントです。（参照[2]）
~~~~ruby:パイプライン
"ahcsrc name=ahcsrc ! capsfilter name=filter caps=video/x-raw,width=640,height=480,framerate=30/1 ! tee name=tee tee. ! queue name=video_queue ! glimagesink name=vsink tee. ! queue name=udp_queue ! videoconvert ! openh264enc bitrate=5000000 ! h264parse ! rtph264pay pt=100 mtu=1400 config-interval=3 ! udpsink host=\"192.168.xx.yy\" port=9000"
~~~~
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/77836f25-f125-3618-e77d-60b573ab20e4.png">

### 2. 受信側
 port9000で受信したRTPをデコードして2分岐、それぞれを別のSurfaceViewで表示
※左右の目で見せるSurfaceViewを用意し、teeで分岐させたglimagesinkにリンクさせてます
~~~~ruby:パイプライン
"udpsrc port=9000 ! application/x-rtp,media=video,encoding-name=H264 ! queue ! rtph264depay ! avdec_h264 ! videoconvert ! tee name=tee tee. ! queue name=video01_queue ! glimagesink name=vsink_01 tee. ! queue name=video02_queue ! glimagesink name=vsink_02"
~~~~
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/a1125575-546d-0851-ced8-fabc365a4eba.png">


## 完成！！
### 動作している送信機と受信機
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/d2b540a6-0554-979f-a573-5f36eb3a1163.gif">

### ゴーグル化！​
<img width="25%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/a2a081b9-cc2e-1027-8db6-84b57fee799f.png"><img width="25%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210612/4f2716b3-c1e0-e81e-b8bc-922099a26135.png">


## あとがき（この試作の利用？発展させる方向性）
・外部から映像を受け取って、受信機(2眼)で見るってのは応用が利きそう
　⇒映像ソース側でフィルタとか加工すれば面白いVRコンテンツとか作れるかも
・今回はRTPだったりWiFiのローカルNWでのP2Pだったが、別の構成やGstremaerパイプラインを使うことで、
　別の映像プロトコルつかったりインターネット経由で遠距離伝送もできそう。
・本物のVRゴーグルも使ってみたいなぁ、、

## 参照URL
■[1] RustでもGStreamer理解がしたい! その0 〜まずはGStreamerパイプラインを書こう 〜
 https://qiita.com/alivelime/items/50d796c09baabb765625

■[2] Example Android App for AHCSRC
 https://github.com/justinjoy/gst-android-camera