如何在Django REST Framework结合React实现多摄像头直播展示
解决方案
用OpenCV + Django REST Framework 实现多摄像头实时流
完全可以用OpenCV实现,结合DRF的流式响应能力,就能在浏览器中展示多个摄像头的实时画面。
后端实现(DRF视图)
- 先安装OpenCV依赖:
pip install opencv-python
- 编写流式响应视图,读取摄像头帧并编码为JPEG流:
from django.http import StreamingHttpResponse import cv2 from rest_framework.decorators import api_view def generate_camera_frames(camera_source): # camera_source可以是整数(本地摄像头ID,0为内置,1为外接等)或网络摄像头URL cap = cv2.VideoCapture(camera_source) if not cap.isOpened(): yield b'' return while True: success, frame = cap.read() if not success: break # 将帧编码为JPEG格式 ret, buffer = cv2.imencode('.jpg', frame) if not ret: continue # 以multipart/x-mixed-replace格式输出,浏览器会自动刷新画面 yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + buffer.tobytes() + b'\r\n') cap.release() @api_view(['GET']) def camera_stream(request, camera_id): # 根据camera_id映射到实际的摄像头源,比如配置在settings里 camera_sources = { 0: 0, # 本地内置摄像头 1: "rtsp://admin:password@192.168.1.100:554/stream", # 网络摄像头RTSP地址 # 更多摄像头配置... } source = camera_sources.get(int(camera_id), 0) return StreamingHttpResponse( generate_camera_frames(source), content_type='multipart/x-mixed-replace; boundary=frame' )
- 配置URL路由:
# urls.py from django.urls import path from .views import camera_stream urlpatterns = [ path('api/camera/stream/<str:camera_id>/', camera_stream, name='camera-stream'), ]
前端React处理
直接用<img>标签加载每个摄像头的流地址即可,浏览器会自动处理实时刷新:
import React from 'react'; const CameraStream = ({ cameraId }) => { const streamUrl = `/api/camera/stream/${cameraId}/`; return <img src={streamUrl} alt={`Camera ${cameraId}`} style={{ width: '400px', margin: '10px' }} />; }; const MultiCameraView = () => { // 假设有3个摄像头 const cameraIds = [0, 1, 2]; return ( <div style={{ display: 'flex', flexWrap: 'wrap' }}> {cameraIds.map(id => <CameraStream key={id} cameraId={id} />)} </div> ); }; export default MultiCameraView;
DRF生成字节流响应的通用方法
如果不需要OpenCV,只是要返回字节流(比如文件、自定义二进制数据),有两种方式:
一次性字节数据响应
适合返回完整的二进制文件或数据:
from rest_framework.response import Response from rest_framework.decorators import api_view @api_view(['GET']) def static_byte_stream(request): # 示例:读取本地文件作为字节流返回 with open('example.bin', 'rb') as f: byte_data = f.read() return Response( byte_data, content_type='application/octet-stream', headers={'Content-Disposition': 'attachment; filename="example.bin"'} )
流式字节数据响应
适合实时生成的字节流(比如实时日志、动态生成的内容):
from django.http import StreamingHttpResponse from rest_framework.decorators import api_view def generate_byte_chunks(): # 模拟实时生成字节数据 for i in range(10): yield f"实时数据块 {i}\n".encode('utf-8') @api_view(['GET']) def dynamic_byte_stream(request): return StreamingHttpResponse( generate_byte_chunks(), content_type='text/plain' )
额外提示
- 如果是前端用户本地的摄像头,更高效的方式是直接用浏览器的
MediaDevices API获取流,不需要经过后端,React中可以这样实现:
const LocalCamera = ({ deviceId }) => { const videoRef = React.useRef(null); React.useEffect(() => { const startStream = async () => { const stream = await navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: deviceId } } }); if (videoRef.current) { videoRef.current.srcObject = stream; } }; startStream(); return () => { if (videoRef.current?.srcObject) { videoRef.current.srcObject.getTracks().forEach(track => track.stop()); } }; }, [deviceId]); return <video ref={videoRef} autoPlay playsInline style={{ width: '400px', margin: '10px' }} />; };
- 服务器端摄像头流要注意资源占用,建议用异步任务或线程池处理多个摄像头的读取,避免阻塞请求。
- 跨域场景下,需要在DRF中配置CORS(比如使用
django-cors-headers包)。
内容的提问来源于stack exchange,提问作者Muhammad Arshad
相关产品推荐
相关产品推荐

