Flask 从web服务器上的Raspberry Pi向多个用户传输视频

Flask 从web服务器上的Raspberry Pi向多个用户传输视频,flask,raspberry-pi,streaming,zeromq,pyzmq,Flask,Raspberry Pi,Streaming,Zeromq,Pyzmq,我有一个Raspberry Pi,使用Wifi,它正在运行人员计数模型,并将使用ZeroMQ套接字将处理后的图像发送到我的服务器。在这个服务器上,我使用Flask构建了一个web服务器。我得到了一个错误,第一个访问网站的人在流媒体播放过程中没有显示,但是第一个访问之后的下一个访问将失败: zmq.error.ZMQError:正在使用的地址 我应该怎么做才能让更多的人访问我的服务器并观看视频流 服务器代码: from flask import Flask, render_temp

我有一个Raspberry Pi,使用Wifi,它正在运行人员计数模型,并将使用ZeroMQ套接字将处理后的图像发送到我的服务器。在这个服务器上,我使用Flask构建了一个web服务器。我得到了一个错误,第一个访问网站的人在流媒体播放过程中没有显示,但是第一个访问之后的下一个访问将失败:

zmq.error.ZMQError:正在使用的地址

我应该怎么做才能让更多的人访问我的服务器并观看视频流

服务器代码:

from flask         import Flask, render_template, Response, request, jsonify
from flask_restful import Api
import numpy as np
from api.configs   import configs
from flask_cors    import CORS
import zmq
import cv2
import base64

app = Flask(__name__, static_url_path='/static')
api_restful = Api(app)
cors = CORS(app)

def gen():
    context = zmq.Context()
    footage_socket = context.socket(zmq.SUB)
    footage_socket.bind('tcp://*:{}'.format(configs.SOCKET_PORT))
    footage_socket.setsockopt_string(zmq.SUBSCRIBE, np.unicode(''))
    while True:
        frame = footage_socket.recv()
        npimg = np.fromstring(frame, dtype=np.uint8)
        source = cv2.imdecode(npimg, 1)
        s = cv2.imencode('.jpg', source)[1].tobytes()
        yield ( b'--frame\r\n'
                b'Content-Type: image/jpeg\r\n\r\n' + s + b'\r\n' )

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

if __name__ == '__main__':
    app.run( debug    = True,
             threaded = True,
             port     = configs.PORT,
             host     = configs.HOST
             )
Raspberry Pi客户端代码:

import socket
import logging as log
import numpy as np
from api.configs import configs
import zmq
import numpy as np
import cv2

context = zmq.Context()
footage_socket = context.socket(zmq.PUB)
footage_socket.connect( 'tcp://{}:{}'.format( configs.SERVER_HOST,
                                              configs.SOCKET_PORT )
                         )
time.sleep(1)
cap = cv2.VideoCapture(0)
while True:
    while cap.isOpened():
        ret, frame = cap.read()
        frame = cv2.resize(frame, (640, 480))
        encoded, buffer_ = cv2.imencode('.jpg', frame)
        footage_socket.send(buffer_)
我省略了一些代码,以便于查看

欢迎来到Zen of Zero的艺术。
如果您从未使用过ZeroMQ,
您可能会喜欢在深入了解更多细节之前先看看


我无法谈论
Flask()
web服务视频重新包装/交付中隐藏的细节,但ZeroMQ部分似乎是问题所在,因此:

a)
似乎每个web观察家都会产生另一个
@app.route('/video\u feed')
-desk()-instance(检查模式-如果只是基于线程或基于进程-这很重要,无论是中央
上下文()
实例可能得到共享,也可能无法得到有效重用)

b)
驻留在那里的代码钩住了
Response()
-feeder,它试图为每个后续的
Flask()
-服务的用户
.bind()
,这显然是因为资源(
地址:端口
)在第一次访问时被
POSACK
”专用,第一位访客(任何下一位访客都必须崩溃,并按照上述记录崩溃)


专业的解决方案(或者只是一个快速但肮脏的解决方案): 对于小规模的用例,它应该足以反转
.bind()
/
.connect()
-s,即
发布
.bind()
(因为它不会复制自身,并且可以通过
.connect()
-s提供任何少量的进一步
子项)

然而,这个快速修复有点脏。这决不能在生产级系统中进行。工作量范围很快就会超过合理水平。适当的体系结构应该以不同的方式工作

  • 实例化一个中央
    zmq.Context(configs.nIOthreads)
    -实例(可以共享以在调用的方法中重用),因此出于性能原因,还可以对
    nIOthreads
    进行中央缩放

  • 实例化一个中央
    实例,该实例与Rpi通信并收集视频帧,以避免图像/服务的任何重复

  • 将双方配置为使用
    .setsockopt(zmq.CONFLATE)
    主要避免重新播放视频“无价值的历史记录”

  • 实例化所有的
    @app
    -Flask()
-工具,以重用中央
上下文()
-实例,并使用另一个
发布/发布
原型的
SUB
-侧,在此处内部连接到中央视频,使用proc://
中映射的高效内存,再次使用
.setsockopt(zmq.CONFLATE)

  • 将所有资源配置为具有更高的健壮性-至少使用显式的
    .setsockopt(zmq.LINGER,0)

  • 检测和处理所有错误状态,因为ZeroMQ API充分记录了所有错误状态,可以帮助您专业、安全地诊断和管理任何故障状态

  • 欢迎来到Zero的禅宗艺术。
    如果您从未使用过ZeroMQ,
    您可能会喜欢在深入了解更多细节之前先看看


    我无法谈论
    Flask()
    web服务视频重新包装/交付中隐藏的细节,但ZeroMQ部分似乎是问题所在,因此:

    a)
    似乎每个web观察家都会产生另一个
    @app.route('/video\u feed')
    -desk()
    -instance(检查模式-如果只是基于线程或基于进程-这很重要,无论是中央
    上下文()
    实例可能得到共享,也可能无法得到有效重用)

    b)
    驻留在那里的代码钩住了
    Response()
    -feeder,它试图为每个后续的
    Flask()
    -服务的用户
    .bind()
    ,这显然是因为资源(
    地址:端口
    )在第一次访问时被
    POSACK
    ”专用,第一位访客(任何下一位访客都必须崩溃,并按照上述记录崩溃)


    专业的解决方案(或者只是一个快速但肮脏的解决方案): 对于小规模的用例,它应该足以反转
    .bind()
    /
    .connect()
    -s,即
    发布
    .bind()
    (因为它不会复制自身,并且可以通过
    .connect()
    -s提供任何少量的进一步
    子项)

    然而,这个快速修复有点脏。这决不能在生产级系统中进行。工作量范围很快就会超过合理水平。适当的体系结构应该以不同的方式工作

    • 实例化一个中央
      zmq.Context(configs.nIOthreads)
      -实例(可以共享以在调用的方法中重用),因此出于性能原因,还可以对
      nIOthreads
      进行中央缩放

    • 实例化一个与Rpi通信并收集视频-f的中央
      -实例