Unity WebGL实现RTSP视频流弹窗播放:基于FFmpeg与HLS的完整方案
1. 项目概述:为什么要在Unity WebGL里折腾RTSP弹窗?
做Unity开发的朋友,尤其是涉及安防监控、智慧园区、工业物联网这类需要实时视频预览的项目,估计都遇到过这个头疼的问题:客户要求在网页里就能直接看摄像头的实时画面,而且最好是点一下就能弹窗播放,别搞得太复杂。Unity WebGL是个好东西,能把你的3D应用直接搬到浏览器里跑,但一碰到RTSP这种实时流媒体协议,就有点“水土不服”了。
RTSP(Real Time Streaming Protocol)是监控摄像头、网络视频录像机(NVR)最常用的取流协议。它本身不传输数据,更像一个“遥控器”,负责建立和控制RTP/RTCP数据包的传输。浏览器原生环境,比如Chrome、Firefox,早就因为安全和实现复杂度等原因,放弃了对RTSP的直接支持。这就意味着,你没法像播一个MP4文件那样,简单地在HTML5的<video>标签里塞一个rtsp://地址就完事。
所以,这个“终极教程”要解决的核心矛盾就是:在Unity WebGL这个“沙盒”环境里,如何打通从RTSP流到浏览器视频播放的整个链路,并且实现用户友好的弹窗交互。这不仅仅是写几行C#代码调用Unity的VideoPlayer组件那么简单,它涉及到流媒体协议的转换、前后端的分工、以及Unity与JavaScript的深度交互。我做过好几个类似的项目,从最初的一头雾水到现在的稳定方案,踩过的坑不计其数。今天就把这套经过实战检验的、完全免费的方案拆开揉碎了讲给你听,目标是让你看完就能动手实现。
简单来说,我们的技术路线图是这样的:摄像头输出RTSP流 → 服务器端进行协议转换(转成Web友好的格式如HLS或WebRTC) → Unity WebGL应用通过网页前端技术(JavaScript)请求并播放转换后的流 → 在Unity中触发弹窗逻辑来展示这个播放器。整个过程,Unity更像一个“导演”,指挥着浏览器里的“演员”(HTML/JS组件)来完成播放动作。
2. 核心思路与架构选型:为什么是“转码+前端播放”?
当你决定在WebGL里播放RTSP时,摆在面前的有几条路,但很多都是死胡同。首先,直接让Unity的VideoPlayer去播RTSP地址?此路不通。Unity WebGL的VideoPlayer在浏览器底层依赖的是HTML5 Video,它同样不支持RTSP。其次,在Unity里集成一个原生的RTSP解码库(比如用FFmpeg)编译到WebGL?理论上可行,但实践上是噩梦。WebGL是沙盒环境,对本地文件系统、网络套接字的访问有极其严格的限制,而且FFmpeg库体积庞大,编译到WebGL后性能堪忧,还可能遇到内存、线程等一系列兼容性问题,对于生产环境来说风险太高。
因此,业界公认的、最稳妥的方案是将协议转换的工作放到服务器端。让专业的服务器软件去做RTSP拉流、解码、转码、再封装成Web端能直接播放的格式。Unity WebGL应用只负责展示和交互。这个架构清晰地将责任分离,也符合现代Web应用的设计哲学。
那么,服务器端转成什么格式最好呢?主要有两个主流选择:
- HLS (HTTP Live Streaming):苹果公司推出的标准,现在已被广泛支持。它把整个流切割成一个个小的TS文件片段(m3u8索引),通过普通的HTTP协议下载播放。优点是兼容性极好,从桌面浏览器到手机浏览器基本通吃。缺点是延迟较高,通常有几秒到十几秒,因为需要缓存一定数量的分片才能开始播放。适合对实时性要求不高的监控回看或直播场景。
- WebRTC (Web Real-Time Communication):谷歌主导的实时通信协议,天生为低延迟而生,延迟可以做到毫秒级。它是点对点的,但通常也需要一个信令服务器和(可选的)流媒体服务器(如Janus, Mediasoup)。优点是延迟极低,体验流畅。缺点是实现复杂度高,服务器资源消耗相对大,且在一些企业内网环境下可能因为UDP端口等问题遇到连接障碍。
对于大多数“视频弹窗播放”的场景,比如查看一个摄像头的实时画面,HLS的延迟通常是可接受的。它的技术栈更简单、更成熟,免费开源的方案也多。因此,本教程将围绕HLS方案展开。如果你有超低延迟(<1秒)的强需求,可以在理解本方案后,自行研究将后端替换为WebRTC网关。
整个架构的流程图可以这样理解:
[摄像头/NVR] --(RTSP流)--> [流媒体服务器 (如FFmpeg, Nginx-rtmp-module)] --(HLS流 .m3u8/.ts)--> [Web服务器 (如Nginx)] | v [用户浏览器] <--(HTML/JS/Unity WebGL)--> [点击播放] --(请求.m3u8)--> [Web服务器]Unity WebGL包和转换后的HLS流,都由同一个或同域的Web服务器提供,这样可以避免跨域问题。
3. 服务器端流媒体转换实战:用FFmpeg打造免费转码服务
服务器端是我们的“心脏”,它需要持续稳定地将摄像头的RTSP流“翻译”成HLS。这里我强烈推荐使用FFmpeg,它是音视频处理领域的“瑞士军刀”,免费、强大、灵活。我们将在一台Linux服务器(Ubuntu/CentOS均可)上部署它。
3.1 环境准备与FFmpeg安装
首先,确保你有一台有公网IP或至少能在局域网内访问的服务器。通过SSH登录后,更新系统并安装FFmpeg。在Ubuntu上,命令非常简单:
sudo apt update sudo apt install ffmpeg安装完成后,输入ffmpeg -version检查是否安装成功。接下来,我们需要一个地方来存放生成的HLS文件(即.m3u8索引文件和.ts分片文件)。创建一个专用目录:
sudo mkdir -p /var/www/hls/live sudo chmod -R 755 /var/www/hls这里/var/www/hls是我们的HLS根目录,live子目录用于存放实时生成的片段。你可以根据实际情况调整路径。
3.2 FFmpeg转码命令深度解析
这是最核心的一步。假设你的摄像头RTSP地址是rtsp://admin:password@192.168.1.100:554/h264/ch1/main/av_stream,我们要将它转为HLS。一个基础但功能完整的FFmpeg命令如下:
ffmpeg -i "rtsp://admin:password@192.168.1.100:554/h264/ch1/main/av_stream" \ -c:v copy \ -c:a aac \ -f hls \ -hls_time 2 \ -hls_list_size 5 \ -hls_flags delete_segments \ -hls_segment_filename "/var/www/hls/live/camera1_%03d.ts" \ /var/www/hls/live/camera1.m3u8我们来逐条解析这个命令,理解每个参数背后的“为什么”,这对排查问题至关重要:
-i "rtsp://...":指定输入源,即你的摄像头RTSP地址。地址格式很关键,通常包含用户名、密码、IP、端口和流路径。有些摄像头可能有主码流、子码流之分,需要查阅摄像头厂商的文档。-c:v copy:视频编码器选项。copy意味着直接复制(转封装),不进行重新编码。这是性能最佳、延迟最低的方式,前提是摄像头的原始编码(通常是H.264)能被浏览器支持。如果你的摄像头输出的是H.265(HEVC),大多数浏览器不支持,那么你就需要将其转码为H.264,例如-c:v libx264。-c:a aac:音频编码器选项。将音频转码为AAC格式,这是HLS标准推荐且浏览器广泛支持的格式。如果流里没有音频,可以加-an参数禁用音频处理。-f hls:指定输出格式为HLS。-hls_time 2:设置每个TS分片的目标时长,单位为秒。这里设置为2秒。这个值会影响延迟和流畅度。值越小,延迟越低,但服务器负载会稍高(因为更频繁地生成文件)。通常设置在2-6秒之间。-hls_list_size 5:在m3u8播放列表中保留的TS分片数量。这里保留5个。结合-hls_time 2,意味着播放列表大约包含10秒的内容。当生成新的分片时,旧的分片会被从列表中移除(如果配合delete_segments,文件也会被删除)。-hls_flags delete_segments:一个非常重要的标志。它会让FFmpeg自动删除旧的、不再出现在播放列表里的TS分片文件。如果没有这个标志,TS文件会不断堆积,直到撑满你的硬盘!这是线上部署必须加的参数。-hls_segment_filename:定义生成的TS分片文件的命名模式。%03d会被替换为三位数的序列号(如001, 002)。- 最后一个参数:指定输出的m3u8索引文件的路径和文件名。
重要提示:将RTSP地址中的用户名和密码明文写在命令里存在安全风险。在生产环境中,应考虑使用更安全的方式,如配置文件中加密存储,或使用摄像头支持的另一种认证方式。
3.3 后台运行与管理:让转码服务稳定持续
我们不能在SSH窗口里一直运行这个命令,窗口一关服务就停了。我们需要让它成为后台服务。这里推荐使用systemd来管理,这是Linux上标准的服务管理工具,可以方便地设置开机自启、查看日志、重启服务。
创建一个systemd服务文件:
sudo nano /etc/systemd/system/rtsp-to-hls.service将以下内容粘贴进去,请根据你的实际情况修改ExecStart中的命令和User:
[Unit] Description=RTSP to HLS Transcoder for Camera 1 After=network.target [Service] Type=simple User=www-data # 建议使用一个非root用户,如www-data或新建一个用户 Restart=always RestartSec=5 ExecStart=/usr/bin/ffmpeg -i "rtsp://admin:password@192.168.1.100:554/h264/ch1/main/av_stream" -c:v copy -c:a aac -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments -hls_segment_filename "/var/www/hls/live/camera1_%%03d.ts" /var/www/hls/live/camera1.m3u8 ExecStop=/bin/kill -TERM $MAINPID StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target注意:在systemd的ExecStart里,%需要转义为%%。
保存退出后,执行以下命令:
# 重新加载systemd配置 sudo systemctl daemon-reload # 启动服务 sudo systemctl start rtsp-to-hls.service # 设置开机自启 sudo systemctl enable rtsp-to-hls.service # 查看服务状态和日志 sudo systemctl status rtsp-to-hls.service sudo journalctl -u rtsp-to-hls.service -f如果状态显示active (running),并且日志中没有持续的错误输出,说明服务启动成功。此时,你可以检查/var/www/hls/live/目录下是否生成了camera1.m3u8和camera1_001.ts等文件。
3.4 配置Web服务器(Nginx)提供HLS流
现在HLS文件已经生成了,我们需要一个Web服务器(如Nginx)来把它们发布出去,让浏览器能够通过HTTP访问到。
安装Nginx(如果尚未安装):
sudo apt install nginx为HLS流配置一个location。编辑Nginx的站点配置文件,通常是/etc/nginx/sites-available/default:
sudo nano /etc/nginx/sites-available/default在server块内,添加以下配置:
server { listen 80; server_name your_server_ip_or_domain; # 你的服务器IP或域名 location /hls { # 指向我们存放HLS文件的目录 alias /var/www/hls; # 设置正确的MIME类型,这对HLS播放至关重要 types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } # 允许跨域访问(如果Unity WebGL页面和HLS流在不同域名下) add_header Access-Control-Allow-Origin *; # 禁用缓存,确保总是获取最新的直播片段(对直播很重要) add_header Cache-Control no-cache; # 允许预检请求 if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, OPTIONS'; add_header Access-Control-Allow-Headers 'Range'; add_header Access-Control-Max-Age 1728000; add_header Content-Type 'text/plain; charset=utf-8'; add_header Content-Length 0; return 204; } } # ... 其他配置,比如托管Unity WebGL构建文件的location location / { root /var/www/unity_webgl; # 你的Unity WebGL构建文件目录 index index.html index.htm; try_files $uri $uri/ /index.html; } }保存并测试Nginx配置,然后重启:
sudo nginx -t sudo systemctl reload nginx现在,你的HLS流应该可以通过http://你的服务器IP/hls/live/camera1.m3u8访问到了。用浏览器或VLC播放器打开这个链接测试一下,如果能播放,说明服务器端全部搞定。
4. Unity WebGL前端交互:用JavaScript“桥接”视频播放
服务器端准备就绪后,我们转向Unity。Unity WebGL不能直接播放HLS,但浏览器可以。所以我们的策略是:在Unity里触发一个事件,然后通过JavaScript在网页上动态创建一个视频播放器来播放HLS流,并以弹窗形式呈现。
4.1 创建播放器弹窗的HTML/JS模块
首先,我们需要在托管Unity WebGL的HTML页面(通常是index.html)里,提前准备好视频弹窗所需的HTML结构和CSS样式,以及控制它的JavaScript函数。
在你的index.html的<body>标签内,Unity的<canvas>元素之后,添加如下代码:
<!-- 视频弹窗容器,默认隐藏 --> <div id="videoModal" class="modal" style="display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.8);"> <div class="modal-content" style="position: relative; margin: 5% auto; padding: 20px; width: 80%; max-width: 900px; background: #222; border-radius: 10px;"> <span class="close" style="position: absolute; right: 20px; top: 10px; color: #aaa; font-size: 28px; font-weight: bold; cursor: pointer;">×</span> <h2 style="color: white;">实时视频</h2> <!-- 视频播放器容器 --> <div id="videoPlayerContainer"> <video id="hlsVideoPlayer" controls style="width: 100%; height: auto; background: #000;"></video> </div> <p style="color: #ccc; margin-top: 10px;">视频加载中...</p> </div> </div> <script> // 引入HLS.js库,这是一个强大的HLS客户端JavaScript库,兼容所有浏览器。 // 我们使用CDN链接,你也可以下载到本地。 if (!window.Hls) { const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/hls.js@latest'; document.head.appendChild(script); } // 定义全局函数供Unity调用 window.unityNamespace = window.unityNamespace || {}; // 打开视频弹窗并播放指定流 unityNamespace.openVideoPopup = function(hlsStreamUrl) { const modal = document.getElementById('videoModal'); const videoElement = document.getElementById('hlsVideoPlayer'); const statusText = modal.querySelector('p'); // 显示弹窗 modal.style.display = 'block'; statusText.textContent = '正在加载视频流...'; // 清理之前的HLS实例(如果存在) if (window.currentHlsInstance) { window.currentHlsInstance.destroy(); window.currentHlsInstance = null; } // 检查浏览器是否原生支持HLS(如Safari) if (videoElement.canPlayType('application/vnd.apple.mpegurl')) { videoElement.src = hlsStreamUrl; statusText.textContent = '使用原生HLS播放...'; } else if (window.Hls && Hls.isSupported()) { // 使用hls.js库 const hls = new Hls({ enableWorker: true, // 使用Web Worker提升性能 lowLatencyMode: true, // 低延迟模式 backBufferLength: 90, // 控制内存占用 }); window.currentHlsInstance = hls; hls.loadSource(hlsStreamUrl); hls.attachMedia(videoElement); hls.on(Hls.Events.MANIFEST_PARSED, function() { console.log('HLS流加载成功,开始播放。'); statusText.textContent = ''; videoElement.play().catch(e => { statusText.textContent = '自动播放被阻止,请点击播放按钮。'; console.warn('自动播放失败:', e); }); }); hls.on(Hls.Events.ERROR, function(event, data) { console.error('HLS错误:', data); if (data.fatal) { switch(data.type) { case Hls.ErrorTypes.NETWORK_ERROR: statusText.textContent = '网络错误,正在尝试重连...'; hls.startLoad(); break; case Hls.ErrorTypes.MEDIA_ERROR: statusText.textContent = '媒体解码错误,尝试恢复...'; hls.recoverMediaError(); break; default: statusText.textContent = '无法播放此视频流。'; hls.destroy(); break; } } }); } else { statusText.textContent = '抱歉,您的浏览器不支持HLS视频播放。'; return; } // 关闭按钮事件 const closeBtn = modal.querySelector('.close'); closeBtn.onclick = function() { unityNamespace.closeVideoPopup(); }; // 点击弹窗背景关闭 modal.onclick = function(event) { if (event.target === modal) { unityNamespace.closeVideoPopup(); } }; }; // 关闭视频弹窗 unityNamespace.closeVideoPopup = function() { const modal = document.getElementById('videoModal'); const videoElement = document.getElementById('hlsVideoPlayer'); modal.style.display = 'none'; videoElement.pause(); videoElement.src = ''; // 清空src以停止加载 if (window.currentHlsInstance) { window.currentHlsInstance.destroy(); window.currentHlsInstance = null; } }; </script>这段代码做了几件关键事:
- 创建了一个全屏遮罩的弹窗(
#videoModal)。 - 引入了
hls.js库,它是一个功能完善的HLS客户端,解决了非Safari浏览器(如Chrome, Firefox)的HLS播放问题。 - 定义了
openVideoPopup(url)函数,它接收一个HLS流的m3u8地址,然后初始化播放器并开始播放。 - 定义了
closeVideoPopup()函数来清理资源并关闭弹窗。 - 添加了错误处理和用户交互(点击关闭)。
4.2 在Unity中调用JavaScript函数
现在,我们需要在Unity C#脚本中,调用上面定义的JavaScript函数。Unity提供了Application.ExternalCall和[DllImport("__Internal")]等方式与JavaScript通信。在较新的Unity版本中,推荐使用WebGL插件接口。
首先,创建一个C#脚本,比如叫VideoPopupController.cs:
using UnityEngine; using System.Runtime.InteropServices; // 用于DllImport public class VideoPopupController : MonoBehaviour { // 声明要调用的JavaScript函数 [DllImport("__Internal")] private static extern void OpenVideoPopup(string url); [DllImport("__Internal")] private static extern void CloseVideoPopup(); // 一个公开的方法,用于在Unity中(例如按钮点击事件)触发播放 public void PlayStreamInPopup() { // 这里拼接你的HLS流完整URL。在实际项目中,这个URL可能来自配置、数据库或用户输入。 string hlsStreamUrl = "http://你的服务器IP/hls/live/camera1.m3u8"; // 检查是否在WebGL平台下运行 #if UNITY_WEBGL && !UNITY_EDITOR OpenVideoPopup(hlsStreamUrl); #else // 在编辑器或非WebGL平台下的模拟行为,例如打开一个调试日志 Debug.Log($"模拟播放: {hlsStreamUrl}"); // 你也可以在这里集成一个本地播放器用于测试 #endif } // 一个公开的方法,用于关闭弹窗(例如由Unity中的关闭按钮调用) public void ClosePopup() { #if UNITY_WEBGL && !UNITY_EDITOR CloseVideoPopup(); #else Debug.Log("模拟关闭视频弹窗"); #endif } }将这个脚本挂载到Unity场景中的一个GameObject上,比如一个空物体叫VideoManager。然后,你可以在UI按钮的OnClick()事件上,拖拽这个GameObject,并选择VideoPopupController.PlayStreamInPopup方法。
4.3 构建、部署与测试
- Unity构建:在Unity编辑器中,打开
File -> Build Settings,选择WebGL平台,然后点击Build。选择一个输出目录(例如WebGLBuild)。 - 部署到服务器:将构建生成的整个文件夹(包含
index.html,.js,.data等文件)上传到你的Web服务器。按照前面Nginx配置的例子,可以放到/var/www/unity_webgl目录下。 - 修改HTML:上传后,务必用文本编辑器打开服务器上的
index.html文件,将我们之前写的弹窗HTML/JS代码添加进去。Unity构建生成的index.html是一个模板,每次构建都会被覆盖,所以需要在构建后手动添加或编写脚本自动注入。 - 测试:在浏览器中访问你的Unity WebGL应用(如
http://你的服务器IP/)。点击触发播放的按钮,应该能看到一个全屏遮罩弹窗出现,并且视频开始加载播放。
5. 性能优化、问题排查与进阶技巧
实现基本功能只是第一步,要让它在生产环境中稳定可靠,还需要考虑很多细节。
5.1 性能与兼容性优化
- 视频参数优化:
- 分辨率与码率:如果原始RTSP流码率过高(如4K),在网页上播放可能卡顿。可以在FFmpeg命令中通过
-vf scale缩放分辨率,或通过-b:v限制视频码率。例如:-vf "scale=1280:720" -b:v 1500k。 - 关键帧间隔:确保摄像头的关键帧(I帧)间隔不要太大(如2-4秒),这会影响HLS切片的效率和播放器 seeking 的速度。
- 分辨率与码率:如果原始RTSP流码率过高(如4K),在网页上播放可能卡顿。可以在FFmpeg命令中通过
- hls.js 配置调优:
enableWorker: true务必开启,利用Web Worker进行解析,避免阻塞主线程。maxBufferLength,maxMaxBufferLength,backBufferLength这几个参数控制缓冲区大小,根据网络状况和视频码率调整,可以平衡内存占用和播放流畅度。
- CDN与缓存:对于大量用户访问的场景,可以考虑将生成的
.ts和.m3u8文件推送到CDN,并合理配置HTTP缓存头。对于直播流(delete_segments开启),m3u8文件应设置为no-cache或max-age=0,而.ts分片可以在播放完成后缓存一小段时间。
5.2 常见问题排查实录
在实际部署中,你几乎一定会遇到下面这些问题。这里是我的排查笔记:
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 黑屏,控制台报跨域错误 (CORS) | Nginx未正确配置CORS头。 | 1. 检查浏览器开发者工具(F12)的Console和Network标签。确认请求HLS流时返回的头信息是否包含Access-Control-Allow-Origin: *。2. 确保Nginx配置中 add_header Access-Control-Allow-Origin *;在正确的location块内,并且没有被其他配置覆盖。3. 对于复杂请求(如带Range头的),需要处理OPTIONS预检请求,参考前面Nginx配置中的 if ($request_method = 'OPTIONS')部分。 |
| 视频能加载但一直缓冲/卡顿 | 1. 服务器带宽不足或网络延迟高。 2. FFmpeg转码性能瓶颈。 3. HLS分片时间 ( -hls_time) 设置不当。4. 客户端网络差。 | 1. 在服务器上用top或htop查看FFmpeg进程的CPU占用。如果持续很高,考虑使用-c:v copy或升级服务器。2. 在客户端用浏览器开发者工具Network标签看 .ts文件的下载速度和时间。如果下载很慢,可能是服务器带宽或网络路由问题。3. 尝试增大 -hls_time(如4或6),减少文件请求频率。4. 检查摄像头本身的RTSP流是否稳定,可以用VLC直接拉取RTSP流测试。 |
控制台报Hls.ErrorTypes.NETWORK_ERROR | 网络连接中断,或HLS流URL无法访问。 | 1. 直接在浏览器地址栏输入m3u8文件的完整URL,看是否能下载到一个文本文件(m3u8列表)。2. 检查FFmpeg服务是否在运行 ( sudo systemctl status rtsp-to-hls.service)。3. 查看FFmpeg日志 ( sudo journalctl -u rtsp-to-hls.service -f),看是否有拉流失败的错误(如认证失败、连接超时)。4. 确认RTSP地址、端口、用户名密码是否正确,摄像头是否允许同时多路取流。 |
| 视频有画面但没声音 | 1. RTSP流本身无音频。 2. FFmpeg音频转码失败或未处理。 | 1. 在FFmpeg命令中增加-report参数生成日志,查看音频流信息。2. 如果确认流里没音频,在FFmpeg命令中加 -an参数禁用音频,避免不必要的处理。3. 如果音频编码不被支持,尝试指定音频编码器,如 -c:a aac -strict experimental。 |
| 弹窗不显示或显示异常 | 1. JavaScript代码未正确注入到index.html。2. CSS样式冲突或被覆盖。 3. Unity调用函数名不对。 | 1. 检查浏览器开发者工具Console是否有JavaScript错误。 2. 确认 index.html中弹窗的HTML结构和JS函数是否存在且语法正确。3. 在浏览器中手动调用 window.unityNamespace.openVideoPopup('测试URL')看弹窗是否正常。 |
| 内存占用越来越高 | 1. hls.js 缓冲区未释放。 2. FFmpeg未删除旧TS文件。 | 1. 确保在closeVideoPopup函数中正确调用了hls.destroy()。2. 确保FFmpeg命令中包含了 -hls_flags delete_segments。检查服务器磁盘空间。 |
5.3 进阶技巧与扩展思路
- 多摄像头支持:只需为每个摄像头创建独立的FFmpeg转码服务(不同的systemd service文件,输出到不同的m3u8文件),然后在Unity中根据摄像头ID动态拼接HLS URL并调用
openVideoPopup即可。 - 安全加固:
- RTSP认证:避免在命令行中明文写密码。可以考虑使用
.netrc文件或编写一个简单的脚本从安全存储中读取凭证。 - HLS流鉴权:给HLS流URL加上时间戳Token或签名,防止被非法盗用。这需要在Nginx配置中使用
secure_link等模块,并在Unity中动态生成带Token的URL。
- RTSP认证:避免在命令行中明文写密码。可以考虑使用
- 降低延迟:如果HLS的2-3秒延迟不可接受,可以研究LL-HLS (Low Latency HLS)或切换到WebRTC方案。LL-HLS需要服务器端(如FFmpeg使用
-hls_flags split_by_time+omit_endlist+append_list等参数)和客户端(hls.js需支持)共同配合。WebRTC方案则需要部署如Janus Gateway或Mediasoup这样的SFU/MCU服务器,实现RTSP to WebRTC的转换,复杂度更高,但延迟可降至500毫秒以内。 - 状态同步:如果你需要在Unity的3D场景中反映视频播放状态(如播放/暂停),可以通过JavaScript回调到Unity。在C#中定义回调方法,并用
[DllImport("__Internal")]暴露给JS,然后在JS的播放器事件(如play,pause)中调用这些Unity方法。
这套从RTSP到Unity WebGL弹窗播放的免费方案,我已经在多个智慧工地、楼宇监控的项目中成功应用。它的优势在于架构清晰、组件成熟、完全免费且可控性强。虽然初始搭建需要理解整个流水线,但一旦跑通,后续的扩展和维护都会非常顺畅。记住,流媒体开发,耐心和细致的日志排查是你最好的朋友。