4. RTP与RTCP
FFmpeg 这工具,说白了就是我们流媒体工程师的瑞士军刀。不管你后面做 RTSP 推流、转码还是录制,最终都得跟它打交道。我刚开始接触 FFmpeg 时,看着那一长串命令行也头疼,但摸清它的结构后,你会发现其实就那么几块东西拼起来。
4.1 FFmpeg 命令行结构:先拆开看看
一条完整的 FFmpeg 命令,通常长这样:
ffmpeg [全局参数] [输入参数] -i 输入文件 [输出参数] 输出文件
嗯,核心就四个部分:
- ffmpeg – 调用程序本身
- [全局参数] – 影响整个命令行为的设置,比如日志级别、覆盖文件策略
- [输入参数] + -i 输入文件 – 指定输入源及其解码方式
- [输出参数] + 输出文件 – 指定输出目标及其编码方式
你想想看,FFmpeg 本质上就是个管道:输入 → 解码 → 滤镜处理 → 编码 → 输出。每个环节都可以用参数控制。
核心原则:参数的位置决定了它的作用范围。写在 -i 前面的,影响输入;写在 -i 后面的,影响输出。
举个例子,我早期在项目中经常看到有人把输出参数写在 -i 前面,结果 FFmpeg 直接报错。记住这个顺序,能省不少调试时间。
4.2 常用参数解析:这些你必须记住
FFmpeg 参数多到能写本书,但日常推流管线搭建中,常用的其实就二三十个。我把它们分成几类,方便你记忆。
4.2.1 核心控制参数
| 参数 | 作用 | 示例 |
|---|---|---|
-y |
覆盖输出文件,不询问 | -y output.mp4 |
-n |
不覆盖输出文件,直接退出 | -n output.mp4 |
-loglevel |
控制日志输出级别 | -loglevel debug |
-hide_banner |
隐藏编译信息,只显示日志 | -hide_banner -i input.mp4 |
我的习惯:调试时用 -loglevel debug 或 info,上线后改成 warning 或 error,不然日志刷屏你根本找不到关键信息。
4.2.2 视频相关参数
| 参数 | 作用 | 示例 |
|---|---|---|
-c:v 或 -vcodec |
指定视频编码器 | -c:v libx264 |
-b:v |
设置视频码率 | -b:v 2M |
-r |
设置帧率 | -r 25 |
-s |
设置分辨率 | -s 1920x1080 |
-vf |
应用视频滤镜 | -vf "scale=1280:720" |
4.2.3 音频相关参数
| 参数 | 作用 | 示例 |
|---|---|---|
-c:a 或 -acodec |
指定音频编码器 | -c:a aac |
-b:a |
设置音频码率 | -b:a 128k |
-ar |
设置音频采样率 | -ar 44100 |
-ac |
设置声道数 | -ac 2 |
4.2.4 流映射与复制模式
| 参数 | 作用 | 示例 |
|---|---|---|
-map |
手动选择要处理的流 | -map 0:v:0 -map 0:a:1 |
-c copy |
流复制模式,不解码不编码 | -c copy output.ts |
-sn |
禁用字幕流 | -sn output.mp4 |
-dn |
禁用数据流 | -dn output.mp4 |
我曾经踩过的坑:用 -c copy 做转封装时,如果输入文件有 B 帧,输出容器不支持的话,播放器会花屏。所以复制模式不是万能的,得先确认容器兼容性。
4.3 音视频文件转封装:最常用的实战操作
转封装,说白了就是改变文件的容器格式,不重新编码。比如把 MP4 转成 TS,或者把 MKV 转成 MP4。这个过程快得飞起,因为 FFmpeg 只做解复用和复用,不碰编解码。
基本命令就一行:
ffmpeg -i input.mp4 -c copy output.ts
-c copy 就是告诉 FFmpeg:视频和音频都直接复制,别给我转码。我见过很多新手在这个命令上翻车,原因往往是输入文件的编码格式不被输出容器支持。
4.3.1 常见转封装场景
- MP4 → TS:常用于直播录制转点播,或者 HLS 切片前的预处理
- MKV → MP4:MKV 封装了 H.264 + AAC,直接复制到 MP4 容器
- FLV → MP4:老式 Flash 视频转通用格式
- AVI → MKV:AVI 容器太老,换成 MKV 支持更多特性
举个例子,我在做一个点播平台时,用户上传的是 TS 文件,但播放器只认 MP4。转封装命令就是:
ffmpeg -i input.ts -c copy -movflags +faststart output.mp4
这里加了个 -movflags +faststart,目的是把 MP4 的 moov box 挪到文件头,这样播放器不用下载完整个文件就能开始播放。嗯,这个参数在 Web 播放场景下几乎是必加的。
4.3.2 转封装时的流选择
有时候输入文件里有多个视频流或多个音频流,比如电影文件带了好几条音轨。这时候 -map 就派上用场了。
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:1 -c copy output.mp4
这条命令的意思是:取第一个视频流(0:v:0)和第二个音频流(0:a:1),直接复制到 MP4 里。我习惯用 -map 来精确控制,而不是让 FFmpeg 自动选,因为自动选的结果有时候不是你想要的。
4.3.3 转封装 + 局部转码
还有一种情况:视频流保持复制,但音频流需要转码。比如输入是 DTS 音频,但目标播放器不支持,只认 AAC。
ffmpeg -i input.mkv -c:v copy -c:a aac -b:a 192k output.mp4
这样视频直接复制,音频重新编码成 AAC。速度比全转码快得多,质量损失也小。
我的建议:能用复制就别转码。转封装几秒搞定,转码可能要几分钟甚至几小时。只有在容器不兼容或编码格式不匹配时,才考虑局部转码。
4.4 本章知识体系总览
下面这张图,把 FFmpeg 命令行结构、参数分类和转封装流程串起来了。你以后写命令时,脑子里可以过一遍这个流程。
4.5 避坑指南与实战技巧
最后,分享几个我在项目中积累的经验,希望能帮你少走弯路。
- 先查容器兼容性:转封装前,用
ffprobe看一眼输入文件的编码格式,确认目标容器是否支持。比如 MP4 不支持 DTS 音频,MKV 不支持某些 MPEG-2 变体。 - 测试小文件:我习惯先拿一个 10 秒的片段做测试,确认命令没问题再处理大文件。用
-t 10或-ss 0 -to 10截取片段。 - 保留原始时间戳:转封装时加
-copyts可以保留输入文件的时间戳,避免播放时出现跳变。 - 注意 B 帧问题:有些容器对 B 帧支持不好,转封装后可能出现解码错误。遇到这种情况,要么换容器,要么加
-bf 0禁用 B 帧(但会重新编码)。
我曾经踩过的坑:有一次线上转封装任务,我用了 -c copy 把一批 TS 文件转成 MP4,结果播放器全部卡在开头。排查了半天,发现是 TS 文件里的 PTS 起始值不是 0,MP4 容器不认。最后加了 -output_ts_offset 0 才解决。嗯,从那以后我转封装都会先跑一遍 ffprobe 看看时间戳信息。