type
status
date
slug
summary
tags
category
icon
password
写在前面:一个前端的监控画面实现之旅
最近在参与一个比赛项目,其中一个核心需求是实现监控摄像头的实时画面预览。按理说,作为一名前端开发者,这块业务通常不归我负责。但项目时间紧、任务重,只好硬着头皮顶上。
刚接触这项任务时,我几乎毫无头绪。项目使用的是海康威视的摄像头,我开始四处查阅文档,却屡屡碰壁。由于对摄像头和流媒体技术完全不了解,我足足花了三天时间,才勉强搭建出一个可运行的Demo。
一个惨痛的教训: 如果你的摄像头配置友好,能够直接通过厂商提供的SDK或Demo连接上,那将为你省下大量宝贵的排错时间。因此,在动手之前,务必仔细研究你的摄像头配置,了解它支持哪些协议和功能! 这点非常重要,因为时间真的太宝贵了。
一、核心概念:流媒体传输协议与方案概览
在深入实战之前,我们需要了解一些常见的流媒体传输协议:RTSP、RTMP、HLS、HTTP-FLV。
初次接触这些协议时,我同样是一头雾水,它们都是什么?各自有什么用途?
经过一番学习,我梳理了本项目的实现方案:
我们使用的摄像头支持通过 RTSP (Real Time Streaming Protocol) 协议获取视频流。因此,我们的方案是在服务器上使用 FFmpeg 工具从摄像头的RTSP地址拉取视频流,然后将此流推送到 Nginx 服务器。Nginx再通过其模块(或配合FFmpeg的输出)将视频流处理成对前端Web播放更友好的 HLS (HTTP Live Streaming) 格式(即一系列
.m3u8索引文件和.ts视频片段),最后前端通过HTTP(S)拉取HLS流进行播放。整体流程示意图:
关于“推流”与“拉流”的通俗理解:
可能你会问,什么是推流?什么是拉流?听起来很专业,但似乎又有点抽象。
说实话,经过三天的摸索,我对这两个概念的理解可能仍不够“教科书”。但我是这么理解的:
- 推流 (Push):好比网络主播将自己的直播画面数据主动发送(推送)到流媒体服务器上。在我们的场景中,可以理解为FFmpeg将从摄像头获取的视频流数据“推送”给Nginx(或直接转换为HLS文件供Nginx分发)。
- 拉流 (Pull):好比我们观众点开主播的直播间,从流媒体服务器上请求(拉取)直播画面数据进行观看。在我们的场景中,前端播放器从Nginx服务器上“拉取”HLS流数据。
1. RTSP协议简介
RTSP (Real-Time Streaming Protocol) 是一种应用层网络控制协议,设计用于控制、启动、停止和管理实时流媒体数据的传输。它本身不传输媒体数据,而是作为流媒体服务器的“遥控器”,与媒体传输协议(如RTP/RTCP)配合工作。许多监控摄像头都支持通过RTSP地址对外提供视频流。
更详细的RTSP介绍可以参考这篇文章:(https://zhuanlan.zhihu.com/p/478736595)
2. 调试工具:VLC & PotPlayer
在正式搭建服务之前,验证RTSP流的可用性非常重要。我们可以使用一些强大的媒体播放器作为调试工具,如 VLC media player 和 PotPlayer。它们都支持播放网络串流,包括RTSP、RTMP、HLS等。
- VLC media player:轻量且跨平台。 操作:打开软件 -> 「媒体(M)」 -> 「打开网络串流(N)...」 -> 输入RTSP地址。
- PotPlayer:功能强大的Windows平台播放器。 操作:右键点击播放器界面 -> 「打开」 -> 「打开链接...」 -> 输入RTSP地址。
使用这些工具确保你的摄像头RTSP流能正常播放,是后续工作顺利进行的前提。
接下来,就是我们方案中的两大核心组件:FFmpeg 和 Nginx。
坦白说,我对FFmpeg是初次接触,Nginx也仅限于通过宝塔面板进行一键部署的程度。这次实战算是一次深度学习。
3. FFmpeg:强大的多媒体处理工具
FFmpeg 是一个领先的、开源的、跨平台的多媒体处理框架,能够录制、转换、流化音频和视频。它通过命令行方式使用,功能极其强大。
官方下载地址:(https://ffmpeg.org/download.html) 中文文档参考:(https://ffmpeg.org/ffmpeg-all.html) (官方文档是英文,中文文档通常是社区翻译)
如果你的服务器使用宝塔面板,可以直接在软件商店中找到并一键安装FFmpeg,非常方便。
在我们的方案中,FFmpeg扮演着从摄像头RTSP流拉取数据,并将其转换为HLS格式(
.m3u8 和 .ts 文件)的关键角色。4. Nginx:高性能Web服务器与流媒体分发
Nginx 在这里主要作为HTTP服务器,对外提供FFmpeg生成的HLS流(
索引文件和
视频片段)的访问。
重要提示: 如果你的方案涉及到Nginx接收RTMP推流再转HLS或FLV,那么需要确保Nginx编译安装了相应的模块,如
nginx-rtmp-module 或 nginx-http-flv-module。我在此过程中踩了不少坑,比如模块安装不上、配置文件不生效等。
但根据我后续的实践,如果FFmpeg直接将RTSP流转换为HLS文件输出到Nginx的Web可访问目录,Nginx仅作为HTTP服务器分发这些文件,那么Nginx的RTMP或HTTP-FLV模块对于这个核心流程而言并非必需。 当然,这些模块可以提供更灵活的流媒体处理能力,例如接收RTMP推流、生成HTTP-FLV流等。二、实战步骤
1. 获取摄像头的RTSP地址
本项目使用的是海康威视摄像头,其RTSP地址格式通常为:
rtsp://<用户名>:<密码>@<摄像头IP地址>:<RTSP端口号>/<编码格式>/<通道号>/<码流类型>/av_stream
例如:rtsp://admin:password123@192.168.1.100:554/h264/ch1/main/av_stream2. RTSP流画面测试
使用VLC或PotPlayer播放上述获取到的RTSP地址,确保能正常预览到摄像头画面。
3. 安装FFmpeg
方式一:宝塔面板安装 (推荐新手)
如果你的服务器安装了宝塔面板,可以在“软件商店”中搜索“FFmpeg”,一键安装即可。
方式二:手动编译安装 (Linux)
- 下载FFmpeg源码包: 访问 FFmpeg官网下载页面 (https://ffmpeg.org/download.html),选择一个源码包 (Source Code) 下载。 将下载的压缩包上传到服务器。
- 安装依赖:NASM FFmpeg编译可能依赖NASM汇编器。访问 NASM官网 (https://www.nasm.us/) 下载源码。 上传到服务器并解压编译安装:
- 编译安装FFmpeg 解压FFmpeg源码包,进入目录,配置、编译、安装:
- 配置软链接 (可选,方便全局调用)
为FFmpeg和NASM(如果手动安装)的可执行文件创建软链接到系统路径(如
/usr/local/bin或/usr/local/sbin)。
- 验证FFmpeg安装
执行
ffmpeg -version,如果能看到版本信息,则安装成功。
4. 安装Nginx (及可选的流媒体模块)
如前所述,如果FFmpeg直接生成HLS文件,Nginx主要作为HTTP服务器。但如果也想支持RTMP推流到Nginx再转HLS/FLV,则需要安装相应模块。
情况一:服务器未安装Nginx
- 安装依赖 (CentOS 7 示例):
- 下载Nginx源码
访问 Nginx官网 (http://nginx.org/en/download.html) 下载稳定版源码。
上传到服务器并解压,例如解压到
/usr/local/src/nginx-1.24.0。
- (可选) 下载Nginx流媒体模块源码 如果需要Nginx处理RTMP流或输出HTTP-FLV/HLS流,需要下载模块源码:
nginx-rtmp-module: (https://github.com/arut/nginx-rtmp-module.git)nginx-http-flv-module: (https://github.com/winshining/nginx-http-flv-module.git) (此模块也支持HLS)
- 配置、编译、安装Nginx
进入Nginx源码目录 (
cd /usr/local/src/nginx-1.24.0),执行./configure。作者后期实践说明: “压根不需要rtmp模块,要http-flv模块就行了,昨晚复盘的时候发现不装nginx-rtmp-module也能跑通”。如果FFmpeg直接生成HLS文件,Nginx仅作HTTP服务器,则这两个流媒体模块都不是必需的。但nginx-http-flv-module可以增强Nginx对HLS和FLV的支持能力。 同样,可以为Nginx可执行文件创建软链接到系统路径。 检查Nginx配置:/usr/local/nginx/sbin/nginx -t
编译安装:
- 防火墙配置 确保Nginx监听的端口(默认为80,如果配置了RTMP则为1935,HLS服务HTTP端口通常为80或自定义,如8888)已在防火墙中放行。
- 启动Nginx
/usr/local/nginx/sbin/nginx访问服务器IP,应能看到Nginx欢迎页。
情况二:服务器已安装Nginx (需要添加模块)
如果已安装Nginx但缺少流媒体模块,需要重新编译Nginx,步骤与上述类似,但在
./configure时加上--add-module参数,并确保其他编译参数与原Nginx一致(可以通过 nginx -V 查看)。然后只执行make(不要make install),备份旧的nginx可执行文件,并将新编译的objs/nginx替换过去。5. Nginx配置文件 (nginx.conf)
编辑Nginx的配置文件 (通常在
或宝塔面板指定的路径)。
以下是一个结合了HLS HTTP服务和可选RTMP服务的配置示例:
核心解读:
- 在
http块中,我们配置了一个监听8888端口的server,专门用于HLS服务。
location /hls块:types指令定义了.m3u8和.ts文件的MIME类型。root /www/tmp;(或alias /www/tmp/hls;) 至关重要,它指定了Nginx查找HLS文件的根目录。这个目录必须是FFmpeg输出HLS文件的目标目录或其上级目录。add_header Cache-Control no-cache;和expires -1;用于禁止浏览器和代理缓存HLS文件,确保播放器获取最新的流信息。add_header Access-Control-Allow-Origin *;允许跨域播放。
- 关于RTMP块:如果你的FFmpeg命令是直接将RTSP流转换为HLS文件并输出到磁盘(如本文后续的命令),那么Nginx的
rtmp配置块对于这个核心播放流程是可选的。它主要用于Nginx自身作为RTMP服务器(接收推流、转HLS/FLV等)的场景。如果你的方案中Nginx不扮演RTMP服务器角色,可以省略此块。
6. 使用FFmpeg进行拉流转码 (RTSP to HLS)
执行以下FFmpeg命令,将摄像头的RTSP流转换为HLS格式,并输出到Nginx配置的Web可访问目录下。
请确保目标目录 (
/www/tmp/hls/) 已创建并有写入权限。命令参数解释:
re: 以原生帧率读取输入。
rtsp_transport tcp: 强制使用TCP传输RTSP流(更稳定,但可能延迟略高)。
i "rtsp://...": 输入的RTSP流地址。
c:v copy: 视频编码直接拷贝(如果源视频已经是H.264等HLS兼容格式)。如果需要转码,则使用如c:v libx264。
c:a aac -strict experimental: 音频编码转换为AAC(HLS广泛支持)。
f hls: 输出格式为HLS。
hls_time 10: 每个.ts视频片段的期望时长(秒)。
hls_list_size 0:m3u8播放列表中包含的媒体段数量。0表示保留所有片段(适用于录制完整内容,直播时通常设为较小值如3-10)。
hls_segment_filename "/www/tmp/hls/test_%Y%m%d_%H%M%S_%%03d.ts": 定义ts切片的文件名格式,可以包含时间戳和序号。
/www/tmp/hls/test.m3u8: 输出的HLS主索引文件的路径和名称。此路径必须与Nginx配置中location /hls的root或alias相对应。
FFmpeg运行后,会在
目录下生成
文件和一系列
视频片段文件。
7. 测试HLS流播放
在FFmpeg运行且Nginx配置正确并启动后,可以使用VLC或其他支持HLS的播放器访问:
http://<你的Nginx服务器IP>:8888/hls/test.m3u8如果一切正常,应该能看到监控画面。
如果播放失败,请检查:
- Nginx是否启动,8888端口是否监听并在防火墙中放行。
- FFmpeg命令是否正确运行,并且在
/www/tmp/hls/目录下生成了.m3u8和.ts文件。
- Nginx的
location /hls配置中root或alias指令是否正确指向FFmpeg输出HLS文件的目录。
- 浏览器开发者工具的网络请求,看
.m3u8和.ts文件是否能正常加载,状态码是什么。
8. 前端Vue3中使用Video.js播放HLS流
在Vue3项目中使用
video.js库来播放HLS流。安装
video.js:Vue组件示例:
运行结果预览:
三、总结与思考
经过几天的试验与探索,我成功实现了从RTSP摄像头拉流,通过FFmpeg转码为HLS,再由Nginx提供HTTP服务,最终在Vue3前端使用Video.js播放实时画面的方案。
关于浏览器直接播放RTSP流:浏览器本身通常不直接支持播放RTSP流,这是由浏览器厂商的安全和技术栈决定的。因此,将RTSP流转换为Web友好的协议(如HLS、HTTP-FLV、WebRTC)是必要的步骤。转码过程不可避免地会引入延迟。
延迟问题:本Demo中,FFmpeg在本机进行转码,HLS方案本身也会带来一定的延迟(通常是几个切片时长的累积,例如10-30秒)。在实际生产环境中,如果转码服务器和流媒体分发服务器是分开部署的,网络传输可能进一步增加延迟。
回放需求
:如果项目需要历史录像回放功能,那么对存储和点播方案需要额外设计。例如,FFmpeg可以将流录制为MP4或FLV文件,Nginx配置点播服务,或者使用专门的录像存储系统。
性能考量 (实际环境中)
作者提到其测试机器配置较低,单个FFmpeg进程已造成较高负载。
优化方向可能包括:
- 硬件升级:更强的CPU、GPU(如果FFmpeg使用硬件加速转码)、更快的磁盘I/O。
- FFmpeg参数调优:
- 使用硬件加速(如
hwaccel qsv或hwaccel cuda,需硬件和编译支持)。 - 调整视频编码参数(码率、分辨率、帧率、GOP大小等)以平衡质量和性能。
- 如果视频源已经是H.264,使用
c:v copy避免重复编码。
- 分布式处理:对于大量摄像头,可以考虑多台FFmpeg服务器进行分布式转码。
- 选择其他低延迟方案:如HTTP-FLV或WebRTC,但它们在兼容性和部署复杂度上各有特点。
让FFmpeg后台24小时稳定运行
- 后台运行FFmpeg命令:
使用
nohup和&让FFmpeg命令在后台运行,并将标准输出和错误输出重定向,避免因终端关闭而中断。 nostdin: 防止FFmpeg从标准输入读取,避免在后台意外挂起。> /var/log/ffmpeg_hls.log 2>&1: 将标准输出和标准错误都重定向到日志文件。&: 后台运行。
- 进程守护与自动重启脚本:
为了防止FFmpeg进程意外挂掉,可以编写一个Shell脚本,通过定时任务(如
cron或宝塔面板的计划任务)定期检查FFmpeg进程是否存在,如果不存在则尝试重启。确保此脚本也有执行权限。然后可以通过crontab -e或宝塔面板的计划任务(如下图所示)设置定时执行此检查脚本(例如每5分钟执行一次)。
重启脚本 (
/root/restart_ffmpeg_hls.sh):确保此脚本有执行权限 (
chmod +x /root/restart_ffmpeg_hls.sh)。检查脚本 (
/root/check_ffmpeg_hls.sh):更健壮的进程守护可以使用
systemd服务、supervisor等工具。- 作者:90_blog
- 链接:https://blog.tri7e.com/article/other_ffmpeg
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
