Sony Camera Remote API,实时视频流很慢
Sony Camera Remote API, Liveview streaming slow
我正在尝试在桌面上流式传输 SONY FDR-X1000V 相机的实时视图。我使用 python 调用 API 并下载包并使用 opencv 解码 jpeg。
当我 运行 它时,它几乎不能每秒捕捉一帧。后来发现一个jpeg的payload size可以达到8MB。但是,FDR-X1000V 不支持更改实时取景尺寸。但是当我使用 iPhone 上的应用程序进行实时取景时,它可以流畅地播放。所以这是我的问题:
1. 一个jpeg payload能达到8MB正常吗?
2. 如果可以,如何流畅的直播?
这是我的代码:
try:
result = api.do('startLiveview')
url = result['result'][0]
except KeyError:
print result
f = urllib2.urlopen(url)
buff = ''
chunk_size = 32768
for i in xrange(3000):
if len(buff) < chunk_size:
time_s = time.time()
buff = buff + f.read(chunk_size)
print "Download Speed %f KB/s"%(chunk_size/1000/(time.time() - time_s))
time_s = time.time()
start_code = ''.join(buff).find('hy')
# print "LCS time cost", time.time() - time_s
if start_code < 0:
buff = buff[-12:]
print "skip", len(buff)-12
elif start_code < 8:
buff = buff[8:]
else:
if start_code > len(buff) - 129:
buff = buff + f.read(chunk_size)
payload_type = ord(buff[start_code-7])
payload_size, = struct.unpack('<I', buff[start_code+4:start_code+8].ljust(4,'[=11=]'))
padding_size = ord(buff[start_code+8])
print "Type:%d\tPayload:%d\tPadding:%d\t"%(payload_type,payload_size,padding_size)
buff = buff[start_code+128:]
if payload_type == 1:
if payload_size + padding_size > len(buff):
time_s = time.time()
download_size = payload_size+padding_size-len(buff)
buff = buff + f.read(download_size)
print "Download Speed %f KB/s"%(download_size/1000/(time.time() - time_s))
img_data = buff[:payload_size]
buff = buff[payload_size:]
time_s = time.time()
d = np.asarray(bytearray(img_data), dtype='uint8')
img = cv2.imdecode(d,cv2.IMREAD_COLOR)
cv2.imshow('postview',img)
cv2.waitKey(30)
# print "Decode time cost", time.time() - time_s
一些输出:
Type:1 Payload:8410624 Padding:0
Download Speed 679.626326 KB/s
有点无耻的推销 - 但它可能会帮助你。您尝试使用 pysony 代码了吗?
您必须手动设置 QX_ADDR 但这应该会给您一个 'faster' 实时视频流...
https://github.com/Bloodevil/sony_camera_api/issues/22
pygameLiveView 示例具有所需的构建块,您只需调整 jpeg 加载即可拉入 openCV 而不是 pygame
我认为问题可能是您将“LiveView’s Payload Header”中的“Payload data size without padding size”解析为 4 字节数据而不是 3 字节数据。所以在这种情况下,有效载荷大小看起来比预期的要大。这在“实时取景数据 JPEG 容器的格式”下的文档中进行了解释。尝试更改此设置,如果它仍然不适合您,请告诉我。
@Simon Wood 和@Robert - Sony 的回答都很有用!
我在代码中犯了两个错误。
一个是负载大小是 3 字节而不是 4 字节。
另一个是我假设字节顺序是小端而不是大端。
@Simon Wood提到的这个项目不错。虽然它没有对4字节的起始码实现再同步。
为了做到这一点,我用两种方法编写了自己的代码来检查和重新同步它:
try:
result = api.do('startLiveview')
url = result['result'][0]
except KeyError:
print result
f = urllib2.urlopen(url)
#method 1
buff = ''
chunk_size = 8192
for i in xrange(300):
if len(buff) < chunk_size:
time_s = time.time()
buff = buff + f.read(chunk_size)
# print "Download Speed %f KB/s"%(chunk_size/1000/(time.time() - time_s))
time_s = time.time()
start_code = ''.join(buff).find('hy')
# print "LCS time cost", time.time() - time_s
if start_code < 0:
buff = buff[-12:]
print "skip", len(buff)-12
elif start_code < 8:
buff = buff[8:]
print "skip a header"
else:
if start_code > len(buff) - 129:
buff = buff + f.read(chunk_size)
start_byte = ord(buff[start_code - 8])
payload_type = ord(buff[start_code - 7])
sequence_num, = struct.unpack('>I', buff[start_code - 6:start_code - 4].rjust(4,'[=10=]'))
time_stamp, = struct.unpack('>I', buff[start_code - 4:start_code].rjust(4,'[=10=]'))
payload_size, = struct.unpack('>I', buff[start_code+4:start_code+7].rjust(4,'[=10=]'))
padding_size = ord(buff[start_code+8])
print "StartByte:%d\t sequenceNum:%d\t timeStamp:%d\t Type:%d\t Payload:%d\t Padding:%d\t"%(
start_byte,sequence_num,time_stamp,payload_type,payload_size,padding_size)
buff = buff[start_code+128:]
if payload_type == 1:
if payload_size + padding_size > len(buff):
time_s = time.time()
download_size = payload_size+padding_size-len(buff)
buff = buff + f.read(download_size)
# print "Download Speed %f KB/s"%(download_size/1000/(time.time() - time_s))
img_data = buff[:payload_size]
buff = buff[payload_size:]
time_s = time.time()
d = np.asarray(bytearray(img_data), dtype='uint8')
img = cv2.imdecode(d,cv2.IMREAD_COLOR)
cv2.imshow('postview',img)
cv2.waitKey(10)
# print "Decode time cost", time.time() - time_s
#method 2
def checkbyte(f):
if f.read(4) == 'hy':
return
state = 0
i = 1
while 1:
i+=1
if state == 0 :
if f.read(1) == '$':
state = 1
else:
state = 0
if state == 1 :
if f.read(1) == '5':
state = 2
else:
state = 0
if state == 2 :
if f.read(1) == 'h':
state = 3
else:
state = 0
if state == 3 :
if f.read(1) == 'y':
state = 4
else:
state = 0
if state == 4 :
print 'skip', i
return
for i in xrange(300):
buff = f.read(8)
start_byte ord(buff[0])
payload_type, = struct.unpack('>I',buff[1].rjust(4,'[=10=]'))
sequence_num, = struct.unpack('>I',buff[2:4].rjust(4,'[=10=]'))
time_stamp, = struct.unpack('>I',buff[4:8])
#payload header
checkbyte(f)
buff = f.read(124)
payload_size, = struct.unpack('>I',buff[0:3].rjust(4,'[=10=]'))
padding_size= ord(buff[3])
print "StartByte:%d\t sequenceNum:%d\t timeStamp:%d\t Type:%d\t Payload:%d\t Padding:%d\t"%(
start_byte,sequence_num,time_stamp,payload_type,payload_size,padding_size)
d = f.read(payload_size)
if padding_size > 0:
f.read(padding_size)
if payload_type == 1:
# Type = 0x01
d = np.asarray(bytearray(d), dtype='uint8')
img = cv2.imdecode(d,cv2.IMREAD_COLOR)
cv2.imshow('postview',img)
cv2.waitKey(1)
print api.do('stopLiveview')
我正在尝试在桌面上流式传输 SONY FDR-X1000V 相机的实时视图。我使用 python 调用 API 并下载包并使用 opencv 解码 jpeg。 当我 运行 它时,它几乎不能每秒捕捉一帧。后来发现一个jpeg的payload size可以达到8MB。但是,FDR-X1000V 不支持更改实时取景尺寸。但是当我使用 iPhone 上的应用程序进行实时取景时,它可以流畅地播放。所以这是我的问题: 1. 一个jpeg payload能达到8MB正常吗? 2. 如果可以,如何流畅的直播?
这是我的代码:
try:
result = api.do('startLiveview')
url = result['result'][0]
except KeyError:
print result
f = urllib2.urlopen(url)
buff = ''
chunk_size = 32768
for i in xrange(3000):
if len(buff) < chunk_size:
time_s = time.time()
buff = buff + f.read(chunk_size)
print "Download Speed %f KB/s"%(chunk_size/1000/(time.time() - time_s))
time_s = time.time()
start_code = ''.join(buff).find('hy')
# print "LCS time cost", time.time() - time_s
if start_code < 0:
buff = buff[-12:]
print "skip", len(buff)-12
elif start_code < 8:
buff = buff[8:]
else:
if start_code > len(buff) - 129:
buff = buff + f.read(chunk_size)
payload_type = ord(buff[start_code-7])
payload_size, = struct.unpack('<I', buff[start_code+4:start_code+8].ljust(4,'[=11=]'))
padding_size = ord(buff[start_code+8])
print "Type:%d\tPayload:%d\tPadding:%d\t"%(payload_type,payload_size,padding_size)
buff = buff[start_code+128:]
if payload_type == 1:
if payload_size + padding_size > len(buff):
time_s = time.time()
download_size = payload_size+padding_size-len(buff)
buff = buff + f.read(download_size)
print "Download Speed %f KB/s"%(download_size/1000/(time.time() - time_s))
img_data = buff[:payload_size]
buff = buff[payload_size:]
time_s = time.time()
d = np.asarray(bytearray(img_data), dtype='uint8')
img = cv2.imdecode(d,cv2.IMREAD_COLOR)
cv2.imshow('postview',img)
cv2.waitKey(30)
# print "Decode time cost", time.time() - time_s
一些输出:
Type:1 Payload:8410624 Padding:0
Download Speed 679.626326 KB/s
有点无耻的推销 - 但它可能会帮助你。您尝试使用 pysony 代码了吗?
您必须手动设置 QX_ADDR 但这应该会给您一个 'faster' 实时视频流... https://github.com/Bloodevil/sony_camera_api/issues/22
pygameLiveView 示例具有所需的构建块,您只需调整 jpeg 加载即可拉入 openCV 而不是 pygame
我认为问题可能是您将“LiveView’s Payload Header”中的“Payload data size without padding size”解析为 4 字节数据而不是 3 字节数据。所以在这种情况下,有效载荷大小看起来比预期的要大。这在“实时取景数据 JPEG 容器的格式”下的文档中进行了解释。尝试更改此设置,如果它仍然不适合您,请告诉我。
@Simon Wood 和@Robert - Sony 的回答都很有用! 我在代码中犯了两个错误。
一个是负载大小是 3 字节而不是 4 字节。
另一个是我假设字节顺序是小端而不是大端。
@Simon Wood提到的这个项目不错。虽然它没有对4字节的起始码实现再同步。
为了做到这一点,我用两种方法编写了自己的代码来检查和重新同步它:
try:
result = api.do('startLiveview')
url = result['result'][0]
except KeyError:
print result
f = urllib2.urlopen(url)
#method 1
buff = ''
chunk_size = 8192
for i in xrange(300):
if len(buff) < chunk_size:
time_s = time.time()
buff = buff + f.read(chunk_size)
# print "Download Speed %f KB/s"%(chunk_size/1000/(time.time() - time_s))
time_s = time.time()
start_code = ''.join(buff).find('hy')
# print "LCS time cost", time.time() - time_s
if start_code < 0:
buff = buff[-12:]
print "skip", len(buff)-12
elif start_code < 8:
buff = buff[8:]
print "skip a header"
else:
if start_code > len(buff) - 129:
buff = buff + f.read(chunk_size)
start_byte = ord(buff[start_code - 8])
payload_type = ord(buff[start_code - 7])
sequence_num, = struct.unpack('>I', buff[start_code - 6:start_code - 4].rjust(4,'[=10=]'))
time_stamp, = struct.unpack('>I', buff[start_code - 4:start_code].rjust(4,'[=10=]'))
payload_size, = struct.unpack('>I', buff[start_code+4:start_code+7].rjust(4,'[=10=]'))
padding_size = ord(buff[start_code+8])
print "StartByte:%d\t sequenceNum:%d\t timeStamp:%d\t Type:%d\t Payload:%d\t Padding:%d\t"%(
start_byte,sequence_num,time_stamp,payload_type,payload_size,padding_size)
buff = buff[start_code+128:]
if payload_type == 1:
if payload_size + padding_size > len(buff):
time_s = time.time()
download_size = payload_size+padding_size-len(buff)
buff = buff + f.read(download_size)
# print "Download Speed %f KB/s"%(download_size/1000/(time.time() - time_s))
img_data = buff[:payload_size]
buff = buff[payload_size:]
time_s = time.time()
d = np.asarray(bytearray(img_data), dtype='uint8')
img = cv2.imdecode(d,cv2.IMREAD_COLOR)
cv2.imshow('postview',img)
cv2.waitKey(10)
# print "Decode time cost", time.time() - time_s
#method 2
def checkbyte(f):
if f.read(4) == 'hy':
return
state = 0
i = 1
while 1:
i+=1
if state == 0 :
if f.read(1) == '$':
state = 1
else:
state = 0
if state == 1 :
if f.read(1) == '5':
state = 2
else:
state = 0
if state == 2 :
if f.read(1) == 'h':
state = 3
else:
state = 0
if state == 3 :
if f.read(1) == 'y':
state = 4
else:
state = 0
if state == 4 :
print 'skip', i
return
for i in xrange(300):
buff = f.read(8)
start_byte ord(buff[0])
payload_type, = struct.unpack('>I',buff[1].rjust(4,'[=10=]'))
sequence_num, = struct.unpack('>I',buff[2:4].rjust(4,'[=10=]'))
time_stamp, = struct.unpack('>I',buff[4:8])
#payload header
checkbyte(f)
buff = f.read(124)
payload_size, = struct.unpack('>I',buff[0:3].rjust(4,'[=10=]'))
padding_size= ord(buff[3])
print "StartByte:%d\t sequenceNum:%d\t timeStamp:%d\t Type:%d\t Payload:%d\t Padding:%d\t"%(
start_byte,sequence_num,time_stamp,payload_type,payload_size,padding_size)
d = f.read(payload_size)
if padding_size > 0:
f.read(padding_size)
if payload_type == 1:
# Type = 0x01
d = np.asarray(bytearray(d), dtype='uint8')
img = cv2.imdecode(d,cv2.IMREAD_COLOR)
cv2.imshow('postview',img)
cv2.waitKey(1)
print api.do('stopLiveview')