1 简介
只是简单学学。。。
简单看了下,貌似就是SIP的下一代。因为我对SIP很熟,所以就比对着来写。
传统的SIP
WebRTC
网络端

终端

2 树莓派的实现
代码
bash
webrtc-pi/
├── server.py
├── static/
│ └── client.html
python
import cv2
import asyncio
from aiortc import MediaStreamTrack, RTCPeerConnection, RTCSessionDescription
from aiortc.contrib.media import MediaRelay
from flask import Flask, render_template, request, jsonify, send_from_directory
import json
app = Flask(__name__, static_url_path='')
pcs = set()
relay = MediaRelay()
# 视频采集轨道(OpenCV)
class VideoTrack(MediaStreamTrack):
kind = "video"
def __init__(self):
super().__init__()
self.cap = cv2.VideoCapture(0)
async def recv(self):
pts, time_base = await self.next_timestamp()
ret, frame = self.cap.read()
if not ret:
return None
# 关键:OpenCV 转 RGB
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
from av import VideoFrame
video_frame = VideoFrame.from_ndarray(frame, format="rgb24")
video_frame.pts = pts
video_frame.time_base = time_base
return video_frame
@app.route('/')
def index():
return send_from_directory('static', 'client.html')
@app.route('/offer', methods=['POST'])
def offer():
offer_sdp = request.get_json()
pc = RTCPeerConnection()
pcs.add(pc)
video = VideoTrack()
pc.addTrack(video)
async def create_answer():
await pc.setRemoteDescription(RTCSessionDescription(**offer_sdp))
answer = await pc.createAnswer()
await pc.setLocalDescription(answer)
return pc.localDescription
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
desc = loop.run_until_complete(create_answer())
return jsonify({'sdp': desc.sdp, 'type': desc.type})
@app.route('/answer', methods=['POST'])
def answer():
return "OK"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
client.html
html
<!DOCTYPE html>
<html>
<head>
<title>Raspberry Pi WebRTC Camera</title>
</head>
<body>
<h2>WebRTC Camera Stream</h2>
<video id="video" autoplay playsinline controls></video>
<script>
const pc = new RTCPeerConnection();
const video = document.getElementById("video");
pc.ontrack = function (event) {
video.srcObject = event.streams[0];
};
fetch("/offer", { method: "POST" })
.then(res => res.json())
.then(async ({ sdp, type }) => {
await pc.setRemoteDescription({ sdp, type });
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
fetch("/answer", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(pc.localDescription),
});
});
</script>
</body>
</html>
TODO