4、FFmpeg 基础命令:推流命令结构解析
好,咱们进入第四章。前面几章我们把推流的理论框架搭起来了,也聊了 RTMP 协议到底是个什么玩意儿。从这章开始,要动真格的了——敲命令。
FFmpeg 这工具,说简单也简单,说复杂也复杂。我见过不少新手,上来就复制粘贴网上的命令,跑通了就觉得自己会了。结果一换场景,摄像头推流换成桌面推流,立马抓瞎。为什么?因为没搞懂命令的结构。
这一章,我就带你把这个结构拆开揉碎。你搞懂了骨架,以后不管推什么源,都能自己拼命令。
4.1 推流命令的骨架:一个都不能少
一条完整的 FFmpeg 推流命令,说白了就四个部分:
ffmpeg [输入选项] -i [输入源] [输出选项] [输出地址]
嗯,就这么简单。但每个部分都有讲究。我画了张图,你先看个全貌:
你看,左边是输入部分,右边是输出部分。中间用 -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),然后拿这些命令去试。跑通了,你就真正入门了。