2. 推流环境准备:FFmpeg编译与安装、推流工具链搭建、测试流媒体服务器部署

做推流卡顿排查,第一步不是调参数,而是先把环境搭扎实。我见过太多人花了两小时查问题,最后发现是FFmpeg版本不对,或者服务器少了个模块。嗯,这章我们就一次性把这些基础工作做干净。

本章核心目标:搭建一套可复现、可调试的推流实验环境。包括FFmpeg的定制编译、推流工具链的选型与配置、以及本地测试流媒体服务器的部署。

2.1 FFmpeg编译与安装

很多人直接apt-get install ffmpeg就完事了。但做流媒体优化,我建议你从源码编译。为什么?因为发行版自带的FFmpeg往往砍掉了调试符号、禁用了某些编码器,或者版本太老。你想想看,排查卡顿的时候连个--enable-debug都没有,那真是寸步难行。

2.1.1 为什么选择源码编译

  • 精细控制模块:可以按需开启/关闭编码器、复用器、协议。比如我只用H.264和AAC,那就只编这两个,减少二进制体积和潜在的依赖冲突。
  • 调试符号保留:加上--enable-debug --disable-optimizations,出问题可以直接gdb attach上去看堆栈。
  • 性能优化:可以针对当前CPU架构开启汇编优化(--enable-x86asm),这在推流场景下能省下不少CPU。

注意:如果你只是临时测试,用静态编译版本也行。但做卡顿排查,我强烈建议你走一遍源码编译流程。我曾经在排查一个诡异的丢帧问题时,发现就是发行版FFmpeg的libx264版本太旧,导致B帧参考关系异常。换成最新源码编译后,问题直接消失。

2.1.2 编译步骤(以Ubuntu 22.04为例)

先装依赖,这一步别偷懒。少了某个库,编译出来的FFmpeg可能就缺了某个关键功能。

# 安装基础编译工具
sudo apt update
sudo apt install -y \
  autoconf automake build-essential cmake git \
  libass-dev libfreetype6-dev libsdl2-dev libtool \
  libva-dev libvdpau-dev libvorbis-dev libxcb1-dev \
  libxcb-shm0-dev libxcb-xfixes0-dev pkg-config \
  texinfo wget zlib1g-dev

# 安装编码器依赖(H.264 + AAC)
sudo apt install -y libx264-dev libx265-dev libfdk-aac-dev libmp3lame-dev libopus-dev

然后拉取FFmpeg源码,我习惯用git clone,方便后续切分支或回滚。

git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg
cd ffmpeg
git checkout release/6.0   # 选一个稳定版本

配置环节是关键。下面是我做推流测试常用的配置项:

./configure \
  --prefix=/usr/local/ffmpeg \
  --enable-gpl \
  --enable-version3 \
  --enable-nonfree \
  --enable-debug=3 \
  --disable-optimizations \
  --enable-libx264 \
  --enable-libx265 \
  --enable-libfdk-aac \
  --enable-libmp3lame \
  --enable-libopus \
  --enable-libass \
  --enable-libfreetype \
  --enable-ffplay \
  --enable-ffprobe \
  --enable-network \
  --enable-protocol=tcp,udp,rtmp,http,https \
  --enable-filter=aresample,scale,fps,setpts \
  --enable-encoder=libx264,libx265,libfdk_aac,aac \
  --enable-decoder=h264,aac,hevc \
  --enable-muxer=flv,mp4,ts,mpegts \
  --enable-demuxer=flv,mp4,ts,mpegts

这里我特别提一下--enable-debug=3和--disable-optimizations。调试时这两个选项能让你看到完整的变量值和函数调用链。当然,性能会差一些,但排查阶段无所谓。

编译和安装:

make -j$(nproc)
sudo make install

验证安装:

/usr/local/ffmpeg/bin/ffmpeg -version
# 输出中应包含 --enable-libx264 --enable-libfdk-aac 等字样

小技巧:把/usr/local/ffmpeg/bin加到PATH里,避免和系统自带的FFmpeg冲突。我一般在~/.bashrc里加一行export PATH=/usr/local/ffmpeg/bin:$PATH。

2.2 推流工具链搭建

光有FFmpeg还不够。推流是一个链条:采集 → 编码 → 封装 → 发送。每个环节都需要对应的工具来验证和调试。下面是我常用的工具链清单。

2.2.1 核心工具清单

工具 用途 安装方式
FFmpeg 推流主体,负责编码和发送 源码编译(见2.1节)
FFprobe 分析流媒体信息,查看编码参数、帧率、码率 随FFmpeg一起编译
FFplay 本地播放测试流,验证推流效果 随FFmpeg一起编译
OBS Studio 图形化推流工具,用于对比测试 sudo apt install obs-studio
tshark / Wireshark 抓包分析网络层,排查丢包、延迟 sudo apt install tshark
nload / iftop 实时监控网卡流量,看推流带宽是否跑满 sudo apt install nload iftop

2.2.2 验证工具链是否就绪

写一个简单的测试脚本,确保每个工具都能正常工作:

#!/bin/bash
echo "=== 检查推流工具链 ==="

# 检查FFmpeg
ffmpeg -version &>/dev/null
if [ $? -eq 0 ]; then
    echo "[OK] FFmpeg"
else
    echo "[FAIL] FFmpeg"
fi

# 检查FFprobe
ffprobe -version &>/dev/null
if [ $? -eq 0 ]; then
    echo "[OK] FFprobe"
else
    echo "[FAIL] FFprobe"
fi

# 检查抓包工具
tshark --version &>/dev/null
if [ $? -eq 0 ]; then
    echo "[OK] tshark"
else
    echo "[FAIL] tshark"
fi

echo "=== 检查完成 ==="

个人习惯:我会在每台测试机上跑一遍这个脚本,确保环境一致。曾经有一次排查卡顿,折腾了半天发现是测试机A的FFmpeg版本比测试机B低了两个大版本,导致编码参数解析不一致。从那以后,我坚持用脚本统一校验环境。

2.3 测试流媒体服务器部署

推流总得有个接收端吧?本地测试我推荐用Nginx + RTMP模块,或者SRS(Simple-Rtmp-Server)。SRS功能更全,支持RTMP、HLS、SRT等多种协议,而且配置简单。

2.3.1 部署SRS(推荐)

SRS是我做推流测试的首选。它轻量、稳定,而且日志非常详细,对排查卡顿很有帮助。

# 下载SRS源码
git clone https://github.com/ossrs/srs.git
cd srs/trunk

# 编译(默认开启RTMP + HLS)
./configure
make -j$(nproc)

# 启动服务器
./objs/srs -c conf/srs.conf

启动后,SRS默认监听1935端口(RTMP)和8080端口(HTTP API)。验证是否启动成功:

curl http://localhost:8080/api/v1/versions
# 返回JSON格式的版本信息,说明服务正常

2.3.2 配置SRS用于卡顿测试

默认配置可以直接用,但为了模拟真实推流场景,我建议调整几个参数:

# conf/srs.conf 关键配置项
listen              1935;
max_connections     1000;
daemon              off;          # 前台运行,方便看日志
srs_log_tank        console;      # 日志输出到控制台

vhost __defaultVhost__ {
    gop_cache       off;          # 关闭GOP缓存,模拟低延迟场景
    hls {
        enabled     on;
        hls_fragment    2;        # 每个TS切片2秒
        hls_window      6;        # 窗口大小6秒
    }
}

这里gop_cache off是我做卡顿测试时常用的。关闭GOP缓存后,推流端每发一个关键帧,服务器就立即转发,不会缓存等待。这样能更真实地反映网络抖动对推流的影响。

2.3.3 部署Nginx + RTMP模块(备选)

如果你更习惯Nginx,也可以用这个方案:

# 安装Nginx和RTMP模块
sudo apt install nginx libnginx-mod-rtmp

# 配置RTMP
sudo vim /etc/nginx/nginx.conf
# 在http块外面添加:
rtmp {
    server {
        listen 1935;
        chunk_size 4096;
        application live {
            live on;
            record off;
        }
    }
}

# 重启Nginx
sudo systemctl restart nginx

避坑:Nginx的RTMP模块功能相对基础,不支持HLS切片、SRT协议等高级功能。如果你后续要做HLS卡顿排查,建议直接用SRS。我曾经在Nginx上折腾了半天HLS配置,最后发现是模块不支持,换SRS后十分钟搞定。

2.4 推流环境整体架构

下面这张图展示了我们搭建的推流测试环境全貌。你可以看到数据从采集端到播放端的完整路径,以及每个环节用到的工具。

推流测试环境架构图 采集端 摄像头 / 桌面 / 测试视频 编码 + 封装 FFmpeg (libx264 + FLV) 推流发送 RTMP / SRT 协议 流媒体服务器 SRS / Nginx-RTMP 播放端 FFplay / VLC / 浏览器 调试工具层 FFprobe 流分析 Wireshark 抓包 nload 带宽监控 SRS 日志分析

从架构图可以看出,我们的测试环境覆盖了推流的完整链路。每个环节都有对应的调试工具,这样一旦出现卡顿,我们可以快速定位是采集端的问题、编码端的问题、网络传输的问题,还是服务器端的问题。

2.5 环境验证:跑一个简单的推流测试

环境搭好了,总得跑一下验证吧?下面这个命令会推送一个测试视频到本地SRS服务器:

# 生成一个测试视频源(10秒,30fps,彩色条纹)
ffmpeg -f lavfi -i testsrc2=size=1280x720:rate=30:duration=10 \
       -f lavfi -i sine=frequency=440:duration=10 \
       -c:v libx264 -preset ultrafast -b:v 2000k \
       -c:a aac -b:a 128k \
       -f flv rtmp://localhost:1935/live/test

然后在另一个终端用FFplay拉流播放:

ffplay rtmp://localhost:1935/live/test

如果能看到画面和声音,说明整个推流环境已经就绪。嗯,到这里,我们的测试环境就全部搭好了。

个人经验:第一次跑通推流测试时,我建议你同时打开SRS的控制台日志(srs_log_tank console),观察推流过程中的连接建立、数据接收、GOP缓存等日志信息。这些日志在后续排查卡顿时会非常有用。我曾经靠SRS日志里的一条recv timeout信息,定位到一个隐藏了很久的网卡驱动问题。