DeviceConnectのTHETAプラグインには、リアルタイムプレビューの機能が備わっています。THETAの映像をリアルタイムに読み込んで、画像として表示できます(via メディアストリーミング録画API - DeviceConnect Usersのカメラの映像をプレビューする)。データは懐かし(?)のmultipart/x-mixed-replaceで送られてくる形です。
すごく簡単に言うと、
- プレビューAPIで画像データを取り込む
- 全天球の画像データを見やすい形に加工(Canvasに貼り付け)
- スマートフォンの加速度センサーを使って上下、左右の動きに追従させる
でできあがりです。
利用したライブラリ
DeviceConnectManagerとTHETAプラグインのインストール
今回はAndroid向けに作ってみたので、Device Web API Manager - Android Apps on Google Play と THETAプラグインをインストールします。THETAプラグインは野良なので、Androidのセキュリティ設定を変更するか、自分でビルドしてください。
DeviceConnectの接続まで
基本的なコードはDeviceConnectアプリケーションの作り方 - DeviceConnect Usersでできます。
URLを取得した後の処理を書く
今回の処理は全体として次のようになります。DeviceConnectのセットアップが完了後、thetaImageUrlを実行します。その結果、プレビューのURLが送られてきますので、それをThViewに適用して表示します。
$(function() {
// DeviceConnectの生存確認
var dc = new DeviceConnect({
applicationName: "thetaViewer"
});
dc.setup()
.then(function() {
return dc.thetaImageUrl();
})
.then(function(url) {
var img1 = new ThView({
id:'image1',
file: url,
rendererType: 1,
width: 980,
height: 560
});
}, function(error) {
alert(error)
alert("DeviceConnectが起動していません");
})
});
THETAのプレビュー画像を取得する
dc.thetaImageUrl()の内容です。ここはjQueryを使いました。全体の処理は次のようになります。 me.getMediaRecorder
が成功するとカメラのIDが返ってきますので、 me.getPreviewUrl
を実行して、プレビューできるURLを受け取ります。
p.thetaImageUrl = function() {
me = this;
var p = new Promise(function(resolve, reject) {
var id = me.findService("theta");
if (typeof id == 'undefined') {
return reject({
errorCode: 99,
errorMessage: 'THETA is not found.'
});
}
me.getMediaRecorder(id)
.then(function(result) {
var recorder_id = result.recorders[0].id
return me.getPreviewUrl(id, recorder_id);
})
.then(function(result) {
return resolve(result.uri);
})
.fail(function(error) {
return reject(error);
})
});
return p;
}
me.findService
は次の通りです。指定した文字で始まっているサービスのIDを取得するだけです。開発中はthetaではなくhostにしておく方が良いです。
p.findService = function(name) {
for (i in this.services) {
if (this.services[i].id.toLowerCase().indexOf(name.toLowerCase()) == 0) {
return this.services[i].id;
}
}
}
me.getMediaRecorderについて
では me.getMediaRecorder
についてです。カメラの一覧を取得するWeb APIを叩きます。
p.getMediaRecorder = function(id) {
me = this;
return $.ajax({
url: me.host + "/gotapi/mediastream_recording/mediarecorder",
type: "GET",
data: {
serviceId: id,
accessToken: me.accessToken
}
});
};
me.getPreviewUrl について
サービスIDとカメラIDでプレビューURLを取得するWeb APIを叩きます。
p.getPreviewUrl = function(id, recorder_id) {
me = this;
return $.ajax({
url: me.host + "/gotapi/mediastream_recording/preview",
type: "PUT",
data: {
serviceId: id,
accessToken: me.accessToken,
target: recorder_id
}
});
};
これで、例えば http://localhost:9001/1
といったURLが返ってきます。
ThView.jsの修正点
デフォルトのThView.jsでは幾つかの問題があったので、修正しました。
- multipart/x-mixed-replaceに対応していないので画像が更新されない
- なぜか上下逆さまに…
- 画像を上下逆にすると、左右上下の動きまで逆に…
これはThView.js側ではなく、適用する画像に起因するものだと思われます。
修正点は以下の通りです。
-90回転した際に、
// 元
this.mesh.rotation.y = this.degree[1] + alpha - Math.PI / 2;
this.camera.rotation.z = -beta + Math.PI;
// 修正後
this.mesh.rotation.y = this.degree[1] + alpha + Math.PI / 2;
this.camera.rotation.z = -beta;
レンダリング実行前に、
self.texture[0].needsUpdate = true; // これを追加
renderer.render(scene, self.camera);
としました。
ファイルの転送
できあがったアプリをデバイスに送る際にはadbを使います。
$ adb push path_to_dir/theta_viewer /sdcard/data/data
後はAndroidのChromeブラウザでアップしたファイルのindex.htmlを開きます。
実行した動画は以下です。結構画質は粗いです。
ソースコードはDeviceConnectUsers/theta_viewerにアップしてあります。AndroidとTHETA m15またはTHETA Sがあれば、JavaScriptだけでリアルタイムビューワーが作れますのでぜひやってみてください。