使用 Flask、OpenCV 和 WebRTC 构建直播应用程序

在本教程中,我们将探索如何将 Flask、OpenCV 和 WebRTC 简单而强大地结合起来,创建一个流媒体直播应用程序。无论您是初学者还是经验丰富的开发人员,本教程都将一步步指导您创建自己的流媒体直播平台。

要求

机器:任何笔记本电脑/PC 都可用于运行服务器。请注意,我们不会使用任何外部服务器,而是使用 Flask 创建自己的服务器。我们还需要一台可以使用网络浏览器观看直播的机器。这台机器可以是智能手机、不同的笔记本/电脑、远程机器(连接到同一网络)。

摄像头: Webcam / IP camera。

Python 软件包: 需要安装以下软件包。我们将使用 pip。

  • Flask:用于构建一个简单的 Web 应用。
pip install Flask
  • OpenCV:包含处理视频帧的工具。

pip install opencv-python-headless

  • WebRTC:为 Web 应用程序添加实时流功能。我们将直接使用结合了 WebRTC 和 asyncio 的 aiortc python 软件包。
pip install aiortc

开始编码

创建一个目录,名称自定。我们将把项目分为三部分:网页(templates/index.html)、客户端(static/main.js)和服务器端(server.py)。下面是最终的目录层次结构:

your_app
├── static
│   └── main.js
├── templates
│   └── index.html
└── server.py

网页

在这里,我们将为网页创建一个简单的 HTML 模板。您可以自行添加任何花哨的样式,但我们不会这么做。在 your_app/templates 中创建 index.html,并添加以下代码。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Your APP</title>
</head>
<body>
    <video id="remoteVideo" autoplay></video>
    <a href="{{ url_for('video_feed') }}" target="_self">Link to Video Feed</a>
    <script src="{{ url_for('static', filename='main.js') }}"></script>
</body>
</html>

注意:我创建的网页不是直接在网页浏览器上打开实时流,而是提供了一个简单的链接 “Link to Video Feed“,必须点击该链接,然后才能进入实时流,因为一般情况下,您希望在索引页上提供多种服务。但是,如果您想直接观看直播流,请转到下文服务器端部分。

客户端

客户端逻辑将使用 JavaScript 处理。我们将使用网络浏览器来查看我们的直播流,WebRTC API 可通过浏览器本地使用。在 your_app/static 中创建一个 main.js 文件。

如果觉得无聊,可点击此处查看完整的 main.js 文件

  • RTCPeerConnection
let pc = new RTCPeerConnection();

这一行创建了 RTCPeerConnection 类的新实例,该类是 WebRTC 的基本组件,用于建立点对点连接。

  • createOffer Function
async function createOffer() {
    console.log("Sending offer request");

    const offerResponse = await fetch("/offer", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify({
            sdp: "",
            type: "offer",
        }),
    });

    const offer = await offerResponse.json();
    console.log("Received offer response:", offer);

    await pc.setRemoteDescription(new RTCSessionDescription(offer));

    const answer = await pc.createAnswer();
    await pc.setLocalDescription(answer);
}

该异步函数启动与服务器的要约交换流程。它会向服务器的”/offer “端点发送一个 POST 请求,并附上一个空的 SDP(会话描述协议)和要约类型。收到服务器的要约响应后,它会根据收到的要约设置远程描述,并创建一个应答。应答被设置为本地描述。

  • 启动流程

createOffer();

通过创建并向服务器发送报价启动流程。

服务器端

该服务器设置了一个 Flask 网络应用程序,其中包含用于渲染 HTML 模板、处理 WebRTC 报文交换和从摄像头流式传输视频帧的路由。它使用 aiortc 实现 WebRTC 功能,并集成 OpenCV 以生成视频帧。在 your_app 中创建 server.py,并添加以下代码。

完整的 server.py 可在此处找到。

  • 导入模块
from flask import Flask, render_template, Response, request, jsonify
from aiortc import RTCPeerConnection, RTCSessionDescription
import cv2
import json
import uuid
import asyncio
import logging
import time
  • Flask 设置
app = Flask(__name__, static_url_path='/static')

创建带有静态 URL 路径的 Flask 应用程序实例,用于提供静态文件。

  • 视频帧生成
def generate_frames():
 camera = cv2.VideoCapture(0) # ==============IMPORTANT============
 while True:
  start_time = time.time()
  success, frame = camera.read()
  if not success:
   break
  else:
   ret, buffer = cv2.imencode('.jpg', frame)
   frame = buffer.tobytes()
   # concat frame one by one and show result
   yield (b'--frame\r\n'
    b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') 
   elapsed_time = time.time() - start_time
          logging.debug(f"Frame generation time: {elapsed_time} seconds")

VideoCapture() 会触发摄像头并读取帧。

注意:如果要使用webcam(网络摄像头),请在参数中输入 0(零)。如果要使用 IP camera,则需要将 RTSP 链接作为参数传递。请阅读此文了解如何找到 RTSP 链接,但它应该如下所示(包括参数中的引号):

'rtsp://[USER]:[PASS]@[IP_ADDRESS]:[RTSP PORT]/media/video[STREAM TYPE]'
  • 渲染 HTML 模板的路径
@app.route( '/' ) 
def  index (): 
    return render_template( 'index.html' )

注意:该逻辑将带您进入 index.html,在那里您会找到链接到视频源的链接,必须点击该链接才能查看实时流。不过,如果您想直接转到视频源,可以修改上述逻辑,如下所示:

from flask import redirect, url_for

# Route to video_feed directly
@app.route('/')
def index():
    return redirect(url_for('video_feed'))
  • 异步报价处理
async def offer_async():
    params = await request.json
    offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"])

    # Create an RTCPeerConnection instance
    pc = RTCPeerConnection()

    # Generate a unique ID for the RTCPeerConnection
    pc_id = "PeerConnection(%s)" % uuid.uuid4()
    pc_id = pc_id[:8]

    # Create and set the local description
    await pc.createOffer(offer)
    await pc.setLocalDescription(offer)

    # Prepare the response data with local SDP and type
    response_data = {"sdp": pc.localDescription.sdp, "type": pc.localDescription.type}

    return jsonify(response_data)

async_offer()从 JSON 请求中提取参数、创建 RTCPeerConnection、生成唯一 ID 并设置名为 chat 的数据通道。创建、设置本地要约并准备响应数据。

  • 运行异步报价函数的封装函数
def  Offer (): 
    Loop = asyncio.new_event_loop() 
    asyncio.set_event_loop(loop) 
    
    future = asyncio.run_coroutine_threadsafe(offer_async(), Loop) 
    return future.result()

offer() 是一个封装函数,用于使用 asyncio 运行异步 offer_async() 函数。

  • Offer Route
# Route to handle the offer request
@app.route('/offer', methods=['POST'])
def offer_route():
    return offer()
  • Video Feed Route
@app.route('/video_feed')
def video_feed():
    return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
  • 运行 Flask App
if __name__ == "__main__" : 
    app.run(debug= True , host= '0.0.0.0' )

注意:设置 host=’0.0.0.0’将允许您在不同机器的 Web 浏览器中查看流媒体。但机器(客户端)应连接到同一网络。默认情况下,Flask 将绑定到 localhost(127.0.0.1),也就是说,如果不按上图设置,您只能在运行服务器的机器的 Web 浏览器上查看数据流。

开始直播

要启动服务器,请按照以下步骤操作:

  • 导航至应用程序所在的目录。在该目录下打开命令提示符/终端,输入 cd your_app,然后按回车键。
  • 启用 webcam: 如果要使用 webcam,请确保启用摄像头访问。进入 “设置” > “隐私与安全” > “摄像头设置” > “启用摄像头访问”。如果你使用的是不同的操作系统,请遵循类似的设置。
  • 如果没有Web浏览器,请安装任何一款。
  • 在终端/命令提示符下键入:python server.py 或 python3 server.py(如果未设置别名)。
使用 Flask、OpenCV 和 WebRTC 构建直播应用程序

要在同一台机器的浏览器中查看视频流,请按住 Ctrl 键并点击 http://127.0.0.1:5000,这将在默认浏览器中打开网络摄像头视频流。

使用 Flask、OpenCV 和 WebRTC 构建直播应用程序
单击链接以查看本地主机上的流
  • 设置端口

请注意,5000 是 Flask 服务器监听的默认端口。您可以通过修改行设置端口参数来更改端口:

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=8000) # put any port number

确保没有其他服务在新端口上运行,以避免冲突。要检查这一点,请执行以下操作:

在 Windows 上 打开命令提示符并键入:

netstat -ano | findstr :<port_number>

如果没有输出,则说明该端口上没有运行任何程序。但是,如果看到输出,请在输出的最后一列找到进程 ID。键入以下命令杀死进程或使用其他端口:

taskkill /F /PID <process_id>

在 Linux 上打开终端并输入:

sudo netstat -tuln | grep :<port_number>

同样,如果有进程正在运行,需要将其终止。

sudo kill <process_id>

  • 在不同的客户端机器上查看直播

正如你在上面的输出(运行服务器)图片中看到的,你会得到两个链接来查看直播。一个是本地主机 http://127.0.0.1:5000,另一个是你的服务器 IP(为保护隐私,我已将其隐藏)。看起来是这样的

http://<flask_server_ip>:5000

转到另一台客户端机器的浏览器,可以是智能手机或另一台电脑,然后键入第二个链接(带服务器 IP)。然后就可以在浏览器中看到直播了。

要关闭流媒体,只需关闭客户端浏览器。要停止服务器,只需按下 Ctrl + C 即可。

注意事项

  • 如上所述,客户端机器应与服务器机器连接到同一网络(同一无线路由器或以太网等)。
  • 确保服务器上的防火墙设置允许在 Flask 应用程序中使用的端口上传入连接。

参考:GitHub 上的代码

作者:supersjgk

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/webrtc/43200.html

(0)

相关推荐

发表回复

登录后才能评论