Lazy loaded image
后端
实战教程:从RTSP到HLS,实现监控摄像头Web实时预览 (FFmpeg + Nginx + Vue3)
字数 6059阅读时长 16 分钟
2024-4-26
2025-5-9
type
status
date
slug
summary
tags
category
icon
password

写在前面:一个前端的监控画面实现之旅

最近在参与一个比赛项目,其中一个核心需求是实现监控摄像头的实时画面预览。按理说,作为一名前端开发者,这块业务通常不归我负责。但项目时间紧、任务重,只好硬着头皮顶上。
刚接触这项任务时,我几乎毫无头绪。项目使用的是海康威视的摄像头,我开始四处查阅文档,却屡屡碰壁。由于对摄像头和流媒体技术完全不了解,我足足花了三天时间,才勉强搭建出一个可运行的Demo
一个惨痛的教训: 如果你的摄像头配置友好,能够直接通过厂商提供的SDK或Demo连接上,那将为你省下大量宝贵的排错时间。因此,在动手之前,务必仔细研究你的摄像头配置,了解它支持哪些协议和功能! 这点非常重要,因为时间真的太宝贵了。

一、核心概念:流媒体传输协议与方案概览

在深入实战之前,我们需要了解一些常见的流媒体传输协议:RTSP、RTMP、HLS、HTTP-FLV
初次接触这些协议时,我同样是一头雾水,它们都是什么?各自有什么用途?
notion image
经过一番学习,我梳理了本项目的实现方案: 我们使用的摄像头支持通过 RTSP (Real Time Streaming Protocol) 协议获取视频流。因此,我们的方案是在服务器上使用 FFmpeg 工具从摄像头的RTSP地址拉取视频流,然后将此流推送到 Nginx 服务器。Nginx再通过其模块(或配合FFmpeg的输出)将视频流处理成对前端Web播放更友好的 HLS (HTTP Live Streaming) 格式(即一系列.m3u8索引文件和.ts视频片段),最后前端通过HTTP(S)拉取HLS流进行播放。
整体流程示意图:
notion image
关于“推流”与“拉流”的通俗理解:
可能你会问,什么是推流?什么是拉流?听起来很专业,但似乎又有点抽象。
notion image
说实话,经过三天的摸索,我对这两个概念的理解可能仍不够“教科书”。但我是这么理解的:
  • 推流 (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 playerPotPlayer。它们都支持播放网络串流,包括RTSP、RTMP、HLS等。
  • VLC media player:轻量且跨平台。 操作:打开软件 -> 「媒体(M)」 -> 「打开网络串流(N)...」 -> 输入RTSP地址。
    • notion image
  • PotPlayer:功能强大的Windows平台播放器。 操作:右键点击播放器界面 -> 「打开」 -> 「打开链接...」 -> 输入RTSP地址。
    • notion image
使用这些工具确保你的摄像头RTSP流能正常播放,是后续工作顺利进行的前提。

接下来,就是我们方案中的两大核心组件:FFmpegNginx。 坦白说,我对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流(
索引文件和
视频片段)的访问。
notion image
重要提示: 如果你的方案涉及到Nginx接收RTMP推流再转HLS或FLV,那么需要确保Nginx编译安装了相应的模块,如 nginx-rtmp-modulenginx-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_stream

2. RTSP流画面测试

使用VLC或PotPlayer播放上述获取到的RTSP地址,确保能正常预览到摄像头画面。
notion image

3. 安装FFmpeg

方式一:宝塔面板安装 (推荐新手)

如果你的服务器安装了宝塔面板,可以在“软件商店”中搜索“FFmpeg”,一键安装即可。
notion image

方式二:手动编译安装 (Linux)

  1. 下载FFmpeg源码包: 访问 FFmpeg官网下载页面 (https://ffmpeg.org/download.html),选择一个源码包 (Source Code) 下载。 将下载的压缩包上传到服务器。
    1. notion image
      notion image
      notion image
  1. 安装依赖:NASM FFmpeg编译可能依赖NASM汇编器。访问 NASM官网 (https://www.nasm.us/) 下载源码。 上传到服务器并解压编译安装:
    1. notion image
      notion image
      notion image
  1. 编译安装FFmpeg 解压FFmpeg源码包,进入目录,配置、编译、安装:
    1. 配置软链接 (可选,方便全局调用) 为FFmpeg和NASM(如果手动安装)的可执行文件创建软链接到系统路径(如/usr/local/bin/usr/local/sbin)。
      1. notion image
        notion image
        notion image
    1. 验证FFmpeg安装 执行 ffmpeg -version,如果能看到版本信息,则安装成功。
      1. notion image

    4. 安装Nginx (及可选的流媒体模块)

    如前所述,如果FFmpeg直接生成HLS文件,Nginx主要作为HTTP服务器。但如果也想支持RTMP推流到Nginx再转HLS/FLV,则需要安装相应模块。

    情况一:服务器未安装Nginx

    1. 安装依赖 (CentOS 7 示例):
      1. 下载Nginx源码 访问 Nginx官网 (http://nginx.org/en/download.html) 下载稳定版源码。 上传到服务器并解压,例如解压到 /usr/local/src/nginx-1.24.0
        1. notion image
          notion image
      1. (可选) 下载Nginx流媒体模块源码 如果需要Nginx处理RTMP流或输出HTTP-FLV/HLS流,需要下载模块源码:
        1. notion image
      1. 配置、编译、安装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
        1. notion image
          编译安装:
          notion image
      1. 防火墙配置 确保Nginx监听的端口(默认为80,如果配置了RTMP则为1935,HLS服务HTTP端口通常为80或自定义,如8888)已在防火墙中放行。
        1. 启动Nginx/usr/local/nginx/sbin/nginx 访问服务器IP,应能看到Nginx欢迎页。
          1. notion image

        情况二:服务器已安装Nginx (需要添加模块)

        如果已安装Nginx但缺少流媒体模块,需要重新编译Nginx,步骤与上述类似,但在./configure时加上--add-module参数,并确保其他编译参数与原Nginx一致(可以通过 nginx -V 查看)。然后只执行make(不要make install),备份旧的nginx可执行文件,并将新编译的objs/nginx替换过去。

        5. Nginx配置文件 (nginx.conf)

        编辑Nginx的配置文件 (通常在
        或宝塔面板指定的路径)。
        notion image
        以下是一个结合了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 /hlsrootalias相对应。
        FFmpeg运行后,会在
        目录下生成
        文件和一系列
        视频片段文件。
        notion image

        7. 测试HLS流播放

        在FFmpeg运行且Nginx配置正确并启动后,可以使用VLC或其他支持HLS的播放器访问: http://<你的Nginx服务器IP>:8888/hls/test.m3u8
        如果一切正常,应该能看到监控画面。
        notion image
        如果播放失败,请检查:
        • Nginx是否启动,8888端口是否监听并在防火墙中放行。
        • FFmpeg命令是否正确运行,并且在 /www/tmp/hls/ 目录下生成了.m3u8.ts文件。
        • Nginx的location /hls配置中rootalias指令是否正确指向FFmpeg输出HLS文件的目录。
        • 浏览器开发者工具的网络请求,看.m3u8.ts文件是否能正常加载,状态码是什么。
        notion image

        8. 前端Vue3中使用Video.js播放HLS流

        在Vue3项目中使用video.js库来播放HLS流。
        安装video.js
        Vue组件示例:
        运行结果预览:
        notion image

        三、总结与思考

        经过几天的试验与探索,我成功实现了从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配置点播服务,或者使用专门的录像存储系统。
        notion image

        性能考量 (实际环境中)

        作者提到其测试机器配置较低,单个FFmpeg进程已造成较高负载。
        notion image
        notion image
        优化方向可能包括:
        • 硬件升级:更强的CPU、GPU(如果FFmpeg使用硬件加速转码)、更快的磁盘I/O。
        • FFmpeg参数调优
          • 使用硬件加速(如 hwaccel qsvhwaccel cuda,需硬件和编译支持)。
          • 调整视频编码参数(码率、分辨率、帧率、GOP大小等)以平衡质量和性能。
          • 如果视频源已经是H.264,使用 c:v copy 避免重复编码。
        • 分布式处理:对于大量摄像头,可以考虑多台FFmpeg服务器进行分布式转码。
        • 选择其他低延迟方案:如HTTP-FLV或WebRTC,但它们在兼容性和部署复杂度上各有特点。

        让FFmpeg后台24小时稳定运行

        1. 后台运行FFmpeg命令: 使用nohup&让FFmpeg命令在后台运行,并将标准输出和错误输出重定向,避免因终端关闭而中断。
            • nostdin: 防止FFmpeg从标准输入读取,避免在后台意外挂起。
            • > /var/log/ffmpeg_hls.log 2>&1: 将标准输出和标准错误都重定向到日志文件。
            • &: 后台运行。
        1. 进程守护与自动重启脚本: 为了防止FFmpeg进程意外挂掉,可以编写一个Shell脚本,通过定时任务(如cron或宝塔面板的计划任务)定期检查FFmpeg进程是否存在,如果不存在则尝试重启。确保此脚本也有执行权限。然后可以通过crontab -e或宝塔面板的计划任务(如下图所示)设置定时执行此检查脚本(例如每5分钟执行一次)。
          1. 重启脚本 (/root/restart_ffmpeg_hls.sh):
            确保此脚本有执行权限 (chmod +x /root/restart_ffmpeg_hls.sh)。
            检查脚本 (/root/check_ffmpeg_hls.sh):
            notion image
            更健壮的进程守护可以使用systemd服务、supervisor等工具。
         
        上一篇
        Vue3实战:轻松实现PDF预览与打印功能 (后台管理必备)
        下一篇
        uniapp 安卓、iOS权限判定uni-app 跨平台应用权限管理SDK (iOS/Android) 深度解析与实战