RTSP 拉流与录制:IPC 摄像头本地录像完整方案
做 IPC 摄像头、无人售货柜、安防监控,RTSP 拉流和录制是基本功。这篇讲清楚:怎么稳定拉流、怎么存成文件、怎么按时间分片、断线怎么自动重连、延迟怎么优化------全是实际项目里踩过的坑。
大家好,我是黒漂技术佬。
之前写 IPC 摄像头专栏的时候,很多人问 RTSP 拉流的问题:拉流花屏怎么办?怎么 24 小时录像?断网了怎么自动重连?录像文件太大怎么办?
这些问题 FFmpeg 都能解决,但参数没配对的话,不是不稳定就是延迟高。这篇把我做售货柜项目积累的 RTSP 拉流录制经验全部分享出来。
一、RTSP 基础
RTSP(Real Time Streaming Protocol)是网络摄像头最常用的流媒体协议。IPC 摄像头基本上都支持。
常见 RTSP 地址格式
不同品牌地址不一样,常见的:
bash
# 海康威视
rtsp://用户名:密码@IP:554/h264/ch1/main/av_stream
# 大华
rtsp://用户名:密码@IP:554/cam/realmonitor?channel=1&subtype=0
# 华天龙(我项目里用的)
rtsp://用户名:密码@IP:554/stream1
# 通用格式
rtsp://用户名:密码@IP:554/live
先测试流能不能打开
用 ffplay 先试一下,确认地址和账号密码对不对:
bash
ffplay rtsp://admin:123456@192.168.1.100:554/stream1
能弹出画面就说明通了。
二、最简单的拉流录制
直接存成 MP4
bash
ffmpeg -i rtsp://地址 -c copy output.mp4
-c copy 直接复制流,不重新编码,CPU 占用极低。
存成 MKV(推荐 24 小时录制)
bash
ffmpeg -i rtsp://地址 -c copy output.mkv
为什么推荐 MKV?MP4 的元数据在文件末尾,录制中断(断电、断网)文件会损坏。MKV 是流式封装,断了也能播放前面的内容。
💡 做无人值守的 24 小时录像,一律用 MKV 或 TS 格式,别用 MP4------哪天断电了,录了十几个小时的文件直接废了。
三、按时间分片录制
24 小时录像存成一个文件太大,不方便管理和检索,按时间分片:
每小时一个文件
bash
ffmpeg -i rtsp://地址 -c copy -f segment -segment_time 3600 -strftime 1 "record/%Y%m%d_%H%M%S.mkv"
-f segment:分段输出-segment_time 3600:每 3600 秒(1小时)切一个文件-strftime 1:文件名用时间格式%Y%m%d_%H%M%S:年月日_时分秒,比如20260702_143000.mkv
每天一个文件夹 + 每小时一个文件
bash
ffmpeg -i rtsp://地址 -c copy -f segment -segment_time 3600 -strftime 1 "record/%Y%m%d/%H%M%S.mkv"
自动按日期建文件夹,里面是每小时的文件。
重置时间戳
分片的时候加上 -reset_timestamps 1,每个分片的时间戳从 0 开始,播放器拖动进度条更准:
bash
ffmpeg -i rtsp://地址 -c copy -f segment -segment_time 3600 -reset_timestamps 1 -strftime 1 "record/%Y%m%d_%H%M%S.mkv"
四、按大小分片
每 100MB 切一个文件
bash
ffmpeg -i rtsp://地址 -c copy -f segment -segment_size 100M -strftime 1 "record/%Y%m%d_%H%M%S.mkv"
-segment_size 100M 每个文件最大 100MB。
实际项目里一般按时间分片为主,大小作为辅助限制。
五、只录视频 / 只录音频
bash
# 只录视频(不要音频)
ffmpeg -i rtsp://地址 -c:v copy -an output.mkv
# 只录音频(不要视频)
ffmpeg -i rtsp://地址 -vn -c:a copy output.aac
-an 去掉音频,-vn 去掉视频。
有些摄像头音频有杂音或者不需要录音,加上 -an 省空间。
六、拉流参数优化:稳定、低延迟
默认参数拉流可能会卡、花屏、延迟高,调这几个参数。
1. 传输协议:TCP vs UDP
bash
# TCP 传输(推荐)
ffmpeg -rtsp_transport tcp -i rtsp://地址 ...
# UDP 传输(默认)
ffmpeg -rtsp_transport udp -i rtsp://地址 ...
- UDP:速度快、延迟低,但丢包就花屏
- TCP:可靠不丢包,但有延迟,网络差的时候会卡
实际项目建议用 TCP,稳定最重要。售货柜的摄像头我全部用 TCP,偶尔网络波动也不会花屏。
2. 超时设置
bash
ffmpeg -rtsp_transport tcp -stimeout 5000000 -i rtsp://地址 ...
-stimeout 5000000 超时 5 秒(单位微秒),连不上就退出,不会一直卡着。
3. 缓冲区大小
bash
ffmpeg -rtsp_transport tcp -buffer_size 1024000 -i rtsp://地址 ...
网络抖动大的话,加大缓冲区,减少卡顿。
4. 降低延迟
做实时预览、远程开门这种需要低延迟的场景:
bash
ffmpeg -rtsp_transport tcp -fflags nobuffer -flags low_delay -i rtsp://地址 ...
-fflags nobuffer:不缓冲,收到就解码-flags low_delay:低延迟模式
代价是抗抖动能力下降,网络不好容易卡。
5. 跳过损坏帧
流偶尔有坏数据,FFmpeg 可能直接报错退出。加上:
bash
ffmpeg -err_detect ignore_err -i rtsp://地址 ...
遇到错误忽略,继续跑。
七、断线自动重连
FFmpeg 本身不会自动重连,断网了就退出。需要自己写脚本循环。
Windows PowerShell 脚本
powershell
while ($true) {
ffmpeg -rtsp_transport tcp -stimeout 5000000 `
-i "rtsp://admin:123456@192.168.1.100:554/stream1" `
-c copy -f segment -segment_time 3600 -reset_timestamps 1 `
-strftime 1 "record/%Y%m%d_%H%M%S.mkv"
Write-Host "断线了,3秒后重连..."
Start-Sleep 3
}
Linux / macOS Shell 脚本
bash
#!/bin/bash
while true; do
ffmpeg -rtsp_transport tcp -stimeout 5000000 \
-i "rtsp://admin:123456@192.168.1.100:554/stream1" \
-c copy -f segment -segment_time 3600 -reset_timestamps 1 \
-strftime 1 "record/%Y%m%d_%H%M%S.mkv"
echo "断线了,3秒后重连..."
sleep 3
done
重连的几个注意点
- 加延迟:别立刻重连,等个 3-5 秒,不然网络还没恢复又失败
- 加超时 :
-stimeout必须加,不然卡着不动 - 日志记录:生产环境把输出写到日志文件,方便排查问题
- 分段文件名用时间戳:重连后不会覆盖之前的文件
八、边录边转码(降低存储占用)
直接 -c copy 存的是摄像头原始码流,可能码率很高、占空间大。如果存储空间紧张,可以边拉边转码压缩。
H.264 压缩录制
bash
ffmpeg -i rtsp://地址 -vcodec libx264 -crf 28 -acodec aac -b:a 64k -f segment -segment_time 3600 "record/%Y%m%d_%H%M%S.mp4"
代价是 CPU 占用高,需要机器性能够。
硬件加速录制(RK3588 推荐)
售货柜用的 RK3588,硬编码几乎不占 CPU:
bash
ffmpeg -i rtsp://地址 -vcodec h264_rkmpp -b:v 1M -acodec copy -f segment -segment_time 3600 "record/%Y%m%d_%H%M%S.mp4"
硬件加速后面专门一篇细讲。
九、拉流 + 实时抽帧(不存视频)
只需要定时抽帧做 AI 识别,不需要存录像:
bash
ffmpeg -rtsp_transport tcp -i rtsp://地址 -vf fps=1 frames/%04d.jpg
售货柜项目里,待机状态就每秒抽一帧跑 YOLO 检测,有人拿东西的时候才触发完整识别流程。
抽帧 + 推流同时进行
一边存文件,一边抽帧做分析,用 tee 或者 filter_complex 分流。
十、多路摄像头同时录制
多个摄像头,写个脚本循环启动,或者一条命令多个输入:
bash
ffmpeg \
-i rtsp://摄像头1地址 \
-i rtsp://摄像头2地址 \
-map 0 -c copy -f segment -segment_time 3600 "cam1/%Y%m%d_%H%M%S.mkv" \
-map 1 -c copy -f segment -segment_time 3600 "cam2/%Y%m%d_%H%M%S.mkv"
-map 0 选第一个输入,-map 1 选第二个,分别输出。
但更推荐每个摄像头单独起一个 FFmpeg 进程------一路挂了不影响其他路,也好管理。
十一、实际踩过的坑
坑 1:录制的 MP4 文件损坏打不开
原因:MP4 的 moov atom 在文件末尾,异常退出没写进去。
解决:用 MKV 或 TS 格式录制,或者录制完后用 ffmpeg -i input.mp4 -c copy fixed.mp4 修复。
坑 2:花屏、绿屏、马赛克
原因:UDP 丢包,或者关键帧间隔太大。
解决:
- 改用 TCP 传输:
-rtsp_transport tcp - 摄像头设置里把关键帧间隔改小(比如 1 秒一个 I 帧)
坑 3:延迟越来越大
原因:FFmpeg 默认有缓冲,累积延迟。
解决:加 -fflags nobuffer -flags low_delay -framedrop,丢帧保延迟。
坑 4:音视频不同步
原因:摄像头的时间戳有问题,或者网络抖动。
解决:加 -vsync cfr 统一视频帧率,或者 -async 1 校正音频。
坑 5:FFmpeg 进程挂了没人知道
解决:
- 写个守护脚本,进程没了自动拉起来
- 定期检查录像文件有没有更新
- 生产环境配合监控告警
十二、我项目里用的完整命令
售货柜 IPC 摄像头 24 小时录制的完整命令:
bash
ffmpeg -rtsp_transport tcp \
-stimeout 10000000 \
-err_detect ignore_err \
-i "rtsp://admin:密码@192.168.1.200:554/stream1" \
-c copy \
-f segment \
-segment_time 1800 \
-segment_format matroska \
-reset_timestamps 1 \
-strftime 1 \
"/data/record/cabinet01/%Y%m%d/%H%M%S.mkv"
参数说明:
- TCP 传输,10 秒超时
- 忽略错误继续运行
- 每 30 分钟一个文件
- MKV 格式,断电不损坏
- 按日期建文件夹,文件名带时间戳
外面再套一层自动重连的脚本,稳定跑几个月没问题。
十三、本篇小结
- 录制优先用 MKV 格式,异常退出不损坏
-c copy直接复制流,CPU 占用最低-f segment按时间/大小分片,方便管理-rtsp_transport tcp更稳定,UDP 延迟低但易花屏- 断线重连需要自己写脚本循环
- 生产环境:超时 + 错误忽略 + 自动重连 + 日志监控
下一篇讲HLS/DASH 切片:直播和点播的切片生成,怎么把视频转成 m3u8 放到网页上播放。
我是黒漂技术佬。