Send Video over TCP using OpenCV and sockets in Raspberry Pi

11,180

Solution 1

Create a file with code below, run server code in Powershell on Windows by running for example python "C:\path\toFile\streamTestServer.py"

Code is:

import socket
import sys
import cv2
import pickle
import numpy as np
import struct

HOST = '127.0.0.1'
PORT = 8083

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')

s.bind((HOST, PORT))
print('Socket bind complete')
s.listen(10)
print('Socket now listening')

conn, addr = s.accept()

data = b''
payload_size = struct.calcsize("L")

while True:
    while len(data) < payload_size:
        data += conn.recv(4096)
    packed_msg_size = data[:payload_size]

    data = data[payload_size:]
    msg_size = struct.unpack("L", packed_msg_size)[0]

    while len(data) < msg_size:
        data += conn.recv(4096)
    frame_data = data[:msg_size]
    data = data[msg_size:]

    frame=pickle.loads(frame_data)
    print(frame.size)
    cv2.imshow('frame', frame)
    cv2.waitKey(10)

Then run client in Python IDLE or in another window of Powershell. Client code is:

import cv2
import numpy as np
import socket
import sys
import pickle
import struct

cap = cv2.VideoCapture(0)
clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket.connect(('127.0.0.1', 8083))

while True:
    ret,frame = cap.read()
    data = pickle.dumps(frame)
    clientsocket.sendall(struct.pack("L", len(data)) + data)

Now you are streaming from localhost client to localhost server.

Solution 2

According to my understanding, you should use the same ports for client and server, but you are using two different ones, 8083 and 8081.

Have you checked that the firewall is opened for the port used?

Solution 3

After hours of analysis why the server.py and client.py weren't working(even after the firewall was disabled), there was an error in the server.py code: "word should not be a string". Therefore, word = "" (which is a string) should be changed to word = b'' (these are two single quotes to represent a byte).

Solution 4

Using this same program, I have had problems receiving data on my raspberry pi. I found out that this was because of the difference between how "L" for unsigned long is used on the different machines. At least for me, their native representations on the different machines were different. I fixed this by adding a "=" in the format string to force struct to unpack using the standard size of "L" (4).

payload_size = struct.calcsize("=L")

and

clientsocket.sendall(struct.pack("=L", len(data)) + data)

and so on

Share:
11,180
Shinchan
Author by

Shinchan

Updated on June 16, 2022

Comments

  • Shinchan
    Shinchan almost 2 years

    I have been trying to send live video frame from my client (Raspberry Pi) to a server hosted on Laptop. Both these devices are connected to the same network.

    Server.py

    import socket
    import sys
    import cv2
    import pickle
    import numpy as np
    import struct
    
    HOST = '192.168.1.3'
    PORT = 8083
    
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print 'Socket created'
    
    s.bind((HOST, PORT))
    print 'Socket bind complete'
    s.listen(10)
    print 'Socket now listening'
    
    conn, addr = s.accept()
    
    data = ""
    payload_size = struct.calcsize("L")
    
    while True:
        while len(data) < payload_size:
            data += conn.recv(4096)
        packed_msg_size = data[:payload_size]
    
        data = data[payload_size:]
        msg_size = struct.unpack("L", packed_msg_size)[0]
    
        while len(data) < msg_size:
            data += conn.recv(4096)
        frame_data = data[:msg_size]
        data = data[msg_size:]
    
        frame=pickle.loads(frame_data)
        print frame.size
        # cv2.imshow('frame', frame)
        # cv2.waitKey(10)
    

    Client.py

    import cv2
    import numpy as np
    import socket
    import sys
    import pickle
    import struct
    
    cap = cv2.VideoCapture(0)
    clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    clientsocket.connect(('192.168.1.3', 8081))
    
    while True:
        ret,frame = cap.read()
        data = pickle.dumps(frame)
        clientsocket.sendall(struct.pack("L", len(data)) + data)
    

    My server on laptop is not receiving any data. But when I run this client and server on same devices (e.g. server and client on laptop) then it is working properly.

    I am able to send data from raspberry to laptop (tested for echo application).

    Can anyone help me with this ?

  • Shinchan
    Shinchan about 8 years
    Even when I put my port numbers same, still it is the same problem. And all firewall rules allow connections on that port.
  • tfv
    tfv about 8 years
    Have you checked that the actual IP of your host machine (as obtained by ipconfig) is the same as the one you use in your program? Does a ping work in both directions?
  • Shinchan
    Shinchan about 8 years
    problem i am getting is "payload_size" in server is getting a very big value (7898745431321384897974964) and because of this the program is in an infinite loop.
  • TaeWoo
    TaeWoo over 6 years
    can you share the full code? i dont see "word=" in your server.py code
  • Cristian Zumelzu
    Cristian Zumelzu over 3 years
    you are right, after this little change works, thanks!