【问题标题】:How do I serialize video frames for streaming over UDP?如何序列化视频帧以通过 UDP 流式传输?
【发布时间】:2021-05-04 08:18:35
【问题描述】:

我正在尝试通过 UDP 传输视频。我使用 vidgear 捕获我的屏幕并使用 pickle 进行序列化。我正在尝试构建一个远程桌面解决方案,因此需要低延迟,但我发现泡菜的速度很慢。 还有其他可以序列化视频帧的序列化框架吗? 我能够找到 flatbuffersprotobuf,但我不确定如何将它们用于视频。 p>

因此,如果有人能指出我正确的方向,我将不胜感激,即建议一个快速序列化框架。

提前致谢! :)

【问题讨论】:

  • 真的要序列化吗?帧应该只有bytes,它可能只需要带有bytes数量的标头(一个或两个字节) - 所以当客户端读取它时,它首先应该获取它必须读取多少字节的信息,然后它应该读取这些字节。
  • 看来vidgear 将帧作为numpy.array 提供,它可以将它作为字节提供给你 - arr.tobytes() 并且你可以发送它 - 但在开始时你应该添加一些信息 - 即。帧的宽度和高度,字节数。您可以使用 struct 将整数转换为 4 个字节。这个example 我从 pygame 获取图像,转换为字节,在图像中添加字节数(始终为 4 个字节)并将其发送给客户端。客户端读取 4 个字节,转换为整数,并读取所有需要的字节。
  • @furas 我在某处读到泡菜很慢。那么这是否意味着 numpy 函数 arr.tobytes() 更快?
  • tobytes() 不会对其进行序列化——它只会将原始数据作为字节提供给您。它不会向此类数据类型添加任何额外信息,但这应该始终是相同的类型,因此您可以直接在客户端代码中设置它。您只需添加数据长度 - 即struct.pack('I', len(arr)) 此外,对于数组 3x3(这意味着 9 个值),dtype=np.uint8pickle 给了我 159 个字节,tobytes() 只给了 9 个字节。如果我将struct.pack('I', len(arr)) 添加到tobytes(),那么它将是 13 个字节。并且 numpy 可能会为此使用 C/C++ 代码,因此它可能会运行得更快 - 但我看不出小数据的差异。
  • 嘿@abhiTronix 我正在为此目的使用套接字库。但是我不知道WriteGear 肯定会调查它。谢谢!

标签: python serialization udp pickle


【解决方案1】:

我看到你已经解决了,但同时我做了一些例子。

您可以使用tobytes()numpy.arraay 转换为您可以通过套接字发送的bytes

    byte_data = arr.tobytes()

您还可以使用struct 将值的长度转换为4 bytesheight,width,depth12 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的大小

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 可以获得更多字节,因为它发送有关numpy.array 类的信息来重建它。

使用tobytes 你必须自己重建数组。


示例代码 - 模拟为sendrecv

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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-01
    • 2022-12-16
    • 2019-01-26
    • 1970-01-01
    • 2017-09-04
    • 2013-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多