【问题标题】:Sending video frames to client向客户端发送视频帧
【发布时间】:2017-04-11 12:23:27
【问题描述】:

我目前正在使用 OpenCV 读取视频帧。

在服务器端,我使用 cPickle.dumps() 序列化帧:

flag, frame = cap.read()
frame = cPickle.dumps(frame)
client_socket.sendall(frame)

在客户端,我使用 cPickle.loads() 序列化帧:

data = sock.recv(4000)
frame = cPickle.loads(data) # ValueError: insecure string pickle
self.ImageLabel.configure(image=frame) # Want to show the frame in Tkinter
self.ImageLabel.image = frame
self.ImageLabel.grid(row=4, columnspan=40)

cPickle.loads(data) 导致 ValueError: insecure string pickle。我究竟做错了什么?我想在客户端读取框架并将其显示在 tkinter 窗口中。我到处查找了 9 个多小时,但找不到解决方案。

编辑 1:

我也试过这个:

服务器端

flag, frame = cap.read()
if flag:
    size = sys.getsizeof(frame)
    client_socket.send(str(size))
    client_socket.sendall(cPickle.dumps(frame.tolist()))

客户端

size = sock.recv(4000)
data = sock.recv(int(size))
frame = cPickle.loads(data) # Causes EOFError 

编辑 2: 服务器端

flag, frame = cap.read()
if flag:
   frame = cPickle.dumps(frame)
   size = len(frame)
   p = struct.pack("I", size)
   client_socket.send(p)
   client_socket.sendall(frame)

客户端

sizep = sock.recv(struct.calcsize("I"))
data_size = struct.unpack("I",sizep)
print type (data_size) # tuple - has (11026730, )
data = sock.recv(int(data_size[0]))
frame = cPickle.loads(data) # ValueError: insecure string pickle

【问题讨论】:

  • @Jean-FrançoisFabre cap.read() 是 OpenCV 的一个函数。它给出了一个 对象
  • @Jean-FrançoisFabre cPickle.dumps(frame.tolist()) 在尝试 cPickle.load(data) 时会导致 EOFError。我不确定 self.ImageLabel.configure(image=frame) 是否接受 ndarray。
  • 发送前可以打印frame吗?似乎有些东西在这里损坏了......
  • @Jean-FrançoisFabre 打印帧结果:pasted.co/a6dce83c where frame = cPickle.dumps(frame.tolist())
  • 你没有添加`...,`你自己吗?

标签: python sockets opencv tkinter


【解决方案1】:

您最多接收 4000 字节的数据,其中包含以下内容

data = sock.recv(4000)

但信息远不止于此。您必须完整阅读该消息,否则它会被截断,这就解释了 pickle 错误。例如这样做:

packets = []
while True:
    b = sock.recv(4096)
    if b:
        packets.append(b)
    else:
        break

data = "".join(packets)

这将读取套接字,直到没有任何内容可读取。我将每个数据包放在一个列表中,以便之后可以使用str.join(比字符串连接更快)。

现在data可以加载到pickle中了。

注意:它肯定不能解决self.ImageLabel.configure(image=frame)。确保将预期的数组类型传递给此方法。

编辑:现在你已经编辑了你的问题,你还有更多的问题。

  • 首先你要计算对象的大小之前使用pickle序列化,这是不正确的,你应该使用len(picked object)
  • 那么您正在使用recv(4000) 读取大小:您这样做只是消耗了一部分缓冲区,并且您不知道整数作为字符串的大小,因此无法解决大小问题。如果需要先发送大小,则需要使用struct.pack 对其进行编码,并在客户端使用struct.unpack 对其进行解码。
  • 当你有正确的大小时,你可以读取你的数据。

这是我的建议(您需要导入 struct):

服务器端:

flag, frame = cap.read()
if flag:
    data = cPickle.dumps(frame)  # serialize
    data_size = len(data)        # nb of bytes of serialized data
    p = struct.pack("I",data_size) # encode size
    client_socket.send(p)  # send encoded size
    client_socket.sendall(data)  # send serialized data

客户端:

sizep = sock.recv(struct.calcsize("I")) # first thing: recieved encoded size
data_size = struct.unpack("I",sizep)  # decode size
data = sock.recv(data_size)          # read data size
frame = cPickle.loads(data)          # unserialize

【讨论】:

  • 请看我的编辑。服务器将发送许多帧。所以我在发送实际帧之前先发送了帧的大小,但它仍然会导致错误。如果消息的大小是个问题,这不就解决了吗?
  • 我使用 struct 尝试了您的解决方案。它仍然给出 ValueError: insecure string pickle。请参阅编辑 2。
  • 可以打印发射前后的尺寸吗?
猜你喜欢
  • 2021-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多