Help us understand the problem. What is going on with this article?

DeviceConnectでTHETAのリアルタイムビューワーを作る

More than 3 years have passed since last update.

DeviceConnectのTHETAプラグインには、リアルタイムプレビューの機能が備わっています。THETAの映像をリアルタイムに読み込んで、画像として表示できます(via メディアストリーミング録画API - DeviceConnect Usersのカメラの映像をプレビューする)。データは懐かし(?)のmultipart/x-mixed-replaceで送られてくる形です。

すごく簡単に言うと、

  1. プレビューAPIで画像データを取り込む
  2. 全天球の画像データを見やすい形に加工(Canvasに貼り付け)
  3. スマートフォンの加速度センサーを使って上下、左右の動きに追従させる

でできあがりです。

利用したライブラリ

DeviceConnectManagerとTHETAプラグインのインストール

今回はAndroid向けに作ってみたので、Device Web API Manager - Android Apps on Google PlayTHETAプラグインをインストールします。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を開きます。

Screenshot_ 2016-08-29 12.22.20.png

実行した動画は以下です。結構画質は粗いです。

https://www.youtube.com/watch?v=7oPKP1bZHSU


ソースコードはDeviceConnectUsers/theta_viewerにアップしてあります。AndroidとTHETA m15またはTHETA Sがあれば、JavaScriptだけでリアルタイムビューワーが作れますのでぜひやってみてください。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away