4、FFmpeg 基础命令:推流命令结构解析

好,咱们进入第四章。前面几章我们把推流的理论框架搭起来了,也聊了 RTMP 协议到底是个什么玩意儿。从这章开始,要动真格的了——敲命令。

FFmpeg 这工具,说简单也简单,说复杂也复杂。我见过不少新手,上来就复制粘贴网上的命令,跑通了就觉得自己会了。结果一换场景,摄像头推流换成桌面推流,立马抓瞎。为什么?因为没搞懂命令的结构。

这一章,我就带你把这个结构拆开揉碎。你搞懂了骨架,以后不管推什么源,都能自己拼命令。

4.1 推流命令的骨架:一个都不能少

一条完整的 FFmpeg 推流命令,说白了就四个部分:

ffmpeg [输入选项] -i [输入源] [输出选项] [输出地址]

嗯,就这么简单。但每个部分都有讲究。我画了张图,你先看个全貌:

FFmpeg 推流命令结构 ffmpeg [输入选项] -i [输入源] [输出选项] [输出地址] (rtmp://...) 核心原则: 输入选项只对 -i 后面的输入源生效,输出选项只对输出地址生效。 顺序不能乱:ffmpeg → 输入部分 → 输出部分。

你看,左边是输入部分,右边是输出部分。中间用 -i 隔开。我个人习惯把这条线叫做「分水岭」——分水岭左边管怎么读,分水岭右边管怎么发。

4.2 本地文件推流到 RTMP 服务器

这是最基础的场景。你手头有个 MP4 文件,想推到服务器上做直播。命令长这样:

ffmpeg -re -i ./demo.mp4 -c copy -f flv rtmp://your-server/live/stream-key

咱们拆开看:

  • -re:这个参数很关键。它的意思是「以原始帧率读取」。不加它,FFmpeg 会以最快速度把文件读完然后推出去,服务器那边看到的画面就是快进的。我在项目中遇到过有人不加 -re,结果直播画面像开了 16 倍速,弹幕都炸了。
  • -i ./demo.mp4:指定输入文件。路径可以是相对路径,也可以是绝对路径。
  • -c copy:复制编码。意思是「不解码也不重新编码,直接把文件里的视频流和音频流原封不动地推出去」。这是最高效的方式,CPU 占用极低。
  • -f flv:指定输出封装格式为 FLV。RTMP 协议传输的数据格式就是 FLV,所以这个必须写。
  • rtmp://your-server/live/stream-key:推流地址。注意,stream-key 是你自己定义的流名称,服务器靠它来区分不同的直播间。
小提示:如果你想把文件循环推流,可以加上 -stream_loop -1。比如做 7x24 小时的测试推流,这个参数很实用。但要注意,循环推流时 -re 必须保留,否则 CPU 会飙到 100%。

4.3 摄像头推流:设备输入的坑与解

文件推流只是开胃菜。真正干活的时候,更多是推摄像头或者桌面。不同操作系统,设备名称不一样,这是新手最容易踩坑的地方。

先看 Windows 下的摄像头推流:

ffmpeg -f dshow -i video="USB Camera" -f dshow -i audio="Microphone" -c:v libx264 -preset ultrafast -b:v 2000k -c:a aac -b:a 128k -f flv rtmp://your-server/live/stream-key

这里有几个新面孔:

  • -f dshow:Windows 下通过 DirectShow 接口采集设备。说白了就是告诉 FFmpeg:「我要用 Windows 的摄像头驱动来抓画面」。
  • video="USB Camera":设备名称。这个名称怎么查?运行 ffmpeg -list_devices true -f dshow -i dummy,FFmpeg 会列出你电脑上所有的音视频设备。
  • -c:v libx264 -preset ultrafast:用 CPU 做 H.264 编码。ultrafast 是预设,编码速度最快,但压缩率最低。直播场景下,我建议用 veryfast 或 faster,画质会好一些。
  • -b:v 2000k:视频码率 2Mbps。这个值根据你的上行带宽和画质需求来调。

Linux 下呢?用 V4L2:

ffmpeg -f v4l2 -i /dev/video0 -f alsa -i hw:0,0 -c:v libx264 -preset veryfast -b:v 2000k -c:a aac -b:a 128k -f flv rtmp://your-server/live/stream-key

macOS 下用 AVFoundation:

ffmpeg -f avfoundation -i "0:0" -c:v libx264 -preset veryfast -b:v 2000k -c:a aac -b:a 128k -f flv rtmp://your-server/live/stream-key

你看,核心逻辑都一样,就是设备采集的接口名不同。我建议你把这三个平台的命令存成笔记,用到的时候直接改设备名和码率就行。

注意:摄像头推流时,-re 不需要加。因为摄像头是实时设备,FFmpeg 会按照实际帧率读取。如果你加了 -re,反而可能导致帧率被限制,画面卡顿。

4.4 桌面推流:抓屏与编码的平衡

桌面推流比摄像头复杂一点。因为桌面分辨率通常很高(1080p 甚至 4K),编码压力大。而且不同系统的抓屏方式也不一样。

Windows 下用 gdigrab:

ffmpeg -f gdigrab -i desktop -c:v libx264 -preset ultrafast -b:v 4000k -f flv rtmp://your-server/live/stream-key

这个命令会抓取整个桌面。如果你想抓取某个窗口,可以指定窗口标题:

ffmpeg -f gdigrab -i title="Chrome" -c:v libx264 -preset ultrafast -b:v 3000k -f flv rtmp://your-server/live/stream-key

Linux 下用 x11grab:

ffmpeg -f x11grab -i :0.0 -c:v libx264 -preset ultrafast -b:v 4000k -f flv rtmp://your-server/live/stream-key

macOS 下用 avfoundation 的屏幕捕获:

ffmpeg -f avfoundation -i "1" -c:v libx264 -preset ultrafast -b:v 4000k -f flv rtmp://your-server/live/stream-key

桌面推流有个常见问题:画面静止时码率浪费。我建议加上 -x264-params keyint=60:scenecut=0,强制每 2 秒一个关键帧,这样观众端切换画面时不会卡太久。

经验之谈:桌面推流时,-preset ultrafast 几乎是必须的。因为桌面画面变化频繁(鼠标移动、窗口切换),如果用 medium 或 slow,CPU 会瞬间飙满,导致编码延迟。我曾经在直播一个 PPT 演示时用了 medium,结果翻页时画面卡了 3 秒才更新,观众全跑了。

4.5 常用参数速查表

我把本章涉及的核心参数整理成了一张表,方便你以后查阅:

参数 作用 适用场景
-re 以原始帧率读取输入 文件推流(必须加)
-c copy 复制编码,不重新编码 文件推流(最高效)
-c:v libx264 使用 CPU 进行 H.264 编码 摄像头/桌面推流
-preset ultrafast 编码速度最快,压缩率最低 桌面推流、低配机器
-b:v 2000k 视频码率 2Mbps 根据带宽调整
-f flv 输出封装格式为 FLV RTMP 推流(必须写)
-f dshow Windows 设备采集接口 Windows 摄像头/麦克风
-f v4l2 Linux 设备采集接口 Linux 摄像头
-f avfoundation macOS 设备采集接口 macOS 摄像头/屏幕
-f gdigrab Windows 屏幕采集接口 Windows 桌面推流
-f x11grab Linux 屏幕采集接口 Linux 桌面推流

4.6 避坑指南:我踩过的三个坑

最后,分享几个我实际项目中踩过的坑,你遇到了能少走弯路。

  • 坑一:设备名称带空格。Windows 下摄像头名称可能是 USB Camera,带空格。如果你不加引号,FFmpeg 会报错。记住,设备名有空格就用双引号包起来。
  • 坑二:音频设备没指定。推流时如果只指定了视频设备没指定音频,FFmpeg 会默认用系统的默认音频设备。但有时候默认设备是「无」,结果推出去的流没声音。我建议每次都显式指定音频设备,哪怕用 -an 禁用音频,也比无声流强。
  • 坑三:码率设置过高。我曾经在客户现场用 10Mbps 推 4K 桌面,结果服务器那边带宽扛不住,画面频繁断流。后来降到 4Mbps,稳如老狗。记住,推流码率不是越高越好,要结合你的上行带宽和服务器带宽来定。

嗯,这一章的内容就到这。命令结构搞清楚了,设备采集也知道了,接下来就是多练。你可以在本地搭一个简单的 RTMP 服务器(比如用 SRS 或者 Nginx-RTMP),然后拿这些命令去试。跑通了,你就真正入门了。