发送视频帧到客户端
我目前使用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的。加载(数据)导致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
您收到最多4000个字节的数据具有以下
data = sock.recv(4000)
但该消息比大。您必须完整阅读该消息或将其截断,这就解释了泡菜错误。例如这样做:
packets = []
while True:
b = sock.recv(4096)
if b:
packets.append(b)
else:
break
data = "".join(packets)
将读取插槽,直至没有什么再阅读。我把每个数据包放在一个列表中,所以我可以使用str.join
(比字符串连接更快)。
现在data
可以装入泡菜。
注意:它当然不能解决self.ImageLabel.configure(image=frame)
。确保将期望的数组类型传递给此方法。
编辑:现在你已经编辑了你的问题,你有更多的问题。
- 首先你之前序列化,咸菜,这是不正确的计算对象的大小,你应该使用
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:不安全的字符串pickle。请参阅编辑2. –
您可以在排放之前和之后打印尺寸吗? –
@让FrançoisFabrecap.read( )是OpenCV的一项功能。它给一个对象 –
@ Jean-FrançoisFabrecPickle.dumps(frame.tolist())在尝试cPickle.load(data)时会导致EOFError。 我不确定self.ImageLabel.configure(image = frame)是否接受一个ndarray。 –
你可以在发送之前打印'frame'吗?似乎这里有东西是腐败的...... –