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 命令行结构、参数分类和转封装流程串起来了。你以后写命令时,脑子里可以过一遍这个流程。

FFmpeg 命令行结构与转封装流程 FFmpeg 命令行结构与转封装流程 ffmpeg [全局参数] [输入参数] -i 输入 [输出参数] 输出 参数分类 核心控制:-y, -n, -loglevel 视频参数:-c:v, -b:v, -r, -s 音频参数:-c:a, -b:a, -ar, -ac 转封装流程 输入文件(如 MP4) 解复用(Demux) 流复制(-c copy) 复用(Mux) 输出文件(如 TS) 常见转封装场景 MP4 → TS(直播录制) MKV → MP4(通用播放) FLV → MP4(老格式迁移) AVI → MKV(容器升级) 核心原则:参数位置决定作用范围;能用 -c copy 就别转码;转封装前确认容器兼容性

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 看看时间戳信息。