UnityでTHETA SのWifiストリーミングをする手法メモしてみました
実現させること
vine.co
上記のことをUnityで実装する方法です。
2016 8/25追記
warapuriさんがUnityプロジェクトを公開してくださっているので、手っ取り早く試してみたい方は下記のUnityプロジェクトを使ってみてください。
github.com
________________________________________________________
以下、解説です。
APIについて
Wifiライブストリーミングを扱う際に、APIとしては_getLivePreviewを使用します。
公式リファレンス
他のAPIと違い_getLivePreviewに関しては、ストリームでデータが垂れ流しで渡されるため、リクエスト完了まで待つWWWクラスで取得することができません(たぶん)。
処理の流れ
1.HttpWebRequestクラスを作成しPostリクエストを設定
string url = "thetaのHttpパスをここに入力します"; var request = HttpWebRequest.Create (url); HttpWebResponse response = null; request.Method = "POST"; request.Timeout = (int)(30 * 10000f); // タイムアウトしないようにする request.ContentType = "application/json;charset=utf-8"; byte[] postBytes = Encoding.Default.GetBytes ("jsonデータをここにいれます"); request.ContentLength = postBytes.Length;
2.byteデータを取得するためBinaryReaderのクラスを生成します(1byteずつ取れます)
// ポストデータの送信開始 Stream reqStream = request.GetRequestStream (); reqStream.Write (postBytes, 0, postBytes.Length); reqStream.Close (); stream = request.GetResponse ().GetResponseStream (); BinaryReader reader = new BinaryReader (new BufferedStream (stream), new System.Text.ASCIIEncoding ());
3.mjpegの1枚画像の開始byte〜終了byteで画像を切り取る
Mjpegの仕切り値をbyteでチェックして切り取るという感じです。
...(http) 0xFF 0xD8 --| [jpeg data] |--1枚の画像 0xFF 0xD9 --| ...(http) 0xFF 0xD8 --| [jpeg data] |--1枚の画像 0xFF 0xD9 --| ...(http)
python - How to parse mjpeg http stream from ip camera? - Stack Overflow
※ Mjpegの仕様の仕切り値
開始2byteが0xFF、0xD8で、終了byteは0xD9
コードはこんな感じになるかと
List<byte> imageBytes = new List<byte> (); bool isLoadStart = false; // 画像の頭のバイナリとったかフラグ byte oldByte = 0; // 1つ前のByteデータを格納する while( true ) { byte byteData = reader.ReadByte (); if (!isLoadStart) { if (oldByte == 0xFF){ // 画像の最初のバイナリ imageBytes.Add(0xFF); } if (byteData == 0xD8){ // 画像の2番目のバイナリ imageBytes.Add(0xD8); // 画像の頭をとったので終了バイナリを獲得するまでとる isLoadStart = true; } } else { // 画像バイナリの配列にいれます imageBytes.Add(byteData); // byteが終了byteだった場合 // 0xFF -> 0xD9の場合、終了byte if(oldByte == 0xFF && byteData == 0xD9){ // 画像の終了byteなので // ここで溜まったbyteから画像を生成し、テクスチャの作成をすることができる // imageBytesをテクスチャに反映して // imageBytesを空にしておく // 画像の頭のバイナリ取得のループに戻る isLoadStart = false; } } oldByte = byteData; }
※ 2016 5/25 宣言がループ内にあったのと、フラグがわかり難かったので修正しました
※ 2016 8/23 画像の終了byteチェックでバグ(一つ前のbyteのチェックが抜けていた)があったので修正
4.区切ったbyteでテクスチャ生成
Byteをテクスチャに反映させます
mainTexture.LoadImage ((byte[])imageBytes.ToArray ());
ちょこちょこ端折っていますが、こんな感じでなんとか実装することが可能です。
もっといい方法もありそうですね!