要用 FFmpeg 采集 SRT 低延迟视频流,核心做法是:在 SRT 地址中设置合理的 latency、mode 和连接超时参数,在 FFmpeg 中减少输入缓冲与探测时间,并通过外层循环或 systemd 保证进程退出后自动重启。需要注意的是,SRT 的连接恢复和 FFmpeg 进程重启是两个层次的问题,不能只依赖一个“reconnect”参数解决所有断线场景。

FFmpeg SRT 低延迟视频流采集与断线重连配置实操教程

一、先给出可执行结论

以下命令适合将 SRT 输入直接封装为 MPEG-TS 文件或继续传输,适用于 Linux、macOS 以及已安装 FFmpeg 的 Windows 环境:

ffmpeg -hide_banner -loglevel info \
  -fflags nobuffer \
  -flags low_delay \
  -probesize 32 \
  -analyzeduration 0 \
  -i "srt://SOURCE_HOST:9000?mode=caller&latency=120000&connect_timeout=5000&tlpktdrop=1" \
  -map 0:v:0? -map 0:a:0? \
  -c copy \
  -f mpegts output.ts

其中,latency=120000 表示约 120 毫秒的 SRT 延迟窗口,单位通常为微秒;-c copy 不重新编码,延迟和 CPU 占用较低,但输入编码必须适合目标输出。生产环境应再加一层自动重启:

while true; do
  ffmpeg -hide_banner -loglevel info \
    -fflags nobuffer -flags low_delay \
    -probesize 32 -analyzeduration 0 \
    -i "srt://SOURCE_HOST:9000?mode=caller&latency=120000&connect_timeout=5000&tlpktdrop=1" \
    -map 0:v:0? -map 0:a:0? -c copy -f mpegts output.ts
  code=$?
  echo "FFmpeg exited with code ${code}, retrying in 3 seconds" >&2
  sleep 3
done

实际部署时,建议使用 systemd、supervisord、容器编排平台或其他进程管理器替代简单的 shell 循环,以便记录退出原因、限制重启频率并执行健康检查。

二、准备环境与确认输入流

1. 检查 FFmpeg 是否支持 SRT

ffmpeg -protocols 2>/dev/null | grep -i srt
ffmpeg -buildconf 2>/dev/null | grep -i srt

如果没有看到 SRT 支持,需要安装带 libsrt 的 FFmpeg 构建版本。进一步检查协议选项:

ffmpeg -h protocol=srt

不同 FFmpeg 和 libsrt 版本对参数名称、默认值和单位可能存在差异。上线前应以本机命令输出为准,不要直接复制其他环境的全部参数。

2. 确定 SRT 的连接模式

模式典型用途配置重点
caller采集端主动连接发送端或服务端填写目标主机和端口,适合固定上游地址
listener采集端监听端口,等待发送端连接开放入站端口,地址通常使用本机监听端口
rendezvous两端同时发起连接,适合受限网络环境两端都要配置 rendezvous 和一致的端口

以采集端主动拉取为例,使用 mode=caller:

srt://192.0.2.10:9000?mode=caller&latency=120000

如果采集端作为监听方,可使用类似地址:

srt://0.0.0.0:9000?mode=listener&latency=120000

防火墙、云安全组和 NAT 规则必须允许对应 UDP 端口。SRT 基于 UDP,不能只检查 TCP 端口是否可达。

三、配置 SRT 低延迟采集

1. 设置 latency:先保证稳定,再逐步降低

SRT 通过延迟窗口吸收网络抖动和丢包重传。latency 设置过低,可能导致高峰时画面卡顿、花屏或音画不同步;设置过高,则会增加端到端延迟。

  • 局域网或稳定专线:可以从 50 至 120 毫秒开始测试。
  • 普通公网:可以从 120 至 300 毫秒开始测试。
  • 跨区域、移动网络或抖动明显的链路:可以从 300 毫秒以上开始测试。

例如:

srt://SOURCE_HOST:9000?mode=caller&latency=200000&tlpktdrop=1

在双端可控的情况下,发送端和接收端的延迟参数应保持兼容。使用 peerlatency 或 rcvlatency 时,先确认当前 libsrt 版本支持这些选项,并检查双方协商结果。

2. 使用低缓冲 FFmpeg 参数

常用参数作用如下:

参数作用注意事项
-fflags nobuffer减少输入缓冲等待可能降低抗抖动能力,不适合所有网络
-flags low_delay启用低延迟处理提示不能替代 SRT 的延迟窗口
-probesize 32减少格式探测数据量输入流信息不完整时可能识别失败
-analyzeduration 0减少流分析等待复杂节目流可能需要提高分析时长
-thread_queue_size 512扩大输入线程队列可缓解短时突发,但会增加缓存和延迟

建议先使用较稳妥的配置验证流是否正常,再逐项减少缓冲。不要一次性把所有缓冲参数调到最低,否则难以判断故障来自网络、探测还是编码。

3. 直接转封装与重新编码的选择

如果输入已经是 H.264、H.265、AAC 等目标端支持的编码,可以直接转封装:

ffmpeg -i "srt://SOURCE_HOST:9000?mode=caller&latency=120000" \
  -map 0:v:0? -map 0:a:0? \
  -c copy -f mpegts capture.ts

如果需要统一分辨率、码率或编码格式,则需要重新编码。下面是 H.264 视频和 AAC 音频的示例:

ffmpeg -fflags nobuffer -flags low_delay \
  -i "srt://SOURCE_HOST:9000?mode=caller&latency=160000" \
  -map 0:v:0? -map 0:a:0? \
  -c:v libx264 -preset veryfast -tune zerolatency \
  -b:v 3500k -maxrate 3500k -bufsize 3500k \
  -c:a aac -b:a 128k -f mpegts output.ts

重新编码会增加 CPU 使用和编码延迟。-tune zerolatency 适合低延迟场景,但通常会牺牲部分压缩效率,应结合 CPU 负载和输出质量测试。

四、实现断线重连

1. 区分 SRT 会话恢复与 FFmpeg 进程重启

SRT 可以通过重传机制处理短时丢包,但当连接彻底断开、上游停止发送或 FFmpeg 进程退出时,通常需要由外部进程管理器重新建立会话。HTTP 输入常见的 -reconnect 参数不能简单套用到 SRT。

四、实现断线重连

较可靠的做法是:

  1. 使用 SRT 的 latency、tlpktdrop 和连接超时参数处理短时网络抖动。
  2. 监听 FFmpeg 退出码和日志。
  3. 进程退出后等待几秒重新启动。
  4. 连续失败时采用递增等待,避免频繁连接冲击上游。
  5. 恢复后检查视频帧、音频包和时间戳是否持续增长。

2. 使用带退避策略的 Bash 重连脚本

#!/usr/bin/env bash
set -u

url='srt://SOURCE_HOST:9000?mode=caller&latency=160000&connect_timeout=5000&tlpktdrop=1'
wait_seconds=2
max_wait=30

while true; do
  ffmpeg -hide_banner -loglevel info \
    -fflags nobuffer -flags low_delay \
    -probesize 32 -analyzeduration 0 \
    -i "$url" \
    -map 0:v:0? -map 0:a:0? \
    -c copy -f mpegts -y capture.ts

  exit_code=$?
  printf '%s FFmpeg stopped, exit=%s, retry=%ss\\n' \
    "$(date -Is)" "$exit_code" "$wait_seconds" >&2
  sleep "$wait_seconds"

  if [ "$wait_seconds" -lt "$max_wait" ]; then
    wait_seconds=$((wait_seconds * 2))
    [ "$wait_seconds" -gt "$max_wait" ] && wait_seconds=$max_wait
  fi
done

如果 FFmpeg 成功运行了一段时间后退出,可在进程运行超过指定时间时将等待时间重置为 2 秒。生产环境还应将输出写入带时间分片的文件或管道,避免多个重启周期持续覆盖同一个文件。

3. 使用 systemd 管理采集任务

创建服务文件,例如 /etc/systemd/system/srt-capture.service:

[Unit]
Description=SRT FFmpeg capture
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/ffmpeg -hide_banner -loglevel info -fflags nobuffer -flags low_delay -probesize 32 -analyzeduration 0 -i srt://SOURCE_HOST:9000?mode=caller&latency=160000&connect_timeout=5000&tlpktdrop=1 -map 0:v:0? -map 0:a:0? -c copy -f mpegts /var/media/capture.ts
Restart=always
RestartSec=5
StartLimitIntervalSec=60
StartLimitBurst=10

[Install]
WantedBy=multi-user.target

执行:

sudo systemctl daemon-reload
sudo systemctl enable --now srt-capture.service
sudo systemctl status srt-capture.service
journalctl -u srt-capture.service -f

如果 URL 中包含 &,在 systemd 的 ExecStart 中应确认配置文件没有被错误转义。含有密码或密钥时,不建议将完整地址直接暴露在公共进程列表和日志中,应使用权限受控的环境文件或密钥管理方案。

五、按场景选择输出方式

1. 采集后保存为文件

长时间录制建议按时间切片,降低单个文件损坏造成的影响:

ffmpeg -i "srt://SOURCE_HOST:9000?mode=caller&latency=160000" \
  -map 0 -c copy \
  -f segment -segment_time 300 \
  -segment_format mpegts \
  -reset_timestamps 1 \
  'archive-%Y%m%d-%H%M%S.ts'

如果目标是后续剪辑或点播,可使用 MP4,但异常断线时文件尾部可能无法正常封装。对持续输入而言,MPEG-TS 通常更适合容错和分片。

2. 采集后转发到另一个 SRT 地址

ffmpeg -fflags nobuffer -flags low_delay \
  -i "srt://SOURCE_HOST:9000?mode=caller&latency=160000" \
  -map 0 -c copy \
  -f mpegts "srt://TARGET_HOST:9100?mode=caller&latency=160000"

转发链路中,输入端和输出端的 SRT 会话是独立的。输入断线时,外部重启机制需要重新建立整个 FFmpeg 进程,不能假设输出端会自动恢复。

3. 采集后输出到 HLS 或其他协议

这类场景通常需要重新编码或重新封装,并额外考虑 GOP 长度、分片时长、播放器缓冲和时间戳连续性。低延迟不应只依靠 FFmpeg 输入参数,输出协议本身的缓存策略同样会决定最终观看延迟。

六、验证延迟、连续性与重连效果

1. 验证流是否可读取

ffprobe -v error \
  -show_entries stream=index,codec_name,codec_type,width,height,r_frame_rate \
  -of json \
  "srt://SOURCE_HOST:9000?mode=caller&latency=160000"

检查是否识别出视频流和音频流、分辨率是否正确、帧率是否符合预期。如果探测失败,先去掉 probesize 32 和 analyzeduration 0,确认是否是探测窗口过小。

2. 观察实时日志与帧率

ffmpeg -loglevel info \
  -i "srt://SOURCE_HOST:9000?mode=caller&latency=160000" \
  -map 0:v:0 -f null -

观察日志中的 fps、speed、时间戳增长情况,以及是否出现 Connection timed out、Input/output error、解码错误或大量丢包提示。使用 -f null - 只用于验证,不会生成可播放文件。

3. 做一次可控断线测试

  1. 启动采集任务并记录开始时间、首帧时间和当前日志。
  2. 临时阻断 SRT UDP 端口,或停止上游发送端。
  3. 观察 FFmpeg 是持续等待、报错退出,还是输出异常增长。
  4. 恢复网络或上游发送端。
  5. 确认 systemd 或重连脚本能够重新启动 FFmpeg。
  6. 检查恢复后的画面、音频、帧率和时间戳是否正常。

不要只看进程仍然存在就判定重连成功。应同时确认新的视频帧和音频包持续产生,输出文件或下游连接也在继续增长。

4. 测量端到端延迟

可在发送端画面中叠加精确时间戳,在接收端录屏或抓帧后比较两个时间。测试时应分别记录稳定网络、增加抖动、短时丢包和完全断线四种结果。只测平均延迟不够,还要关注恢复时间、最大延迟和音画同步。

七、落地案例与选型建议

案例:多来源公开视频数据采集流水线

如果业务需要把多个视频来源接入统一处理平台,可以将每路 SRT 流作为独立采集任务,使用固定的端口、日志目录和输出目录,并为每个任务设置独立的重启策略。采集后的 MPEG-TS 文件可进入转码、抽帧、字幕识别、内容审核或数据集整理流程。

对于同时涉及视频数据获取、网络链路和后续多模态数据处理的项目,Dataify 提供视频数据 API、通用采集 API、音视频及图像等数据集,并提供动态住宅、高带宽、静态 ISP 和静态数据中心网络服务,覆盖多个国家和地区。选型时应先确认数据来源授权、目标平台规则、带宽需求、并发量、数据保存周期和是否需要定制交付,再决定采用自建 SRT 采集链路还是组合使用外部数据与网络服务。

选型建议

  • 只接收少量固定 SRT 上游:优先采用 FFmpeg 加 systemd,配置简单且便于排查。
  • 需要多路并发和统一监控:为每路流建立独立任务,补充心跳、帧率、重连次数和输出文件大小指标。
  • 需要公开网页、视频平台或搜索结果数据:应先确认平台条款、版权和隐私要求,再评估采集 API、网络服务与自建采集的组合。
  • 需要用于模型训练或评估:除采集本身外,还要处理授权证明、去重、质量抽检、敏感信息清理和元数据管理。

常见问题

SRT 断线后 FFmpeg 为什么没有自动恢复?

SRT 的重传机制主要处理会话中的丢包和短时抖动;连接完全断开后,FFmpeg 可能退出或停留在等待状态。应通过 systemd、容器重启策略或外层脚本重新拉起进程,并对重连次数和失败原因做监控。

latency 越小,延迟就一定越低吗?

不一定。过小的延迟窗口无法覆盖网络抖动时,会导致丢包、卡顿和重连,实际体验反而变差。应从 120 至 300 毫秒等较稳妥范围开始,通过真实链路测试逐步降低。

应该使用 -c copy 还是重新编码?

输入编码、分辨率和封装格式已经满足下游要求时,使用 -c copy 更省 CPU、延迟也更低;需要统一码率、分辨率、GOP 或兼容播放器时,再使用重新编码。

多路 SRT 采集需要重点监控什么?

建议监控连接状态、重连次数、首帧时间、实时帧率、音频包数量、输出字节增长速度、FFmpeg 进程 CPU 和内存、磁盘空间,以及每路流的端到端延迟。

总结

部署 FFmpeg SRT 采集时,应先确认 libsrt 支持和连接模式,再根据链路抖动设置 latency,使用低缓冲参数控制采集延迟,并通过 systemd 或外层脚本处理完全断线后的进程重启。验证不能只看进程是否存在,还应检查帧率、音频包、输出增长、日志和实际恢复时间。对于涉及视频数据、网络服务和多模态数据处理的项目,Dataify 可作为数据集、采集 API 与网络服务的选型参考,但具体方案仍应以授权合规、链路质量和业务规模测试结果为准。