1. 为什么需要RTSP转HLS流媒体服务RTSPReal Time Streaming Protocol是监控摄像头、视频会议系统常用的流媒体协议但它在网页端兼容性差需要依赖浏览器插件或专用播放器。HLSHTTP Live Streaming则是苹果公司提出的基于HTTP的流媒体传输方案支持自适应码率、跨平台播放尤其适合网页端视频展示。我去年接手过一个园区监控项目客户要求在手机和电脑上都能实时查看200多路摄像头画面。最初尝试直接用RTSP协议结果iOS设备全军覆没Chrome浏览器也频频报错。后来改用NginxFFmpeg方案将RTSP转为HLS三天就解决了所有终端的播放问题。核心痛点对比RTSP的短板需要特定端口默认554防火墙穿透困难原生不支持HTML5播放HLS的优势使用HTTP 80/443端口支持TS分片和自适应码率所有现代浏览器原生兼容2. 环境准备与依赖安装2.1 基础组件安装在Ubuntu 20.04上实测可用的安装命令# 安装FFmpeg包含编码器 sudo apt-get install -y ffmpeg libavcodec-extra # 安装Nginx需包含RTMP模块 sudo apt-get install -y nginx libnginx-mod-rtmp # 安装管理工具 sudo apt-get install -y jq screen如果遇到编码器缺失问题推荐编译安装FFmpeg# 编译安装FFmpeg支持H.265 git clone https://git.ffmpeg.org/ffmpeg.git cd ffmpeg ./configure --enable-gpl --enable-libx264 --enable-libx265 make -j$(nproc) sudo make install2.2 目录结构规划建议采用以下目录结构方便后期维护/var/streaming/ ├── config/ │ └── cameras.json # 摄像头配置 ├── live/ # 实时流TS片段 ├── archive/ # 录像存储 └── logs/ # 运行日志设置权限确保Nginx可读写sudo chown -R www-data:www-data /var/streaming sudo chmod -R 775 /var/streaming3. Nginx流媒体服务配置3.1 核心配置详解编辑/etc/nginx/nginx.conf在http块外添加RTMP配置rtmp { server { listen 1935; ping 30s; notify_method get; application live { live on; meta copy; # 保留原始元数据 # HLS输出配置 hls on; hls_path /var/streaming/live; hls_fragment 2s; # 每个TS切片时长 hls_playlist_length 10s; # HLS列表保留时长 hls_cleanup on; # 自动清理旧片段 } } }在http块内添加HLS访问支持server { listen 80; location /hls { types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } alias /var/streaming/live; add_header Cache-Control no-cache; # 禁用缓存确保实时性 } location /stat { rtmp_stat all; rtmp_stat_stylesheet stat.xsl; } }3.2 性能优化参数在nginx.conf的events块添加worker_processes auto; # 自动匹配CPU核心数 worker_rlimit_nofile 100000; # 提高文件描述符限制 events { worker_connections 4096; multi_accept on; use epoll; # Linux内核下高性能模式 }重启服务生效配置sudo systemctl restart nginx4. FFmpeg转码实战4.1 单路摄像头转码基础转码命令示例ffmpeg -rtsp_transport tcp -i rtsp://admin:password192.168.1.100:554/Streaming/Channels/101 \ -c:v copy -c:a aac -ar 44100 \ -f flv rtmp://localhost:1935/live/camera1关键参数解析-rtsp_transport tcp强制TCP传输避免UDP丢包-c:v copy视频流直接复制不重新编码-c:a aac音频转AAC编码浏览器兼容必须-f flv输出为FLV格式喂给Nginx4.2 多路摄像头管理使用JSON配置文件管理摄像头/var/streaming/config/cameras.json{ cameras: [ { id: entrance, name: 园区主入口, rtsp: rtsp://admin:123456192.168.1.101/Streaming/Channels/101, width: 1280, height: 720 }, { id: parking, name: 地下停车场, rtsp: rtsp://admin:123456192.168.1.102/Streaming/Channels/101, width: 1920, height: 1080 } ] }编写自动启动脚本#!/bin/bash CONFIG/var/streaming/config/cameras.json jq -c .cameras[] $CONFIG | while read camera; do id$(echo $camera | jq -r .id) rtsp$(echo $camera | jq -r .rtsp) ffmpeg -rtsp_transport tcp -i $rtsp \ -c:v copy -c:a aac -ar 44100 \ -f flv rtmp://localhost:1935/live/$id /var/streaming/logs/$id.log 21 done5. 前端播放器实现5.1 使用HLS.js播放HTML示例需引入hls.js库video idvideo controls/video script srchttps://cdn.jsdelivr.net/npm/hls.jslatest/script script const video document.getElementById(video); const url /hls/camera1.m3u8; // 对应Nginx配置的HLS路径 if (Hls.isSupported()) { const hls new Hls(); hls.loadSource(url); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, () video.play()); } else if (video.canPlayType(application/vnd.apple.mpegurl)) { video.src url; // Safari原生支持 video.addEventListener(loadedmetadata, () video.play()); } /script5.2 多画面监控界面基于Vue.js的多画面示例div classgrid div v-forcamera in cameras :keycamera.id h3{{ camera.name }}/h3 video :idplayer-camera.id controls muted/video /div /div script new Vue({ data() { return { cameras: [ {id: entrance, name: 主入口}, {id: parking, name: 停车场} ] } }, mounted() { this.cameras.forEach(cam { const url /hls/${cam.id}.m3u8; const video document.getElementById(player-${cam.id}); if (Hls.isSupported()) { const hls new Hls(); hls.loadSource(url); hls.attachMedia(video); } else { video.src url; } }); } }); /script6. 生产环境优化方案6.1 系统服务化管理创建systemd服务文件/etc/systemd/system/stream.service[Unit] DescriptionRTSP to HLS Streaming Service Afternetwork.target [Service] Userwww-data ExecStart/usr/bin/bash /path/to/start_stream.sh Restartalways RestartSec10 [Install] WantedBymulti-user.target管理命令# 启用服务 sudo systemctl enable stream sudo systemctl start stream # 查看状态 sudo systemctl status stream -l6.2 负载均衡方案当单台服务器无法承载时可采用以下架构[摄像头] - [FFmpeg集群] - [Nginx边缘节点] - [CDN] - [用户]使用Docker Swarm或Kubernetes实现FFmpeg容器动态扩展# docker-compose.yml示例 version: 3 services: transcoder: image: jrottenberg/ffmpeg deploy: replicas: 3 command: [ -rtsp_transport, tcp, -i, rtsp://camera-{1..3}, -c:v, copy, -f, flv, rtmp://nginx/live/camera-${HOSTNAME} ]7. 常见问题排查7.1 播放卡顿优化问题现象HLS播放有5-10秒延迟解决方案调整HLS切片参数hls_fragment 1s; # 缩短切片时长 hls_playlist_length 3s; # 减少播放列表长度启用低延迟模式ffmpeg -fflags nobuffer -flags low_delay ...7.2 时间戳同步问题问题现象音视频不同步或播放器报错修复方案ffmpeg -use_wallclock_as_timestamps 1 -i rtsp://... # 使用系统时钟7.3 内存泄漏处理定期重启FFmpeg进程的监控脚本#!/bin/bash # 每6小时重启一次FFmpeg while true; do sleep 21600 pkill -f ffmpeg.*rtsp # 启动脚本会自动重新拉起 done
基于Nginx+FFmpeg的RTSP转HLS流媒体服务搭建与优化实践
1. 为什么需要RTSP转HLS流媒体服务RTSPReal Time Streaming Protocol是监控摄像头、视频会议系统常用的流媒体协议但它在网页端兼容性差需要依赖浏览器插件或专用播放器。HLSHTTP Live Streaming则是苹果公司提出的基于HTTP的流媒体传输方案支持自适应码率、跨平台播放尤其适合网页端视频展示。我去年接手过一个园区监控项目客户要求在手机和电脑上都能实时查看200多路摄像头画面。最初尝试直接用RTSP协议结果iOS设备全军覆没Chrome浏览器也频频报错。后来改用NginxFFmpeg方案将RTSP转为HLS三天就解决了所有终端的播放问题。核心痛点对比RTSP的短板需要特定端口默认554防火墙穿透困难原生不支持HTML5播放HLS的优势使用HTTP 80/443端口支持TS分片和自适应码率所有现代浏览器原生兼容2. 环境准备与依赖安装2.1 基础组件安装在Ubuntu 20.04上实测可用的安装命令# 安装FFmpeg包含编码器 sudo apt-get install -y ffmpeg libavcodec-extra # 安装Nginx需包含RTMP模块 sudo apt-get install -y nginx libnginx-mod-rtmp # 安装管理工具 sudo apt-get install -y jq screen如果遇到编码器缺失问题推荐编译安装FFmpeg# 编译安装FFmpeg支持H.265 git clone https://git.ffmpeg.org/ffmpeg.git cd ffmpeg ./configure --enable-gpl --enable-libx264 --enable-libx265 make -j$(nproc) sudo make install2.2 目录结构规划建议采用以下目录结构方便后期维护/var/streaming/ ├── config/ │ └── cameras.json # 摄像头配置 ├── live/ # 实时流TS片段 ├── archive/ # 录像存储 └── logs/ # 运行日志设置权限确保Nginx可读写sudo chown -R www-data:www-data /var/streaming sudo chmod -R 775 /var/streaming3. Nginx流媒体服务配置3.1 核心配置详解编辑/etc/nginx/nginx.conf在http块外添加RTMP配置rtmp { server { listen 1935; ping 30s; notify_method get; application live { live on; meta copy; # 保留原始元数据 # HLS输出配置 hls on; hls_path /var/streaming/live; hls_fragment 2s; # 每个TS切片时长 hls_playlist_length 10s; # HLS列表保留时长 hls_cleanup on; # 自动清理旧片段 } } }在http块内添加HLS访问支持server { listen 80; location /hls { types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } alias /var/streaming/live; add_header Cache-Control no-cache; # 禁用缓存确保实时性 } location /stat { rtmp_stat all; rtmp_stat_stylesheet stat.xsl; } }3.2 性能优化参数在nginx.conf的events块添加worker_processes auto; # 自动匹配CPU核心数 worker_rlimit_nofile 100000; # 提高文件描述符限制 events { worker_connections 4096; multi_accept on; use epoll; # Linux内核下高性能模式 }重启服务生效配置sudo systemctl restart nginx4. FFmpeg转码实战4.1 单路摄像头转码基础转码命令示例ffmpeg -rtsp_transport tcp -i rtsp://admin:password192.168.1.100:554/Streaming/Channels/101 \ -c:v copy -c:a aac -ar 44100 \ -f flv rtmp://localhost:1935/live/camera1关键参数解析-rtsp_transport tcp强制TCP传输避免UDP丢包-c:v copy视频流直接复制不重新编码-c:a aac音频转AAC编码浏览器兼容必须-f flv输出为FLV格式喂给Nginx4.2 多路摄像头管理使用JSON配置文件管理摄像头/var/streaming/config/cameras.json{ cameras: [ { id: entrance, name: 园区主入口, rtsp: rtsp://admin:123456192.168.1.101/Streaming/Channels/101, width: 1280, height: 720 }, { id: parking, name: 地下停车场, rtsp: rtsp://admin:123456192.168.1.102/Streaming/Channels/101, width: 1920, height: 1080 } ] }编写自动启动脚本#!/bin/bash CONFIG/var/streaming/config/cameras.json jq -c .cameras[] $CONFIG | while read camera; do id$(echo $camera | jq -r .id) rtsp$(echo $camera | jq -r .rtsp) ffmpeg -rtsp_transport tcp -i $rtsp \ -c:v copy -c:a aac -ar 44100 \ -f flv rtmp://localhost:1935/live/$id /var/streaming/logs/$id.log 21 done5. 前端播放器实现5.1 使用HLS.js播放HTML示例需引入hls.js库video idvideo controls/video script srchttps://cdn.jsdelivr.net/npm/hls.jslatest/script script const video document.getElementById(video); const url /hls/camera1.m3u8; // 对应Nginx配置的HLS路径 if (Hls.isSupported()) { const hls new Hls(); hls.loadSource(url); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, () video.play()); } else if (video.canPlayType(application/vnd.apple.mpegurl)) { video.src url; // Safari原生支持 video.addEventListener(loadedmetadata, () video.play()); } /script5.2 多画面监控界面基于Vue.js的多画面示例div classgrid div v-forcamera in cameras :keycamera.id h3{{ camera.name }}/h3 video :idplayer-camera.id controls muted/video /div /div script new Vue({ data() { return { cameras: [ {id: entrance, name: 主入口}, {id: parking, name: 停车场} ] } }, mounted() { this.cameras.forEach(cam { const url /hls/${cam.id}.m3u8; const video document.getElementById(player-${cam.id}); if (Hls.isSupported()) { const hls new Hls(); hls.loadSource(url); hls.attachMedia(video); } else { video.src url; } }); } }); /script6. 生产环境优化方案6.1 系统服务化管理创建systemd服务文件/etc/systemd/system/stream.service[Unit] DescriptionRTSP to HLS Streaming Service Afternetwork.target [Service] Userwww-data ExecStart/usr/bin/bash /path/to/start_stream.sh Restartalways RestartSec10 [Install] WantedBymulti-user.target管理命令# 启用服务 sudo systemctl enable stream sudo systemctl start stream # 查看状态 sudo systemctl status stream -l6.2 负载均衡方案当单台服务器无法承载时可采用以下架构[摄像头] - [FFmpeg集群] - [Nginx边缘节点] - [CDN] - [用户]使用Docker Swarm或Kubernetes实现FFmpeg容器动态扩展# docker-compose.yml示例 version: 3 services: transcoder: image: jrottenberg/ffmpeg deploy: replicas: 3 command: [ -rtsp_transport, tcp, -i, rtsp://camera-{1..3}, -c:v, copy, -f, flv, rtmp://nginx/live/camera-${HOSTNAME} ]7. 常见问题排查7.1 播放卡顿优化问题现象HLS播放有5-10秒延迟解决方案调整HLS切片参数hls_fragment 1s; # 缩短切片时长 hls_playlist_length 3s; # 减少播放列表长度启用低延迟模式ffmpeg -fflags nobuffer -flags low_delay ...7.2 时间戳同步问题问题现象音视频不同步或播放器报错修复方案ffmpeg -use_wallclock_as_timestamps 1 -i rtsp://... # 使用系统时钟7.3 内存泄漏处理定期重启FFmpeg进程的监控脚本#!/bin/bash # 每6小时重启一次FFmpeg while true; do sleep 21600 pkill -f ffmpeg.*rtsp # 启动脚本会自动重新拉起 done