Windows与Sony Camera Remote API的兼容性

Tha*_*ris 3 windows camera sony windows-store-apps

在"如何使用Camera Remote API开发应用程序"中,它表示"Camera Remote API使用基于HTTP的JSON-RPC.因此,您可以将Camera Remote API与任何操作系统一起使用,例如Android,IOS或Microsoft®的Windows®".这是有道理的,因为协议是平台无关的.但是,在此页面上的相机兼容性图表中:http://developer.sony.com/develop/cameras/它指出必须安装Sony智能远程控制应用程序才能"启用API".由于该应用仅限iOS和Android,这是否意味着API无法在Windows上使用?

我非常有兴趣为Windows 8平板电脑开发远程控制应用程序,然后为Windows 8手机开发.但如果我无法控制A5000,A7R,A7,NEX-6,NEX-5R或NEX-5T,那么它就变得不那么有趣了.

是否可以使用普通的HTTP JSON通信来控制这些摄像机?

谢谢

Ern*_*run 9

我不知道你是否解决了你的问题,但我有同样的问题,我设法让它以某种方式使用C++.我花了一些时间来弄清楚我必须做什么,我从来没有做任何HTTP的东西,甚至没有开发的即插即用驱动程序,所以我将解释我是如何逐步完成的,因为我希望我已经解释过了.

在消息的最后,我给了我整个文件的链接,随便尝试一下.

我正在为每个与网络相关的问题使用boost asio库,以及更多(一切都是异步的,这是一个很棒的库,但对于像我这样无知的人很难掌握......).我的大多数函数都是从文档中的示例中部分复制粘贴的,这解释了为什么我的代码在某些地方很尴尬.这是我的主要功能,没有什么花哨我实现asio :: io_service,创建我的对象(我错误地命名为multicast_manager)然后运行服务:

#include <bunch_of_stuff>    
using namespace std;
namespace basio = boost::asio;    

int main(int argc, char* argv[]) {
    try {
        basio::io_service io_service;
        multicast_manager m(io_service, basio::ip::address::from_string("239.255.255.250"));
        io_service.run();
        m.parse_description();
        m.start_liveview();
        io_service.reset();
        io_service.run();
        m.get_live_image();
        io_service.reset();
        io_service.run();   
    } catch (const std::exception& e)   {
        std::cerr << "Exception: " << e.what() << "\n";
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

通过ssdp发现相机

首先,我们必须使用其upnp(通用即插即用)功能连接到相机.原理是每个upnp设备正在侦听组播端口230.255.255.250:1900以获取M-SEARCH请求.这意味着如果您将正确的消息发送到此地址,设备将通过告知您它存在来回答,并向您提供使用它的信息.文档中给出了正确的消息.我遇到了两个陷阱:首先,我省略了在消息末尾添加换行符,如http标准中所指定的那样.因此,您要发送的消息可以像这样构建:

multicast_manager(basio::io_service& io_service, const basio::ip::address& multicast_address)
    : endpoint_(multicast_address, 1900),
    socket_(io_service, endpoint_.protocol())
{
    stringstream os;
    os << "M-SEARCH * HTTP/1.1\r\n";
    os << "HOST: 239.255.255.250:1900\r\n";
    os << "MAN: \"ssdp:discover\"\r\n";
    os << "MX: 4\r\n";
    os << "ST: urn:schemas-sony-com:service:ScalarWebAPI:1\r\n";
    os << "\r\n";
    message_ = os.str();
    // ...
Run Code Online (Sandbox Code Playgroud)

这部分重要的第二件事是检查消息是否发送到正确的网络接口.在我的情况下,即使它被禁用,它通过我的以太网卡出去,直到我更改了套接字中的正确选项,我用以下代码解决了这个问题:

    // ...
    socket_.set_option(basio::ip::multicast::outbound_interface(
                            basio::ip::address_v4::from_string("10.0.1.1")));
    socket_.async_send_to(
                basio::buffer(message_), endpoint_,
                boost::bind(&multicast_manager::handle_send_to, this,
                            basio::placeholders::error));       
}
Run Code Online (Sandbox Code Playgroud)

现在我们听.如果你像我一样,我们会听你问你在哪里?什么端口,什么地址?好吧,我们不在乎:事情是,当我们发送消息时,我们定义了一个目的地ip和端口(在端点构造​​函数中).我们没有必要定义任何本地地址,它是我们自己的IP地址(事实上,我们确实定义了它,但只是为了知道可以选择哪个网络接口); 我们没有定义任何本地端口,它实际上是自动选择的(我猜的是OS?).无论如何,重要的是,任何收听多播组的人都会得到我们的消息并知道它的来源,并且会直接响应正确的ip和端口.所以不需要在这里指定任何内容,不需要创建新的套接字,我们只需要听一下我们在瓶子中发送消息的同一个套接字:

void handle_send_to(const boost::system::error_code& error)
{
    if (!error) {
        socket_.async_receive(asio::buffer(data_),
                boost::bind(&multicast_manager::handle_read_header, this,
                        basio::placeholders::error,
                        basio::placeholders::bytes_transferred));
    }
}
Run Code Online (Sandbox Code Playgroud)

如果一切顺利,答案就是:

HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1800
EXT: 
LOCATION: http://10.0.0.1:64321/DmsRmtDesc.xml
SERVER: UPnP/1.0 SonyImagingDevice/1.0
ST: urn:schemas-sony-com:service:ScalarWebAPI:1
USN: uuid:00000000-0005-0010-8000-10a5d09bbeda::urn:schemas-sony-com:service:ScalarWebAPI:1
X-AV-Physical-Unit-Info: pa=""; pl=;
X-AV-Server-Info: av=5.0; hn=""; cn="Sony Corporation"; mn="SonyImagingDevice"; mv="1.0";
Run Code Online (Sandbox Code Playgroud)

为了解析这个消息,我重新使用了boost http客户端示例中的解析,除了我一次性完成它,因为由于某种原因我无法使用UDP套接字执行async_read_until.无论如何,重要的是相机收到了我们的信息; 另一个重要的部分是描述文件DmsRmtDesc.xml的位置.

检索和读取描述文件

我们需要获取DmsRmtDesc.xml.这次我们将直接向摄像机发送GET请求,指定IP地址和端口.这个请求是这样的:

GET /DmsRmtDesc.xml HTTP/1.1
Host: 10.0.0.1
Accept: */*
Connection: close
Run Code Online (Sandbox Code Playgroud)

不要忘记额外的空行.我不知道连接是什么:关闭意味着什么.接受行指定您接受的答案的应用程序类型,在这里我们将采取任何答案.我使用boost http客户端示例获取文件,基本上我打开一个套接字到10.0.0.1:64321并接收HTPP标头,后面跟着文件的内容.现在我们有一个xml文件,其中包含我们要使用的Web服务的地址.让我们再次使用boost来解析它,我们想要检索相机服务地址,也许是实时视图流地址:

namespace bpt = boost::property_tree;
bpt::ptree pt;
bpt::read_xml(content, pt);
liveview_url = pt.get<string>("root.device.av:X_ScalarWebAPI_DeviceInfo.av:X_ScalarWebAPI_ImagingDevice.av:X_ScalarWebAPI_LiveView_URL");
for (bpt::ptree::value_type &v : pt.get_child("root.device.av:X_ScalarWebAPI_DeviceInfo.av:X_ScalarWebAPI_ServiceList")) {
    string service = v.second.get<string>("av:X_ScalarWebAPI_ServiceType");
    if (service == "camera")
        camera_service_url = v.second.get<string>("av:X_ScalarWebAPI_ActionList_URL");
}
Run Code Online (Sandbox Code Playgroud)

完成后,我们可以开始向摄像机发送实际命令,并使用API​​.

向摄像机发送命令

这个想法非常简单,我们使用文档中提供的json格式构建命令,然后将POST请求发送给摄像头服务.我们将启动实时视图模式,因此我们发出POST请求(我们最终将使用boost property_tree来构建我们的json字符串,这里我手动完成):

POST /sony/camera HTTP/1.1
Accept: application/json-rpc
Content-Length: 70
Content-Type: application/json-rpc
Host:http://10.0.0.1:10000/sony

{"method": "startLiveview","params" : [],"id" : 1,"version" : "1.0"}
Run Code Online (Sandbox Code Playgroud)

我们发送到10.0.0.1:10000并等待答案:

HTTP/1.1 200 OK 
Connection: close 
Content-Length: 119 
Content-Type: application/json

{"id":1,"result":["http://10.0.0.1:60152/liveview.JPG?%211234%21http%2dget%3a%2a%3aimage%2fjpeg%3a%2a%21%21%21%21%21"]}
Run Code Online (Sandbox Code Playgroud)

我们第二次获得了liveview网址,我不知道哪个更好,它们是相同的......

无论如何,现在我们知道如何向摄像机发送命令并检索其答案,我们仍然需要获取图像流.

从实时视图流中获取图像

我们有liveview网址,我们在API参考指南中有规范.首先,我们要求相机向我们发送流,所以我们发送一个GET请求到10.0.0.1:60152:

GET /liveview.JPG?%211234%21http%2dget%3a%2a%3aimage%2fjpeg%3a%2a%21%21%21%21%21 HTTP/1.1
Accept: image/jpeg
Host: 10.0.0.1
Run Code Online (Sandbox Code Playgroud)

我们等待答案,不应该花很长时间.答案从通常的HTTTP标头开始:

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Pragma: no-cache
CACHE-CONTROL: no-cache
Content-Type: image/jpeg
transferMode.dlna.org: Interactive
Connection: Keep-Alive
Date: Wed, 09 Jul 2014 14:13:13 GMT
Server: UPnP/1.0 SonyImagingDevice/1.0
Run Code Online (Sandbox Code Playgroud)

根据文档,这应该直接遵循实时视图数据流,其理论在于:

  • 8字节的公共头,指定我们是否确实处于实时视图模式.
  • 128字节的有效载荷数据给出了jpg数据的大小.
  • n个字节的jpeg数据.

然后我们再次获得公共标头,无限期地直到我们关闭套接字.

在我的例子中,公共标题以"88\r \n"开头,所以我不得不丢弃它,并且在切换到下一帧之前,jpg数据后跟10个额外的字节,所以我不得不考虑到这一点.我还必须自动检测jpg图像的开始,因为jpg数据以包含我忽略的符号的数字的文本开始.最有可能这些错误是由于我做错了,或者我对这里使用的技术不了解.

我的代码现在正常工作,但最后的位是非常临时的,它肯定需要更好的检查.

它还需要很多重构才能使用,但它显示了每个步骤的工作原理我猜...

如果您想尝试一下,这是整个文件. 这是一个在github上运行的VS项目.