-1

I find the following code for streaming video over a socket in python2.7. When I run it, the video will be freeze at the beginning in the server-side (It shows the video in a web browser). I debugged the code and understood that in the streamer.py, the third while loop condition creates an infinite loop because of the condition while len(data) < msg_size: is always satisfied. In other words, len(data) is always less than msg_size.So, the streamer.py does not return the image to the server.py. Could anyone help me to solve this issue?

The server.py is:

     from flask import Flask, render_template, Response
     from streamer import Streamer
     app = Flask(__name__)

     def gen():
       streamer = Streamer('localhost', 8089)
       streamer.start()

       while True:
         if streamer.client_connected():
             yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + 
             streamer.get_jpeg() + b'\r\n\r\n')

    @app.route('/')
    def index():
       return render_template('index.html')

    @app.route('/video_feed')
    def video_feed():
        return Response(gen(), mimetype='multipart/x-mixed-replace; 
        boundary=frame')

    if __name__ == '__main__':
      app.run(host='localhost', threaded=True)

The streamer.py is:

import threading
import socket
import struct
import StringIO
import json
import numpy

class Streamer (threading.Thread):
  def __init__(self, hostname, port):
    threading.Thread.__init__(self)

    self.hostname = hostname
    self.port = port
    self.connected = False
    self.jpeg = None

  def run(self):

    self.isRunning = True

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

    s.bind((self.hostname, self.port))
    print 'Socket bind complete'

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

    s.listen(10)
    print 'Socket now listening'

    while self.isRunning:

      conn, addr = s.accept()
      print 'while 1...'

      while True:

        data = conn.recv(4096)

        print 'while 2...'
        if data:
          packed_msg_size = data[:payload_size]
          data = data[payload_size:]
          msg_size = struct.unpack("L", packed_msg_size)[0]

          while len(data) < msg_size:# the infinite loop is here(my problem)!
            data += conn.recv(4096)
            print ("lenght of data is " , len(data) )
            print ("message size is  " ,  msg_size )

          frame_data = data[:msg_size]
          #frame_data = data[:len(data)]
          memfile = StringIO.StringIO()
          memfile.write(json.loads(frame_data).encode('latin-1'))
          memfile.seek(0)
          frame = numpy.load(memfile)

          ret, jpeg = cv2.imencode('.jpg', frame)
          self.jpeg = jpeg

          self.connected = True
          print 'recieving...'

        else:
          conn.close()
          self.connected = False
          print 'connected=false...'
          break

    self.connected = False

  def stop(self):
    self.isRunning = False

  def client_connected(self):
    return self.connected

  def get_jpeg(self):
    return self.jpeg.tobytes()

Client.py is:

import socket
import sys
import pickle
import struct
import StringIO
import json
import time

cap=cv2.VideoCapture(0)
clientsocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
clientsocket.connect(('localhost',8089))

while(cap.isOpened()):
  ret,frame=cap.read()

  memfile = StringIO.StringIO()
  np.save(memfile, fravidme)
  memfile.seek(0)
  data = json.dumps(memfile.read().decode('latin-1'))

  clientsocket.sendall(struct.pack("L", len(data))+data)
  if cv2.waitKey(1) & 0xFF == ord('q'):
    break

cap.release()

I want to show the video captured by my laptop's camera on a client machine in the same network. I expect video stream but in the browser, I just watch an image and it does not update continuously.

HansHirse
  • 18,010
  • 10
  • 38
  • 67
Sajjad Rostami
  • 303
  • 2
  • 3
  • 12

1 Answers1

0

As I analyzed this code I noticed that the default implementation for sending OpenCV frames over the network was not working. I decided to replace it with ZeroMQ implementation I have used before. You can check out the linked question for a deeper explanation of how the streaming works. I have neatly packaged it into classes, with unit tests and documentation as SmoothStream check it out too.

Coming back to the question, here is the working code.

client.py
import base64
import cv2
import zmq

context = zmq.Context()
footage_socket = context.socket(zmq.PUB)
footage_socket.connect('tcp://localhost:5555')

camera = cv2.VideoCapture(0)  # init the camera

while True:
    try:
        grabbed, frame = camera.read()  # grab the current frame
        frame = cv2.resize(frame, (640, 480))  # resize the frame
        encoded, buffer = cv2.imencode('.jpg', frame)
        jpg_as_text = base64.b64encode(buffer)
        footage_socket.send(jpg_as_text)

    except KeyboardInterrupt:
        camera.release()
        cv2.destroyAllWindows()
        break
server.py
from flask import Flask, render_template, Response
from streamer import Streamer

app = Flask(__name__)


def gen():
    streamer = Streamer('*', 5555)
    streamer.start()

    while True:
        if streamer.client_connected():
            yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + streamer.get_jpeg() + b'\r\n\r\n')


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/video_feed')
def video_feed():
    return Response(gen(), mimetype='multipart/x-mixed-replace; boundary=frame')


if __name__ == '__main__':
    app.run(host='localhost', threaded=True)
streamer.py
import base64
import threading

import cv2
import numpy as np
import zmq


class Streamer(threading.Thread):
    def __init__(self, hostname, port):
        threading.Thread.__init__(self)

        self.hostname = hostname
        self.port = port
        self.connected = False
        self.jpeg = None

    def run(self):

        self.isRunning = True

        context = zmq.Context()
        footage_socket = context.socket(zmq.SUB)
        footage_socket.bind('tcp://{}:{}'.format(self.hostname, self.port))
        footage_socket.setsockopt_string(zmq.SUBSCRIBE, np.unicode(''))

        while self.isRunning:
            frame = footage_socket.recv_string()
            img = base64.b64decode(frame)
            npimg = np.fromstring(img, dtype=np.uint8)
            source = cv2.imdecode(npimg, 1)

            ret, jpeg = cv2.imencode('.jpg', source)
            self.jpeg = jpeg

            self.connected = True

        self.connected = False

    def stop(self):
        self.isRunning = False

    def client_connected(self):
        return self.connected

    def get_jpeg(self):
        return self.jpeg.tobytes()

I understand that copy-pasting entire .py files are probably not the best way to post an answer here, but this is a complex question with a lot of moving parts and I honestly could not think of a better way to help the OP.

Community
  • 1
  • 1
Rohan Sawant
  • 938
  • 1
  • 11
  • 18