前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Sony-QX10 Python 连接读取视频流

Sony-QX10 Python 连接读取视频流

作者头像
云深无际
发布2021-11-12 18:36:43
9330
发布2021-11-12 18:36:43
举报
文章被收录于专栏:云深之无迹

Sony 相机API官网资料合集

Sony QX10 相机预告

就是这么个东西,牛逼的狠

装手机上

装好啦

WiFi连接实时传输

有个老哥用QX10拍的珠穆朗玛峰,还是挺能打的

在API的页面,QX10和QX100放在一起,我不知道两个的代码可以混合使用吗?我测试一下。

我们就有API的列表

这里面是安卓的接口,当然还有苹果的

代码语言:javascript
复制
pip install opencv-python
代码语言:javascript
复制
pip install requests

使用这4个协议,SSDP用来让主机发现相机,HTTP来进行长时间的连接,接着json发送控制序列,我好喜欢序列这个词啊。

WiFi密码在里面

代码语言:javascript
复制
zP2EbQVr

真尼玛鬼畜,这密码。。。。

代码语言:javascript
复制
https://sourceforge.net/projects/sony-desktop-dsc-qx10/

QT4写的界面

人家的白色相机好好看

这个是最新的SDK的连接示意图

这个是以前的连接图,其实都一样

  1. json解码和发送指令
  2. requests来进行HTTP协议的打包
  3. Numpy是高效的数组,搭配opencv的库使用
  4. cv2是opencv的名字
  5. 还有多线程的库
  6. cmd是调用控制台协议

完整的函数和类集合

把显示的工作单独拿出来

在api的里面可以看到我吗感兴趣的API

第一个方法,预览画面:

结尾方法

json的例子

执行之后的回复信息

错误代码

我们先写一个关于获取视频流的方法,就好像是一个水管的接口一样

当你拿到这个数据流的时候,我们应该进行解码操作

接下来就进行解码

✓ 通过 HTTP GET 将实时视图数据作为一个数据流下载。

 最小单位称为“数据包”,如下图所示。在下载过程中,这个“数据包”将被重复。

 客户端应不断下载“Packet”的数据,并从一个“数据包”,并对其进行解码,并将其显示在显示器上。

 由于解码时间的原因,客户端可能无法显示所有的JPEG。在这种情况下,

客户端应该跳过一些 JPEG 图像。

✓ 数据的字节序是网络字节序。

不管你看懂与否,你都能找到机器传出来的都是单帧的

你头对上是万里长征第一步,你得看看它的数据部分能不能解码出来东西。

Common Header 由以下 8 个字节构成。

✓ 起始字节 : 1 [B]

 0xFF,固定

 Payload type : 1 [B]  表示Payload的类型

 0x01 = 对于实时取景图像

 0x02 = 用于实时取景帧信息

✓ 序列号:2 [B]

 帧号,2 字节整数,每帧递增

 此帧编号将重复。

 时间戳:4 [B]

 4字节整数,单位以Payload类型表示

 若Payload type = 0x01,则Common Header的时间戳单位为毫秒。开始时间可能不会从零开始,取决于服务器。

有效载荷头

有效载荷头格式将如下 128 字节。 起始码:4[B]

 固定 (0x24, 0x35, 0x68, 0x79)

 这可用于检测有效载荷报头。 无填充大小的有效载荷数据大小:3[B]

 字节。

 如果Payload Type = 0x01,大小表示Payload数据中JPEG的大小。

 如果Payload Type = 0x02,大小表示Payload data中Frame信息数据的大小。

 填充尺寸:1[B]

 JPEG 数据后Payload 数据的填充大小,字节。

如果 Payload Type = 0x01,则报头格式如下。 保留 : 4[B]

✓ 标志 : 1[B]

 该值设置为 0x00

 其他值保留

 保留 : 115[B]

 全部固定,0x00

如果 Payload Type = 0x02,则报头格式如下。 帧信息数据版本:2[B]

 帧信息数据的数据版本。

 高 1 字节表示主要版本,低 1 字节表示次要版本

版本。

 0x01, 0x00: 版本 1.0

 客户端应该使用数据版本忽略它不理解的数据。

 帧数:2[B]

 帧数据的编号。

 单帧数据大小:2[B]

 单一尺寸的帧数据。如果数据版本为 1.0,则数据大小为 16[B]。

 客户端可以使用数据大小读取每一帧。

 保留 : 114[B]

 全部固定,0x00

大概就是这样的,先看看头是不是合适的头,然后把下面的读了



把这个开始视频流的命令给get_payload()这个函数

在此

这个函数是仿照json的样子打包的

是不是一模一样嗷

代码语言:javascript
复制
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Type

然后前端的知识来了

代码语言:javascript
复制
 headers = {'Content-Type': 'application/json'}

所以是json

看语法,写的没有错

这次就更加的正确了

我们这样的发送一个数据出去

代码语言:javascript
复制
https://docs.python-requests.org/zh_CN/latest/user/quickstart.html

文档在此

拍一张照片的指令

get方法是得到一些数据

  1. 开始视频流这个方法返回的东西是一个strurl
  2. 然后给了打开视频流
  3. 然后下面就是解码的工作了

从相机得到数据,给了解码的方法

这个解码的方法解出来视频的数据给了下面得方法

显示,Numpy的库进行数据的变换,接着传给了我们的cv2,cv2使用imshow的方法显示出来

这个可能会看的清晰那么一些

上面把相机的连接,数据的解码什么的,封装了一个类。接着在写一个东西用来管理数据流的状态,比如拍张照片,停止这个事情什么的。

下面可以新建一个对象,这个对象其实

已经对上面的类进行了调用

代码语言:javascript
复制
"""QX10 interfacing code for python"""

import json
import requests
import numpy as np
import cv2
import threading
from cmd import Cmd


class LiveviewThread(threading.Thread):
    running = True

    def __init(self, url):
        threading.Thread.__init__(self)
        self.url = url
        self.running = True

    def run(self):
        s = start_liveview()
        data = open_stream(s)
        while self.running:
            jpg = decode_frame(data)
            show_img(jpg)
        data.raw.close()
        cv2.destroyWindow('liveview')

    def stop_running(self):
        self.running = False


class yunswjPrompt(Cmd):
    LVthread = LiveviewThread()

    def do_t(self, args):
        take_picture()

    def do_loop(self, args):
        for i in range(int(args)):
            take_picture()
            print(i)

    def do_start_liveview(self, args):
        self.LVthread.start()

    def do_start_liveview(self, args):
        self.LVthread.stop_running()

    def do_quit(self, args):
        self.do_stop_liveview([])
        raise SystemExit


def get_payload(method, params):
    return {
        "method": method,
        "params": params,
        "id": 1,
        "version": "1.0"
    }


def take_picture():
    payload = get_payload("actTakePicture", [])
    headers = {'Content-Type': 'application/json'}
    response = requests.post(
        'http://10.0.0.1:10000/sony/camera', data=json.dumps(payload), headers=headers)
    url = response.json()['result']
    strurl = str(url[0][0])
    return strurl


def get_event():
    payload = get_payload("getEvent", [False])
    headers = {'Content-Type': 'application/json'}
    response = requests.post(
        'http://10.0.0.1:10000/sony/camera', data=json.dumps(payload), headers=headers)

    return response


def get_picture(url, filename):
    response = requests.get(url)
    chunk_size = 1024
    with open(filename, 'wb') as fd:
        for chunk in response.iter_content(chunk_size):
            fd.write(chunk)

# LIVEVIEW STUFF


def start_liveview():
    payload = get_payload("startLiveview", [])
    headers = {'Content-Type': 'application/json'}
    response = requests.post(
        'http://10.0.0.1:10000/sony/camera', data=json.dumps(payload), headers=headers)
    url = response.json()['result']
    strurl = str(url[0])
    return strurl


def open_stream(url):
    return requests.get(url, stream=True)


def decode_frame(data):
    # 解码包头
    start = ord(data.raw.read(1))
    if(start != 0xFF):
        print('bad start byte\nexpected 0xFF got %x' % start)
        return
    pkt_type = ord(data.raw.read(1))
    if(pkt_type != 0x01):
        print('not a liveview packet')
        return
    frameno = int(data.raw.read(2).encode('hex'), 16)
    timestamp = int(data.raw.read(4).encode('hex'), 16)

    # 解码 liveview 头
    start = int(data.raw.read(4).encode('hex'), 16)
    if(start != 0x24356879):
        print('expected 0x24356879 got %x' % start)
        return
    jpg_size = int(data.raw.read(3).encode('hex'), 16)
    pad_size = ord(data.raw.read(1))
    # 读出保留的头,就是后面还有信息
    data.raw.read(4)
    fixed_byte = ord(data.raw.read(1))
    if(fixed_byte is not 0x00):
        print('expected 0x00 got %x' % fixed_byte)
        return
    data.raw.read(115)

    # 读出jpg
    jpg_data = data.raw.read(jpg_size)
    data.raw.read(pad_size)

    return jpg_data


def show_img(str_jpg):
    nparr = np.fromstring(str_jpg, np.uint8)
    img_np = cv2.imdecode(nparr, cv2.CV_LOAD_IMAGE_COLOR)

    cv2.namedWindow('liveview', flags=cv2.CV_WINDOW_AUTOSIZE)
    cv2.imshow('liveview', img_np)
    cv2.waitKey(1)


prompt = yunswjPrompt()
prompt.prompt = '> '
prompt.cmdloop('starting qx10 control')

代码附上

这个VSCode和Pycharm比较老是觉得缺点东西

这个地方,网关有点毛病,我没有想明白。。。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档