我正在尝试在网络浏览器中显示 OpenCV 处理的视频,类似于 ShoutCast 的做法。我知道 ShoutCast 以某种方式通过 HTTP 协议执行此操作,但我不知道如何使其显示视频并加载页面,而不是不断加载直到处理完成。我还知道 ShoutCast 不会向流页面发送任何内容,因为当我启动开发人员工具时,不会定期发送任何内容,但时间不断增加,音乐不断播放。有谁知道我该怎么做?
我的测试代码:
import os
from flask import Flask, Response
import cv2
from utils.app_root_dir import app_root_dir
app = Flask(__name__)
def generate_frames():
cap = cv2.VideoCapture(os.path.normpath(app_root_dir().joinpath("data/temp", "video-979257305707693982.mp4")))
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/video-stream')
def video_feed():
return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame', status=None)
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, threaded=True)
@ChristophRackwitz 说 Flask 不适合视频流。这不是真的。 Flask 并不真正知道或关心你发送给客户端的内容。重要的是您可以以流式传输方式逐块发送内容。当然,Flask 使用生成器支持此操作:https://flask.palletsprojects.com/en/2.3.x/patterns/streaming/
我还知道 ShoutCast 不会向流页面发送任何内容,因为当我启动开发人员工具时,不会定期发送任何内容
不,那不是真的。数据通过单个 HTTP 连接连续传输。浏览器发出对流的请求。服务器发送它,并且不会停止。
有人知道我该怎么做吗?
是的,您需要从使用视频编解码器开始。现在您只是将一帧一帧编码为 JPEG。这不是很有效并且不能按原样工作。您需要 VP9 或 H.264 等视频编解码器来获取原始帧缓冲区并将其编码到流中。
接下来,您需要 mux 流式传输到容器中,例如 WebM/Matroska,它将保留所有计时信息以及其他信息,以便播放器可以实际播放解码的帧。
然后,只需将来自复用器的流按需提供给客户端即可。没有多部分,没有这些,只有流。
完成所有这些操作的最简单方法是从 Python 进程中执行 FFmpeg。将其配置为读取 RGBA 格式的原始帧(或从 OpenCV 获得的任何内容),然后输出视频。像这样的东西...
ffmpeg -f rawvideo -s:v 640x480 -r 30 -i - -c:v libvpx-vp9 -f matroska -
然后,只需将 STDOUT 从 FFmpeg 传输到客户端即可。
在您客户的网页上,就像......一样简单
<video src="/video-stream" autoplay muted></video>