4、实战推流:使用FFmpeg推流本地文件、使用FFmpeg推流摄像头、使用FFmpeg推流桌面

好,到了真正动手的时候了。

前面几章我们把RTSP协议、FFmpeg基础、SDP格式都过了一遍。说实话,光看理论容易犯困。我自己学的时候也是这样——看文档看得眼皮打架,一打开终端敲命令反而精神了。

这一章我们就来点实在的。三种最常见的推流场景:本地文件、摄像头、桌面。我会把每个命令拆开讲,告诉你每个参数是干嘛的,踩过哪些坑。

本章核心目标:用FFmpeg把三种不同来源的媒体数据,通过RTSP协议推送到流媒体服务器。

4.1 推流前的准备工作

在开始之前,你得确认几件事。嗯,都是我在项目里吃过亏才养成的习惯。

  • FFmpeg已安装:终端输入 ffmpeg -version,能看到版本号就行。我建议用4.4以上版本,对RTSP支持更稳定。
  • RTSP服务器已启动:我们用的是EasyDarwin或ZLMediaKit。确保服务端监听端口(默认554)是通的。
  • 网络连通性:推流端和服务器之间不要有防火墙拦着。我曾经在客户现场排查了俩小时,最后发现是安全组没开端口。

小技巧:先用 telnet 服务器IP 554 测试一下端口通不通。不通的话,后面所有操作都是白费力气。

4.2 使用FFmpeg推流本地文件

这是最基础、也最常用的场景。比如你想把一个录好的视频文件,模拟成实时直播流。

4.2.1 基本命令

ffmpeg -re -i input.mp4 -c copy -f rtsp rtsp://192.168.1.100:554/live/test

来,我们拆开看看每个参数的意思:

参数 含义 为什么重要
-re 以原始帧率读取 不加这个,文件会以最快速度推完,根本不像直播
-i input.mp4 指定输入文件 支持mp4、flv、ts等常见格式
-c copy 直接复制编码数据 不重新编码,CPU占用极低
-f rtsp 指定输出格式为RTSP 告诉FFmpeg我们要走RTSP协议
rtsp://... 推流目标地址 路径可以自定义,方便区分不同流

注意:-c copy 虽然快,但要求源文件的编码格式能被RTSP容器支持。如果遇到花屏或无法播放,试试换成 -c:v libx264 -c:a aac 重新编码。

4.2.2 循环推流

有时候你想让一个短视频循环播放,模拟24小时不间断直播。加个 -stream_loop -1 就行:

ffmpeg -re -stream_loop -1 -i short_clip.mp4 -c copy -f rtsp rtsp://192.168.1.100:554/live/loop

这里 -1 表示无限循环。我做过一个数字标牌项目,就是用这个方式让广告视频循环推流的。跑了三个月没出过问题。

4.2.3 推流时叠加时间戳

做监控回放或测试时,我习惯在画面上叠加时间戳,方便定位问题:

ffmpeg -re -i input.mp4 -vf "drawtext=text='%{localtime}':fontsize=24:fontcolor=white:x=10:y=10" -c:v libx264 -c:a aac -f rtsp rtsp://192.168.1.100:554/live/timestamp

这个命令会重新编码视频(因为加了滤镜),CPU会高一些。但调试时很有用。

4.3 使用FFmpeg推流摄像头

摄像头推流是安防、直播、远程监控的核心场景。说实话,这里坑最多。

4.3.1 查看可用设备

先看看系统认不认你的摄像头:

  • Linux:v4l2-ctl --list-devices 或 ls /dev/video*
  • Windows:ffmpeg -list_devices true -f dshow -i dummy
  • macOS:ffmpeg -f avfoundation -list_devices true -i ""

我记得第一次在Linux上搞摄像头,忘了加载 v4l2 驱动,折腾了半天才发现设备节点都没出来。

4.3.2 Linux下推流USB摄像头

ffmpeg -f v4l2 -i /dev/video0 -f alsa -i hw:0,0 -c:v libx264 -c:a aac -f rtsp rtsp://192.168.1.100:554/live/cam

参数说明:

  • -f v4l2:指定视频输入格式为V4L2
  • -i /dev/video0:摄像头设备节点
  • -f alsa -i hw:0,0:音频设备(如果摄像头不带麦克风可以去掉)

经验之谈:USB摄像头默认分辨率可能很高,推流会卡。建议加 -s 640x480 或 -s 1280x720 限制分辨率。帧率用 -r 15 或 -r 25。

4.3.3 Windows下推流摄像头

ffmpeg -f dshow -i video="USB Camera" -f dshow -i audio="Microphone" -c:v libx264 -c:a aac -f rtsp rtsp://192.168.1.100:554/live/cam

Windows用dshow(DirectShow)驱动。设备名要用引号括起来,名字可以从 -list_devices 的输出里复制。

4.3.4 摄像头推流的常见问题

问题 原因 解决办法
画面卡顿 分辨率太高或帧率太大 降低 -s 和 -r,或者加 -preset ultrafast
没有画面 设备被占用或驱动不对 检查 ls /dev/video*,关闭其他摄像头应用
延迟很大 编码缓冲太大 加 -tune zerolatency 参数
音频视频不同步 采样率或时间基不一致 显式指定 -ar 44100 -ac 2

4.4 使用FFmpeg推流桌面

桌面推流常用于游戏直播、远程培训、软件演示。说白了就是把屏幕上的内容实时编码推出去。

4.4.1 Linux下推流桌面(X11)

ffmpeg -f x11grab -s 1920x1080 -i :0.0 -f alsa -i hw:0,0 -c:v libx264 -c:a aac -f rtsp rtsp://192.168.1.100:554/live/desktop

关键参数:

  • -f x11grab:抓取X11桌面
  • -s 1920x1080:抓取区域大小
  • -i :0.0:显示器编号,:0.0 是主显示器

注意:如果是在SSH远程会话里,x11grab 抓不到画面。必须在本机或VNC会话中运行。我曾经在服务器上远程执行这个命令,等了半天发现推出去的是黑屏。

4.4.2 Windows下推流桌面(gdigrab)

ffmpeg -f gdigrab -i desktop -f dshow -i audio="Microphone" -c:v libx264 -c:a aac -f rtsp rtsp://192.168.1.100:554/live/desktop

Windows用 gdigrab 抓屏。如果想只抓某个窗口,把 -i desktop 换成 -i title="窗口标题" 就行。

4.4.3 macOS下推流桌面(avfoundation)

ffmpeg -f avfoundation -i "1" -f avfoundation -i ":0" -c:v libx264 -c:a aac -f rtsp rtsp://192.168.1.100:554/live/desktop

macOS用avfoundation。数字 1 代表屏幕(0是摄像头),:0 代表麦克风。

4.4.4 桌面推流的性能优化

桌面推流最吃CPU。你想想看,每秒要抓取、编码1920x1080的画面,还要保证流畅。我建议:

  • 降低帧率:-r 10 或 -r 15,非游戏场景足够了
  • 使用硬件编码:加 -c:v h264_nvenc(NVIDIA)或 -c:v h264_amf(AMD)
  • 限制码率:-b:v 2M,避免网络波动
  • 开启 ultrafast preset:-preset ultrafast,牺牲压缩率换速度
ffmpeg -f x11grab -s 1920x1080 -i :0.0 -c:v h264_nvenc -preset p1 -b:v 2M -r 15 -f rtsp rtsp://192.168.1.100:554/live/desktop

这个命令用了NVIDIA硬件编码,CPU占用从90%降到了20%左右。效果很明显。

4.5 三种推流场景对比

场景 输入方式 典型用途 CPU负载 延迟
本地文件 -i file.mp4 视频点播转直播、循环播放 低(-c copy) 低
摄像头 -f v4l2 / -f dshow 安防监控、视频会议 中 中
桌面 -f x11grab / -f gdigrab 游戏直播、远程培训 高 较高

4.6 本章知识体系

下面这张图把三种推流场景的流程和关键参数串起来了。你可以把它当作速查手册。

FFmpeg RTSP 推流三种场景流程图 本地文件 -re -i input.mp4 摄像头 -f v4l2 -i /dev/video0 桌面 -f x11grab -i :0.0 编码选项(根据场景选择) -c copy(文件) -c:v libx264(摄像头) -preset ultrafast(桌面) -b:v 2M(码率控制) RTSP 封装 -f rtsp + SDP 描述 + RTP 传输 RTSP 流媒体服务器 rtsp://服务器IP:554/live/流名称 常用服务器: EasyDarwin / ZLMediaKit

4.7 避坑指南

最后,分享几个我踩过的坑。嗯,都是真金白银换来的教训。

  • 路径不要有中文:FFmpeg对中文路径支持不好,有时候会莫名其妙报错。我习惯全部用英文路径。
  • 推流地址要唯一:同一个RTSP路径只能有一个推流端。如果第二个推流端用相同路径,第一个会被踢掉。我在一次线上直播中犯过这个错,画面突然断了,观众全在刷问号。
  • 网络断开后不会自动重连:FFmpeg推流时如果网络断了,它不会自动重试。需要自己写脚本监控进程,或者用 -reconnect 参数(部分版本支持)。
  • 音频设备别搞错:推摄像头时如果音频设备选错了,推出去只有画面没有声音。先用 -list_devices 确认设备名。

我的习惯:每次推流前,先用 ffplay 测试一下输入源是否正常。比如 ffplay -f v4l2 -i /dev/video0,能看到画面再推。这一步能省下大量排查时间。