目录
[一、先建立心智模型:FFmpeg 的 RTSP 到底在干什么?](#一、先建立心智模型:FFmpeg 的 RTSP 到底在干什么?)
[1️. rtsp_transport------ 第一重要参数](#1️. rtsp_transport—— 第一重要参数)
[2️. stimeout------ 连接 & 读超时(单位:微秒)](#2️. stimeout—— 连接 & 读超时(单位:微秒))
[3️. max_delay------ 花屏/卡顿的总开关](#3️. max_delay—— 花屏/卡顿的总开关)
[4️. buffer_size------ UDP 必调,TCP 也建议](#4️. buffer_size—— UDP 必调,TCP 也建议)
[5️. reorder_queue_size------ B 帧/高清流救命参数](#5️. reorder_queue_size—— B 帧/高清流救命参数)
[6️. fflags------ 拉流启动 & 断线行为控制](#6️. fflags—— 拉流启动 & 断线行为控制)
[7️. probesize& analyzeduration------ 起播慢的根因](#7️. probesize& analyzeduration—— 起播慢的根因)
[8️. rtsp_flags------ 高级控制(老设备才用)](#8️. rtsp_flags—— 高级控制(老设备才用))
[9️. 海康 / 大华私有参数](#9️. 海康 / 大华私有参数)
[强制 TCP + 低延迟(海康)](#强制 TCP + 低延迟(海康))
[四、API 层(libavformat)完整设置示例(Qt / C++)](#四、API 层(libavformat)完整设置示例(Qt / C++))
[五、常见症状 → 参数根因速查表](#五、常见症状 → 参数根因速查表)
[局域网监控 / OverlayWidget 预览(低延迟)](#局域网监控 / OverlayWidget 预览(低延迟))
[公网 / 4G / 弱网(稳优先)](#公网 / 4G / 弱网(稳优先))
[七、RTSP 调试 Checklist](#七、RTSP 调试 Checklist)
觉得有用,就请您帮忙点赞转发收藏吧,您的鼓励是我创作的动力,多谢看官。
由于能力水平有限,文中的错误或不严谨的地方在所难免,还请批评指正。
本文不是 ffmpeg -h demuxer=rtsp的翻译堆砌,而是工业级 RTSP 拉流实战手册。你将获得:
RTSP 在 FFmpeg 中的真实工作链路:TCP/UDP → RTP → jitter buffer → A/V Queue
每个关键参数的底层含义(为什么设、不设会怎样、副作用是什么)
海康 / 大华 / ONVIF / 国标 28181 场景的参数模板
花屏、丢包、卡顿、连接超时、TCP 粘包断流的根因对照表
一套可直接拷贝的「RTSP 调试 checklist + 推荐参数组合」
一、先建立心智模型:FFmpeg 的 RTSP 到底在干什么?
很多人以为 RTSP 是"流协议",其实 FFmpeg 里它是 三层嵌套:
rtsp:// (demuxer)
└── RTSP 信令 (DESCRIBE / SETUP / PLAY)
└── RTP/RTCP 传输 (UDP / TCP/interleaved)
└── depacketizer → AVPacket (H.264/H.265/AAC)
90% 的 RTSP 问题,不在解码,而在 SETUP 和 depacketizer。
二、基础调用
ffmpeg -i rtsp://admin:12345@192.168.1.64:554/Streaming/Channels/101 out.mp4
默认行为(危险):
| 行为 | 说明 |
|---|---|
| UDP | 默认优先 UDP,局域网丢包直接花屏 |
max_delay=5000000µs |
5s jitter buffer,卡顿容忍极高 |
stimeout=0 |
阻塞无限等待 |
buffer_size=32768 |
UDP socket 很小,高码率必丢 |
结论:默认参数只适合 demo,不适合上线。
三、核心参数逐条解剖(重点章节)
1️. rtsp_transport------ 第一重要参数
-rtsp_transport tcp
| 值 | 场景 | 代价 |
|---|---|---|
udp |
内网、低延迟、老设备 | 丢包即花屏 |
tcp |
生产环境首选 | 延迟略高,但稳 |
udp_multicast |
广电/专网 | 需要交换机支持 |
http |
RTSP over HTTP(穿透) | 海康老固件才用 |
底层真相:
-
tcp=RTP over RTSP (interleaved mode) -
数据走 RTSP 的
0x24分隔通道,不会被防火墙拦 TCP 554 -
但:摄像头 TCP 发送窗口满 → 累积延迟
推荐:
-rtsp_transport tcp
2️. stimeout------ 连接 & 读超时(单位:微秒)
-stimeout 5000000
很多人误解:
stimeout≠ 单次 read 超时,而是 socket 读超时(poll timeout)
| 设置 | 行为 |
|---|---|
0 |
永久阻塞(Qt 线程直接卡死) |
3000000(3s) |
网络断线 3s 后报 EOF |
<1s |
抖动误判为断线 |
Qt / 后台服务推荐:
-stimeout 4000000
配合:
av_dict_set(&opts, "stimeout", "4000000", 0);
3️. max_delay------ 花屏/卡顿的总开关
-max_delay 1000000
作用位置:AVFormatContext::max_delay→ RTP jitter buffer
| 值 | 效果 |
|---|---|
5000000(默认) |
容忍 5s 抖动,延迟高 |
1000000 |
1s jitter,实时交互 |
200000 |
低延迟监控,丢包换实时 |
| 太小 | depacketizer 报 RTP missed xxx packets |
经验公式:
max_delay ≈ 网络抖动峰值 × 2
局域网监控:500k--1000k
公网 4G:2000k--3000k
4️. buffer_size------ UDP 必调,TCP 也建议
-buffer_size 1048576
UDP socket recv buffer(字节)
| 场景 | 建议 |
|---|---|
| 1080p H.265 主码流 | ≥ 1MB |
| 多路拉流 | sysctl net.core.rmem_max一起改 |
| TCP | 可小一点,但设了没坏处 |
Linux 系统级兜底:
sysctl -w net.core.rmem_max=26214400
5️. reorder_queue_size------ B 帧/高清流救命参数
-reorder_queue_size 16
RTP 包乱序重排队列(单位:packet)
-
H.264/H.265 + B 帧 → RTP 序号乱序很正常
-
默认
5~7,高码率 25fps 以上容易:RTP: missed XX packets
IPC 摄像头推荐:
-reorder_queue_size 16
6️. fflags------ 拉流启动 & 断线行为控制
跳过非关键帧(秒开)
-fflags nobuffer+discardcorrupt+igndts
| flag | 作用 |
|---|---|
nobuffer |
关 avformat buffer,延迟↓ |
discardcorrupt |
坏包直接丢,不塞 decoder |
igndts |
某些国产 IPC DTS 乱飞 |
genpts |
自己补 PTS(救花屏) |
秒开 RTSP 黄金组合:
-fflags nobuffer+discardcorrupt -flags low_delay
7️. probesize& analyzeduration------ 起播慢的根因
-probesize 32k
-analyzeduration 1M
RTSP 本质:FFmpeg 要先 DESCRIBE+ SDP parse+ 猜流数量
| 问题 | 调法 |
|---|---|
| 起播 3~5 秒 | probesize/analyzeduration 砍半 |
报 Could not find codec parameters |
放大 probesize |
| 多音频流 | analyzeduration 加大 |
监控秒开推荐:
-probesize 32768
-analyzeduration 0
analyzeduration=0是"赌",但 RTSP SDP 一般够用
8️. rtsp_flags------ 高级控制(老设备才用)
-rtsp_flags prefer_tcp+listen
| flag | 说明 |
|---|---|
prefer_tcp |
老写法,不如 rtsp_transport tcp |
listen |
FFmpeg 当 RTSP Server(反向拉流) |
filter_src |
多播时只收指定源 |
9️. 海康 / 大华私有参数
海康主子码流
主码流:/Streaming/Channels/101
子码流:/Streaming/Channels/102
强制 TCP + 低延迟(海康)
ffmpeg -rtsp_transport tcp -stimeout 4000000 \
-fflags nobuffer -flags low_delay \
-max_delay 500000 \
-i rtsp://admin:pass@ip:554/Streaming/Channels/102 \
-c copy out.mp4
四、API 层(libavformat)完整设置示例(Qt / C++)
AVDictionary *opts = nullptr;
av_dict_set(&opts, "rtsp_transport", "tcp", 0);
av_dict_set(&opts, "stimeout", "4000000", 0);
av_dict_set(&opts, "buffer_size", "1048576", 0);
av_dict_set(&opts, "max_delay", "1000000", 0);
av_dict_set(&opts, "reorder_queue_size", "16", 0);
av_dict_set(&opts, "probesize", "32768", 0);
av_dict_set(&opts, "analyzeduration", "0", 0);
av_dict_set(&opts, "fflags", "nobuffer", 0);
avformat_open_input(&fmt_ctx, url, nullptr, &opts);
av_dict_free(&opts);
线程安全提醒:
-
avformat_open_input可阻塞 → 放工作线程 -
断线重连用 新 AVFormatContext,不要复用
五、常见症状 → 参数根因速查表
| 现象 | 第一怀疑参数 |
|---|---|
| 起播慢(3s+) | analyzeduration/ probesize |
| 花屏但不断线 | max_delay/ reorder_queue_size/ UDP |
| 卡 2s 再跳帧 | max_delay太大 |
| TCP 拉几秒断 | stimeout/ 摄像头 TCP 流控 |
| Qt UI 卡死 | stimeout=0+ 主线程 |
| 报 RTP missed | buffer_size/ reorder_queue_size |
| 有数据但解码失败 | fflags +genpts |
| 音频没流 | analyzeduration |
六、推荐模板
局域网监控 / OverlayWidget 预览(低延迟)
ffmpeg -rtsp_transport tcp -stimeout 3000000 \
-fflags nobuffer+discardcorrupt \
-flags low_delay \
-max_delay 500000 \
-reorder_queue_size 16 \
-probesize 32k -analyzeduration 0 \
-i rtsp://xxx \
-vf scale=960:-2 -an -f rawvideo -
公网 / 4G / 弱网(稳优先)
-rtsp_transport tcp -stimeout 8000000 \
-max_delay 3000000 -reorder_queue_size 32 \
-buffer_size 2M -fflags discardcorrupt \
-probesize 64k -analyzeduration 1M
七、RTSP 调试 Checklist
是否强制 tcp?
stimeout 是否设了(且非 0)?
max_delay 是否按场景裁剪过?
reorder_queue_size ≥ 16?
probesize/analyzeduration 是否为了秒开调过?
ffmpeg 版本 ≥ 5.0?(老版 rtsp depacketizer 有坑)
是否用 av_dict_set 而不是命令行裸跑?
断线是否重建 FormatContext(不是 retry 同一个)?
八、一句话总结
**FFmpeg RTSP 解复用的本质:用 jitter buffer 换连续性,用 TCP 换稳定性,用 probesize 换起播速度。**
参数不是"调优",而是在三者之间做工程取舍。