将视频帧发送到客户端

时间:2016-11-27 19:42:45

标签: python sockets opencv tkinter

我目前正在使用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:不安全的字符串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

1 个答案:

答案 0 :(得分: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