2016-11-27 101 views
1

我目前使用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 
+0

@讓FrançoisFabrecap.read( )是OpenCV的一項功能。它給一個對象 –

+0

@ Jean-FrançoisFabrecPickle.dumps(frame.tolist())在嘗試cPickle.load(data)時會導致EOFError。 我不確定self.ImageLabel.configure(image = frame)是否接受一個ndarray。 –

+0

你可以在發送之前打印'frame'嗎?似乎這裏有東西是腐敗的...... –

回答

1

您收到最多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 
+0

請參閱我的編輯。服務器將發送很多幀。所以我在發送實際幀之前首先發送了幀的大小,但仍然會導致錯誤。如果消息的大小是一個問題,這難道不能解決這個問題嗎? –

+0

我試過使用struct的解決方案。它仍然給ValueError:不安全的字符串pickle。請參閱編輯2. –

+0

您可以在排放之前和之後打印尺寸嗎? –

相關問題