Streaming camera from Python to C# over sockets?

Viewed 479

I need to stream video from a Raspberry Pi's camera (Python server), to a C# script client (Unity, in fact).

I have successfully done this, using a Python to Python workflow, but I can't manage to make It work on C# client side.

This is my python server, where I'm sending the Stream over sockets:

Server.py:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 24000))
s.listen(1)

connection = s.accept()[0].makefile('wb')

print ('Client connected')

while True:
    stream = io.BytesIO()
    for foo in camera.capture_continuous(stream, 'jpeg'):
        connection.write(struct.pack('<L', stream.tell()))
        connection.flush()
        stream.seek(0)
        connection.write(stream.read())
        stream.seek(0)
        stream.truncate()

And this is my Python client side, which is actually working:

Client.py:

def threadLoop(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((self.ip, self.port))

        connection = self.socket.makefile('rb')
        
        print('Recibiendo fotos')
        while not self.haltSignal():
            image_len, image_width, image_height = struct.unpack('<LLL', connection.read(struct.calcsize('<LLL')))
            print ("L: " + str(image_len) + " W: " + str(image_width) + " H: " + str(image_height))

            if not image_len:
                break
            image_stream = io.BytesIO()
            image_stream.write(connection.read(image_len))
            image_stream.seek(0)
            self.callback(image_stream.getvalue(), image_width, image_height)

        self.socket.close()
        self.socket = None
        self.thread = None

So, the question is... having this Server.py, how can I make a C# client that receives the stream and show the pictures?

I've tried to capture the received data in C#, over the socket, store It in a Byte array and convert It to a readable image, which sometimes, when It's a (very)small sized picture, works fine. I guess there must be a better way to achieve this.

Thanks!

Edit: This is what I've been trying in C#. Thanks again!

public int Connect()
{
        if (_clientSocket.Connected == false)
        {
            _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            mutexToSend = new Mutex();
            mutexReceived = new Mutex();

            ThreadStart ts = new ThreadStart(SendReceiveData);
            threadSend = new Thread(ts);
            threadSend.Start();

            return 1;
        }
        else
            return 0;      //There is a socket already connected.
}

//----------------------------------------------------------

private void SendReceiveData()
{

        try
        {
            _clientSocket.SendTimeout = 1000;
            _clientSocket.ReceiveTimeout = 1000;

            System.Net.IPAddress ipaddress = this.serverIP;
            _clientSocket.Connect(new IPEndPoint(ipaddress, this.serverPort));
        }
        catch (SocketException ex)
        {
            //turn ex.Message;  
        }

        _clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}

//----------------------------------------------------------

private void ReceiveCallback(IAsyncResult AR)
{
        //Check how much bytes are recieved and call EndRecieve to finalize handshake
        int recieved = _clientSocket.EndReceive(AR);

        if (recieved <= 0)
        {
            GestorCamaraSala.imgReceived = _recieveBuffer; //I copy the received data to the image texture
            return;
        }

        //Start receiving again
        _clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}// end ReceivedCallback
0 Answers
Related