视频流时冻结视频

时间:2019-09-02 02:12:46

标签: javascript python-2.7 sockets opencv video-streaming

我发现以下代码可通过python2.7中的套接字流式传输视频。当我运行它时,视频将在服务器端开始冻结(在Web浏览器中显示该视频)。我调试了代码,并了解在streamer.py中,由于始终满足len(data)

server.py是:

     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)

streamer.py是:

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是:

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()

我想在同一网络的客户端计算机上显示笔记本电脑的摄像头捕获的视频。我希望有视频流,但是在浏览器中,我只是观看图像,并且不会连续更新。

1 个答案:

答案 0 :(得分:0)

当我分析此代码时,我注意到通过网络发送OpenCV帧的默认实现不起作用。我决定将其替换为我使用过before的ZeroMQ实现。您可以查看链接的问题,以更深入地说明流式传输的工作方式。我已经将它整齐地打包到类中,并带有单元测试和文档,SmoothStream也将其签出。

回到问题,这是工作代码。

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)
流媒体
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()
  

我了解到,复制粘贴整个.py文件可能不是在此处发布答案的最佳方法,但这是一个复杂的问题,涉及很多动态内容,老实说,我想不出更好的方法来帮助OP。