将网络服务器上 Raspberry Pi 的视频流式传输给多个用户
Streaming video from Raspberry Pi on web server to multiple users
我有一个 Raspberry Pi,使用 Wifi,它是 运行 一个人数统计模型,并将使用 ZeroMQ 套接字将处理后的图像发送到我的服务器。在这台服务器上,我使用 Flask 构建了一个 Web 服务器。我收到一个错误,该错误在第一位访问该网站的人的流式传输期间未显示,但第一次访问后的下一次访问将失败:
zmq.error.ZMQError: Address in use
我应该怎么做才能让更多人访问我的服务器并可以看到视频流?
服务器代码:
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_)
我省略了一些代码以便于查看
欢迎来到零之禅的艺术。
如果你从未使用过 ZeroMQ,
你可能会喜欢先看看
,然后再深入了解更多细节
我不能谈论隐藏在 Flask()
网络服务视频 re-wrapping/delivery 中的细节,但 ZeroMQ 部分似乎是问题所在,所以:
a )
似乎每个网络观察者都会生成另一个 @app.route( '/video_feed' )
-decorated Flask()
-实例(检查模式——如果只是基于线程,或基于进程——重要的是,中央 Context()
实例是否可以获取共享并有效地重复使用)。
b )
代码,驻留在那里钩住 Response()
-feeder,尝试 .bind()
为每个后续 Flask()
-服务的用户,由于明显的原因会发生冲突,因为资源( address:port
)已被 POSACK
专供先到先得的访问者使用(任何下一个必须崩溃并如上文所述崩溃)。
专业解决方案(或者只是一个快速但-脏-修复?) :
对于确实小规模的用例,反转.bind()
/.connect()
[=99=就足够了]-s,即 PUB
将 .bind()
(因为它不会自我复制,并且可以服务任何少量的进一步 SUB
(s),通过 .connect()
-s 到达)
但是,这个快速修复有点脏。这绝不应该在生产级系统中完成。工作量范围很快就会超过合理水平。正确的架构应该以不同的方式工作。
实例化一个中央 zmq.Context( configs.nIOthreads )
实例(可以共享以在调用的方法中重复使用),因此出于性能原因也具有 nIOthreads
的中央缩放。
实例化一个中央 SUB
实例,它与 Rpi 通信并收集视频帧,以避免 image/serving
的任何重复
配置双方使用.setsockopt( zmq.CONFLATE )
主要是为了避免视频的任何重播 "History of No Value"
实例化所有 @app
-修饰的 Flask()
-工具以重新使用中央 Context()
-实例并在内部连接到中央视频重-PUB
-lisher,使用另一个 PUB/SUB
原型的 SUB
端,这里使用高效的内存映射 inproc://
,再次使用 .setsockopt( zmq.CONFLATE )
配置所有资源以具有更高的稳健性 - 至少使用显式 .setsockopt( zmq.LINGER, 0 )
检测并处理所有错误状态,因为 ZeroMQ API 很好地记录了所有错误状态,足以帮助您专业安全地诊断 + 管理任何故障状态
我有一个 Raspberry Pi,使用 Wifi,它是 运行 一个人数统计模型,并将使用 ZeroMQ 套接字将处理后的图像发送到我的服务器。在这台服务器上,我使用 Flask 构建了一个 Web 服务器。我收到一个错误,该错误在第一位访问该网站的人的流式传输期间未显示,但第一次访问后的下一次访问将失败:
zmq.error.ZMQError: Address in use
我应该怎么做才能让更多人访问我的服务器并可以看到视频流?
服务器代码:
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_)
我省略了一些代码以便于查看
欢迎来到零之禅的艺术。
如果你从未使用过 ZeroMQ,
你可能会喜欢先看看
,然后再深入了解更多细节
我不能谈论隐藏在 Flask()
网络服务视频 re-wrapping/delivery 中的细节,但 ZeroMQ 部分似乎是问题所在,所以:
a )
似乎每个网络观察者都会生成另一个 @app.route( '/video_feed' )
-decorated Flask()
-实例(检查模式——如果只是基于线程,或基于进程——重要的是,中央 Context()
实例是否可以获取共享并有效地重复使用)。
b )
代码,驻留在那里钩住 Response()
-feeder,尝试 .bind()
为每个后续 Flask()
-服务的用户,由于明显的原因会发生冲突,因为资源( address:port
)已被 POSACK
专供先到先得的访问者使用(任何下一个必须崩溃并如上文所述崩溃)。
专业解决方案(或者只是一个快速但-脏-修复?) :
对于确实小规模的用例,反转.bind()
/.connect()
[=99=就足够了]-s,即 PUB
将 .bind()
(因为它不会自我复制,并且可以服务任何少量的进一步 SUB
(s),通过 .connect()
-s 到达)
但是,这个快速修复有点脏。这绝不应该在生产级系统中完成。工作量范围很快就会超过合理水平。正确的架构应该以不同的方式工作。
实例化一个中央
zmq.Context( configs.nIOthreads )
实例(可以共享以在调用的方法中重复使用),因此出于性能原因也具有nIOthreads
的中央缩放。实例化一个中央
的任何重复SUB
实例,它与 Rpi 通信并收集视频帧,以避免 image/serving配置双方使用
.setsockopt( zmq.CONFLATE )
主要是为了避免视频的任何重播 "History of No Value"实例化所有
@app
-修饰的Flask()
-工具以重新使用中央Context()
-实例并在内部连接到中央视频重-PUB
-lisher,使用另一个PUB/SUB
原型的SUB
端,这里使用高效的内存映射inproc://
,再次使用.setsockopt( zmq.CONFLATE )
配置所有资源以具有更高的稳健性 - 至少使用显式
.setsockopt( zmq.LINGER, 0 )
检测并处理所有错误状态,因为 ZeroMQ API 很好地记录了所有错误状态,足以帮助您专业安全地诊断 + 管理任何故障状态