如何序列化视频帧以通过 UDP 流式传输?
How do I serialize video frames for streaming over UDP?
我正在尝试通过 UDP 传输视频。我使用 vidgear 捕获屏幕并使用 pickle 进行序列化。我正在尝试构建一个远程桌面解决方案,因此需要低延迟,但我发现 pickle 的速度很慢。
有没有其他序列化框架可以序列化视频帧?
我能够找到 flatbuffers 和 protobuf 但我我不确定如何将这些用于视频。
因此,如果有人能指出正确的方向,即建议一个快速序列化框架,我将不胜感激。
提前致谢! :)
我看到你已经解决了,但同时我举了一些例子。
您可以使用tobytes()
将numpy.arraay
转换为可以通过套接字发送的bytes
。
byte_data = arr.tobytes()
您还可以使用 struct
将值的长度转换为 4 bytes
或将 height,width,depth
转换为 12 bytes
size = len(byte_data)
byte_size = struct.pack('I', size)
width, height, depth = arr.shape
byte_width_height = struct.pack('III', width, height, depth)
然后您可以发送尺寸或 width, height, depth
all_bytes = byte_size + byte_data
send(all_bytes)
all_bytes = byte_height_width + byte_data
send(all_bytes)
在客户端你可以先得到 4 bytes
和 size
byte_size = recv(4)
size = struct.unpack('I', byte_size)
或 12 byes
如果您使用 height,width,depth
发送
byte_height_width_depth = recv(12)
height, width, depth = struct.unpack('III', byte_height_width_depth)
然后你知道字节有多少帧
byte_data = recv(size)
arr = np.frombuffer(byte_data, dtype=np.uint8)
有了 height,width,depth
你可能还知道如何重塑它
byte_data = recv(height*width*depth)
arr = np.frombuffer(byte_data, dtype=np.uint8)
arr = arr.reshape((height, width, depth))
如果您始终使用具有相同 height, width, depth
的框架,那么您可以只发送没有 height, width, depth
甚至没有 `size 的数据,并在代码中使用硬编码值。
但是如果您打算将其压缩为 JPG 或 PNG 格式,它们可能具有不同的字节数,那么您需要将大小作为第一个值发送。
使用 pickle
你会得到更多的字节,因为它发送关于 class numpy.array
的信息来重建它。
使用tobytes
你必须自己重建数组。
示例代码 - 它模拟为 send
、recv
.
import numpy as np
import struct
import pickle
"""Simulater socket."""
internet = bytes()
pointer = 0
def send(data):
"""Simulater socket send."""
global internet
internet += data
def recv(size):
"""Simulater socket recv."""
global pointer
data = internet[pointer:pointer+size]
pointer += size
return data
def send_frame(arr):
#height, width, depth = arr.shape
#byte_height_width_depht = struct.pack('III', width, height, depth)
byte_height_width_depht = struct.pack('III', *arr.shape)
#send(byte_height_width_depht)
byte_data = arr.tobytes()
#send(byte_data)
all_bytes = byte_height_width_depht + byte_data
send(all_bytes)
print('all_bytes size:', len(all_bytes))
print('all_bytes data:', all_bytes)
def recv_frame():
byte_height_width_depht = recv(12)
height, width, depth = struct.unpack('III', byte_height_width_depht)
byte_data = recv(height*width*depth)
arr = np.frombuffer(byte_data, dtype=np.uint8).reshape((height, width, depth))
return arr
# --- main ---
arr = np.array([
[[255, 255, 255], [255, 255, 255]],
[[255, 0, 0], [ 0, 0, 255]],
[[255, 0, 0], [ 0, 0, 255]],
[[255, 255, 255], [255, 255, 255]],
], dtype=np.uint8)
print('--- pickle ---')
data = pickle.dumps(arr)
print('pickle size:', len(data))
print('pickle data:')
print(data)
print()
arr = pickle.loads(data)
print('array:')
print(arr)
print()
print('--- send frame ---')
send_frame(arr)
print()
print('--- recv frame ---')
arr = recv_frame()
print(arr)
print()
我正在尝试通过 UDP 传输视频。我使用 vidgear 捕获屏幕并使用 pickle 进行序列化。我正在尝试构建一个远程桌面解决方案,因此需要低延迟,但我发现 pickle 的速度很慢。 有没有其他序列化框架可以序列化视频帧? 我能够找到 flatbuffers 和 protobuf 但我我不确定如何将这些用于视频。
因此,如果有人能指出正确的方向,即建议一个快速序列化框架,我将不胜感激。
提前致谢! :)
我看到你已经解决了,但同时我举了一些例子。
您可以使用tobytes()
将numpy.arraay
转换为可以通过套接字发送的bytes
。
byte_data = arr.tobytes()
您还可以使用 struct
将值的长度转换为 4 bytes
或将 height,width,depth
转换为 12 bytes
size = len(byte_data)
byte_size = struct.pack('I', size)
width, height, depth = arr.shape
byte_width_height = struct.pack('III', width, height, depth)
然后您可以发送尺寸或 width, height, depth
all_bytes = byte_size + byte_data
send(all_bytes)
all_bytes = byte_height_width + byte_data
send(all_bytes)
在客户端你可以先得到 4 bytes
和 size
byte_size = recv(4)
size = struct.unpack('I', byte_size)
或 12 byes
如果您使用 height,width,depth
byte_height_width_depth = recv(12)
height, width, depth = struct.unpack('III', byte_height_width_depth)
然后你知道字节有多少帧
byte_data = recv(size)
arr = np.frombuffer(byte_data, dtype=np.uint8)
有了 height,width,depth
你可能还知道如何重塑它
byte_data = recv(height*width*depth)
arr = np.frombuffer(byte_data, dtype=np.uint8)
arr = arr.reshape((height, width, depth))
如果您始终使用具有相同 height, width, depth
的框架,那么您可以只发送没有 height, width, depth
甚至没有 `size 的数据,并在代码中使用硬编码值。
但是如果您打算将其压缩为 JPG 或 PNG 格式,它们可能具有不同的字节数,那么您需要将大小作为第一个值发送。
使用 pickle
你会得到更多的字节,因为它发送关于 class numpy.array
的信息来重建它。
使用tobytes
你必须自己重建数组。
示例代码 - 它模拟为 send
、recv
.
import numpy as np
import struct
import pickle
"""Simulater socket."""
internet = bytes()
pointer = 0
def send(data):
"""Simulater socket send."""
global internet
internet += data
def recv(size):
"""Simulater socket recv."""
global pointer
data = internet[pointer:pointer+size]
pointer += size
return data
def send_frame(arr):
#height, width, depth = arr.shape
#byte_height_width_depht = struct.pack('III', width, height, depth)
byte_height_width_depht = struct.pack('III', *arr.shape)
#send(byte_height_width_depht)
byte_data = arr.tobytes()
#send(byte_data)
all_bytes = byte_height_width_depht + byte_data
send(all_bytes)
print('all_bytes size:', len(all_bytes))
print('all_bytes data:', all_bytes)
def recv_frame():
byte_height_width_depht = recv(12)
height, width, depth = struct.unpack('III', byte_height_width_depht)
byte_data = recv(height*width*depth)
arr = np.frombuffer(byte_data, dtype=np.uint8).reshape((height, width, depth))
return arr
# --- main ---
arr = np.array([
[[255, 255, 255], [255, 255, 255]],
[[255, 0, 0], [ 0, 0, 255]],
[[255, 0, 0], [ 0, 0, 255]],
[[255, 255, 255], [255, 255, 255]],
], dtype=np.uint8)
print('--- pickle ---')
data = pickle.dumps(arr)
print('pickle size:', len(data))
print('pickle data:')
print(data)
print()
arr = pickle.loads(data)
print('array:')
print(arr)
print()
print('--- send frame ---')
send_frame(arr)
print()
print('--- recv frame ---')
arr = recv_frame()
print(arr)
print()