週末にやっていたメモがてら。
以前某氏から譲っていただいたTHETA Sを愛用している。一時期は旅行へ行ってひたすらTHETAだけで写真を撮るという時期もあった。最近は自分の中でコンデジが復権してきたので出番が少なかったのだけど、遠出する時には旅行鞄へ入れておこうかな、という程度には気持ちが高まってきた。
矢先のことである。
THETAシリーズはスマフォとの連携を前提とするユースケースが多く、撮影した写真は基本的にWi-Fi経由でスマフォへ転送して加工・SNS類へという流れ。
この役目はTHETAアプリとTHETA+アプリのふたつが分担する。
前者がTHETA本体内の写真をWi-Fi経由で転送したりリモートシャッターとしてライブプレビューを見ながらISO値や露出時間を設定して撮影したりという機能を持つ。
後者は転送済み写真を加工するアプリで、様々な効果を加えたり連続した制止画を動画にまとめる機能もある。
スマフォをEssential PH-1へ買い替えたので一応接続テストをしておくか、と試してみると全然THETAへつながらない。
手持ちの古い端末にはつながるので、差分はOSバージョンだろうと当たりをつけて得た結論はこれ。
挙動を観察してると、THETA公式アプリはClearText Trafficの許可処理をサボっていてAndroid 9.0では哀れなことにWi-Fi経由のTHETA(192.168.1.1)へのHTTPトラフィックが遮断されてる模様。
— Kei Nakazawa (@muo_jp) 2018年10月6日
アプリページでの告知は無し、同様の不具合を訴えてる人は居る https://t.co/BzihzbzlND #THETA https://t.co/xFS4LlrPB9
Cleartext Traffic対応はNetworkSecurityPolicyのapplication属性とXMLで処理するのだけど、まだRICOH内で対応してない模様*1。
[*1] usesCleartextTraffic属性の一発指定でもなんとかなりそうではある
また、Wi-Fiからインターネットに出られるか怪しい際にトラフィックを自動的にLTEや3Gといったモバイル回線へと振り向ける機能とも相性が悪そう。これに関してはTHETAのWi-Fi APへつながった直後にbindProcessToNetworkでアプリのデフォルト経路を設定してやるのが無難だろう。
適切にこの処理をするためには何かしらの方法で接続先Wi-FiのNetworkインスタンスを取得する必要がある。ConnectivityManagerに用意されているネットワーク絞り込み用の定数類は明らかにこの用途を満たさないため、自力でNetworkインスタンスを得ることになる。APIをいくらか掘った限りでは残念ながらdeprecatedな要素を利用するしかなかった。WifiInfoあたりにNetworkインスタンスを取得するAPIが生えていればstraightforwardだと思うのだけど。
下調べをできたので、前述のようなネットワーク接続まわりの厄介を一定カバーするようにコードへ落としていった。現状は https://github.com/muojp/oscsync/。
THETAがサポートしているOpen Spherical Camera APIを利用すると、プレビュー取得や写真撮影・各種撮影用設定までWi-Fi経由のHTTPリクエストで完結できる*2。
[*2] APIがRESTfulかというとまあHTTP APIという表現のほうが無難だろう
Googleが公開している公式ドキュメント:https://developers.google.com/streetview/open-spherical-camera/?hl=ja優れているのでほぼ迷わない。
OSC APIはLevel 1とLevel 2が定義されており、THETA SはLevel 2対応だと自称するレスポンスを返すのだけど、実際にはLevel 1のみサポートしている(試した範囲では)ところにちょっとハマった。
やはりTHETA SはAPI Level 1のみ実装しているようなので、撮影はcamera.startSession → camera.takePictureの手順。
— Kei Nakazawa (@muo_jp) 2018年10月4日
Wi-Fi接続直後の状態で/osc/stateを叩くとSID_0000が見えるけど、そのまま使うとエラーが戻ってくるのでstartSession必須。
しかしcurlだけでピヒョンと鳴らせたので実際勝てる
初期調査の段階でここまで試行錯誤できたところでまあ大丈夫だろうと思うに至った。
あとはGenericsを利用するクラスに対して::class.javaを叩きたいとか、suspend functionはasyncキーワードというよりはyieldに近い印象とか、暗黙のitは便利とか、coroutinesの起動用launchは現行仕様だとDispatcherをプログラマに意識させるようになってる(少なくともAndroid Studioは暗黙のlaunch { }に対して文句を言う)のかーとか、最終引数のラムダは引数リスト外へ出す慣習らしい(Swiftもそうらしい)とか、主にKotlinへ馴染みが薄いのをカバーする時間だった。
ESP8266でリモートシャッターを作るぐらいなら簡単にできる。ESP8266はESP32と比べてメインメモリの少なさが問題になりがちだが、THETA SのAPIは完全にHTTPであり、撮影までに必要なコール回数もかなり少ないため、メモリ上で最低限のJSON処理ができれば十分だろう。
現時点でOSC API Level 1デバイスへの接続・セッション開始・撮影機能はつけたので最低限のリモートシャッターとしては動作する状態になっている。
しかしRICOH THETAは本当に面白いハードウェアで、ついついソフト側でもやりたいことが増えてしまう。
setOptionというAPIでISO値や露出時間は設定できる。
これ自体は公式のTHETAアプリでもライブプレビューを見ながらできるものだが、個人的には「暗所用の高ISO・短時間露光」「暗所用の低ISO・長時間露光」「日中の低ISO・短時間露光」あたりを自分の好みで数種類用意しておいて撮影時にシュッと設定したいものである。
調べ損なっていたが、一脚とあわせてセルフタイマー撮影も結構楽しいのでアプリ上から楽にモード設定できるとよい(公式THETAアプリではメニュー階層が深くて不便)。
THETA本体内の写真をいい感じのルールで取り込む仕組みは必要だと思っている。とりわけ、THETAから日々生み出される巨大なJPEGファイルをAndroid端末内にずっと置いておくわけにはいかないので、選別あるいはなんらかのクラウドサービスへと同期してローカル分を削除するのが一般的だろう。
個人的には写真枚数が多い場合の高速転送にはUSB(MTP)を使うのが好きで、USBホストアダプタは常時持ち歩いてる族。
THETA Sに関してもAndroid端末へUSB接続してAndroid組み込みのファイルエクスプローラから/Pictures/RICOH THETA/以下へ写真をコピーすることでそれなりの高速・低ストレスを実現できることは確認してある。
最終更新: 2018/10/08 18:55(UTC)Copyright © Kei Nakazawa 2017, Licensed under CC-4.0-BY unless otherwise noted.