【问题标题】:Video is freezed while video streaming视频流式传输时视频被冻结
【发布时间】:2019-09-02 02:12:46
【问题描述】:

我在 python2.7 中找到以下用于通过套接字流式传输视频的代码。当我运行它时,视频将在服务器端开始冻结(它在网络浏览器中显示视频)。我调试了代码,了解到在 streamer.py 中,第三个 while 循环条件创建了一个无限循环,因为条件 while 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()

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

【问题讨论】:

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


    【解决方案1】:

    当我分析这段代码时,我注意到通过网络发送 OpenCV 帧的默认实现不起作用。我决定用我使用过的 ZeroMQ 实现替换它before。您可以查看链接的问题,以更深入地解释流式传输的工作原理。我已经将它整齐地打包成类,单元测试和文档为SmoothStream,也请查看。

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

    客户端.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
    
    服务器.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)
    
    流光.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()
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-06
      • 1970-01-01
      • 2010-11-03
      • 1970-01-01
      • 1970-01-01
      • 2011-04-07
      • 1970-01-01
      相关资源
      最近更新 更多