如何序列化视频帧以通过 UDP 流式传输?

How do I serialize video frames for streaming over UDP?

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

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

提前致谢! :)

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

您可以使用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你必须自己重建数组。


示例代码 - 它模拟为 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()