LoginSignup
52
51

More than 5 years have passed since last update.

Sony Camera Remote APIを使ってカメラを遠隔操作する -撮影編-

Last updated at Posted at 2015-11-23

※この記事の続編を書きました!こちらからどうぞ。

ソニーの カメラリモートAPI を利用して、アクションカム(HDR-AZ1)を自作プログラムから遠隔操作してみました。

DSC04449.edit.jpeg

カメラリモートAPIとは

最近のカメラはWi-Fi接続で遠隔操作できるものが増えています。たいていは各カメラメーカーの専用のアプリからのみ利用可能ですが、ソニーはその通信仕様を公開しており、 誰でも自由にカメラを利用したアプリケーションを作成することが可能 です。

どのカメラだったら使えるの?

残念ながら、カメラリモートAPIはソニー製の全てのデジタルカメラで使えるわけではありません。こちらのページから、リモートAPIに対応している機種を確認することができます。アクションカムは全機種対応で、その他のデジカメも2013年頃の機種から対応しています。

どうやって使うの?

まず、ソニーの開発者向けサイトからカメラリモートAPI SDKをダウンロードしておきましょう。チュートリアル、APIリファレンス、サンプルコードが同梱されています。
カメラリモートAPIの使い方の流れは以下の通りです。

  1. PCからアクションカムにWi-Fi接続
  2. SSDPでアクションカムのデバイス情報を取得
  3. JSON-RPCでアクションカムにHTTP POSTし、APIを呼び出す

それでは、これからこちらのサンプルコードを使って 「リモートで動画撮影の開始・終了を行う」 ところまで説明していきます。言語はRubyを使いますので、環境の無い方は公式サイトなどを参考にインストールしてください。バージョンは2.2.3で動作確認しましたが、おそらく1.9.3以上なら動くと思います。

1. PCとカメラをWi-Fi接続する

まずはこちらの方法でアクションカムのSSIDとパスワードを調べ、PCからアクションカムにWi-Fi接続します。
GUIのメニューから設定してもOKですが、自作プログラムに組み込むことを考慮するとスクリプト化しておくのが理想です。Linux用(Raspberry Pi対応)Mac用を用意しましたので、良かったら使ってみてください。下記のようにコマンドラインから接続できます。

$ bash wificonn_linux.sh <interface-name> <network-SSID> <password>
$ bash wificonn_mac.sh <network-SSID> <password>

2. SSDPでカメラのデバイス情報を取得する

SSDPとは、同一ネットワーク上にあるUPnP対応デバイスの検索を行うための規格です。詳しくはこのサイトの説明がわかりやすくて参考になります。
RubyではfriskyというgemをインストールすればSSDPを使えるようになります。
ついでにhttpclientnokogiriも入れておきましょう。

$ gem install frisky httpclient nokogiri

まず、以下のようにしてSSDPでデバイス検索を行います。

camera_remote_test.rb
require 'frisky/ssdp'
require 'httpclient'
require 'nokogiri'
require 'json'
require 'pp'

# SSDPで所定のデバイスを検索
SSDP_SEARCH_TARGET = 'urn:schemas-sony-com:service:ScalarWebAPI:1'
SSDP_SEARCH_RETRY   = 3
SSDP_RETRY_INTERVAL = 5
try = 1
while true do
  response = Frisky::SSDP.search SSDP_SEARCH_TARGET 
  if ! response.empty?
    break
  elsif try < SSDP_SEARCH_RETRY
    try += 1
    puts "SSDP discover failed, retrying... (#{try}/#{SSDP_SEARCH_RETRY})" 
    sleep(SSDP_RETRY_INTERVAL)
  else
    puts "The device not found."
    exit 3
  end
end
pp response
puts 'SSDP discover succeeded.'

デバイス検索は一回だけだと失敗することもあるので、念のため何度かリトライしてやります。
Frisky::SSDP.searchメソッドの引数は検索ターゲットで、カメラリモートAPI特有の文字列を指定してやります。何も指定しない場合は同一ネットワークの全てのデバイスが得られます。
これを実行するとアクションカムより以下のようなレスポンスが返ってきます。

実行結果
[{:cache_control=>"max-age=1800",
  :ext=>"",
  :location=>"http://192.168.122.1:64321/dd.xml",
  :server=>"UPnP/1.0 MINT-X/1.8.1",
  :st=>"urn:schemas-sony-com:service:ScalarWebAPI:1",
  :usn=>
   "uuid:000000001000-1010-8000-FEC2DEEB77DC::urn:schemas-sony-com:service:ScalarWebAPI:1"}]

最も重要なのは:locationをキーとするhttp://192.168.122.1:64321/dd.xml です。
このdd.xmlはデバイスデスクリプションというもので、カメラリモートAPIを利用するために必要な情報が書かれています。これをHTTP GETで取得し、nokogiriを使ってパースしてやります。

camera_remote_test.rb(続き)
# デバイスデスクリプション解析
dd_xml = Nokogiri::XML(dd)
if dd_xml.nil?
  puts 'Failed to parse XML.'
  exit 1
end
dd_xml.remove_namespaces!
camera_name = dd_xml.css('device friendlyName')
services = dd_xml.css('device X_ScalarWebAPI_Service')
endpoint_urls = {}
services.each do |sv|
  service_type = sv.css('X_ScalarWebAPI_ServiceType').inner_text
  endpoint_urls[service_type] = File.join(sv.css('X_ScalarWebAPI_ActionList_URL').inner_text, service_type) 
end

puts 'Endpoint URLs are:'
pp endpoint_urls

デバイスデスクリプションを取得すると、中身はこのようなXMLになっています。
特に重要なエレメントはX_ScalarWebAPI_ServiceTypeX_ScalarWebAPI_ActionList_URLです。
ServiceTypeはカメラリモートAPI群の分類で、以下の様なものがあります。

種別 説明
guide サポートするAPIサービスの取得
camera カメラ設定の取得変更、および撮影機能へのアクセス(最も使う)
system システム設定の取得変更
avContent メディアに記録された静止画・動画へのアクセス

ServiceTypeと対応するActionList_URLを/で繋げて<ActionList_URL>/<ServiceType> とすると、次節で使用する エンドポイントURL になります。
先ほどのコードを実行すると、以下のようにサービスタイプをキーとしたエンドポイントURLの連想配列が得られます。

実行結果
Endpoint URLs are:
{"guide"=>"http://192.168.122.1:8080/sony/guide",
 "accessControl"=>"http://192.168.122.1:8080/sony/accessControl",
 "camera"=>"http://192.168.122.1:8080/sony/camera",
 "system"=>"http://192.168.122.1:8080/sony/system",
 "avContent"=>"http://192.168.122.1:8080/sony/avContent"}

デバイス検索に失敗する場合は

SSDPはブロードキャストアドレスとして239.255.255.250のアドレスを使用しますが、ホストが複数のネットワークに接続している場合、ルーティングに問題がある可能性があります。仮に、ホストがwlan0で家庭内LANに接続し、wlan1でアクションカムに接続しているとしましょう。
239.255.255.250へのルートを調べるには、ip route getコマンドを使用します。

$ ip route get 239.255.255.250
multicast 239.255.255.250 dev wlan0  src 192.168.1.10
    cache <mc>

このように dev wlan0 と表示された場合、239.255.255.250にはwlan0を介した経路が設定されているため、デバイス検索はwlan0の接続しているネットワーク(家庭内LAN)内で行われます。そのため、wlan1のネットワークに接続しているアクションカムはSSDPの検索にヒットしなくなってしまいます。
wlan1を介した経路を追加するには、route addコマンドを使用します。

$ sudo route add -host 239.255.255.250 dev wlan1

再度ip route getコマンドを実行して、 dev wlan1 と表示されていればOKです。
こちらもスクリプトを用意しましたので、困ったら活用してください。

3. カメラにJSON-RPCでコマンドを送信する

JSON-RPCとはJSONを用いてリモートプロシージャコールを行う規格で、カメラリモートAPIの呼び出しにはこのJSON-RPCを使用します。
決められたフォーマットでJSONデータを作成し、前節で調べたエンドポイントURLに対してHTTP POSTを実行することでAPIの呼び出しが可能です。JSONデータのフォーマットは以下のように定められています。

キー
method 呼びだすAPIの名前
params APIに渡すパラメータの連想配列
id ユーザーがAPI呼び出しの識別に利用できる番号
version APIのバージョン

APIリファレンスによると、例えば "setShootMode" APIを用いて撮影モードを動画撮影に切り替えるJSONは以下のように書けます。静止画撮影やインターバル静止画撮影モードにするなら、paramsに渡す文字列をそれぞれ"still", "intervalstill"というように変えてやります。

setShootModeのJSON
{
    "method": "setShootMode",
    "params": ["movie"],
    "id": 1,
    "version": "1.0"
}

"setShootMode" APIのサービスタイプは"camera"なので、エンドポイントURLはhttp://192.168.122.1:8080/sony/cameraとなります。このアドレスに対し上記のJSONをPOSTすると、アクションカムのリモート手続完了後にレスポンスのJSONが返され、実行結果を確認することができます。
たいていのAPIは成功時に"result"キーと0の値のペアを返しますが、エラーの際には"result"は返されず、代わりに”error"キーとエラーコード・メッセージの値が返ってきます。

成功時
{
    "result": [0],
    "id": 1
}
失敗時
{
    "error": [2, "Timeout"],
    "id": 1
}

それでは、"setShootMode"に加えて"startMovieRec"と”stopMovieRec"という3つのAPIを使って、録画の開始・停止を実行してみます。"id"キーの値はAPIの実行順ごとに連番にしていますが、単純に同じ値を使っても大丈夫です。

camera_remote_test.rb(続き)
setShootMode_request = {
  'method' => 'setShootMode',
  'params' => ['movie'],
  'id' => 1,
  'version' => '1.0'
}
startMovieRec_request = {
  'method' => 'startMovieRec',
  'params' => [],
  'id' => 2,
  'version' => '1.0'
}
stopMovieRec_request = {
  'method' => 'stopMovieRec',
  'params' => [],
  'id' => 3,
  'version' => '1.0'
}

# 撮影モード切り替え->録画開始->録画停止
res = cli.post_content(endpoint_urls['camera'], setShootMode_request.to_json)
pp JSON.parse(res)
res = cli.post_content(endpoint_urls['camera'], startMovieRec_request.to_json)
pp JSON.parse(res)
sleep(5)
res = cli.post_content(endpoint_urls['camera'], stopMovieRec_request.to_json)
pp JSON.parse(res)

実行すると、録画が始まって5秒間経過したのち停止します。画面には下記のような出力が出て、APIが正常に終了したことを確認できます(stopMovieRecは、現状では成功時に空文字列を返すようです)。

実行結果
{"result"=>[0], "id"=>1}
{"result"=>[0], "id"=>2}
{"result"=>[""], "id"=>3}

終わりに

今回はソニーのカメラリモートAPIを利用して、PCから録画の開始・終了を実行してみました。
他にも、静止画撮影や撮影したコンテンツの取得、ライブビューの取得など、やれることは様々です。
今後も機会がありましたら解説記事を上げていこうと思います。
ちなみに、CanonやNikon、GoProも同様のAPIを公開しています。こちらの製品をお持ちの方は、是非トライしてみてください。

52
51
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
52
51