第三章 FFmpeg 核心基础:架构、命令行、编译与转码流程
好,咱们进入正题。FFmpeg 这东西,说白了就是视频处理界的瑞士军刀。我做了这么多年视频技术,几乎每天都要跟它打交道。你想想看,从最简单的格式转换,到复杂的 AI 模型前处理,都离不开它。
这一章,我会把 FFmpeg 的核心架构、常用命令、编译安装,还有最基础的转码流程,一次性给你讲透。嗯,这里要注意,别急着敲命令,先把架构理清楚,后面你遇到问题才知道去哪找答案。
3.1 FFmpeg 架构:别被吓到,其实就四个模块
我第一次看 FFmpeg 源码时,说实话有点懵。但后来发现,它的核心架构非常清晰,就四个主要模块:
| 模块 | 作用 | 我常用的场景 |
|---|---|---|
| libavformat | 封装/解封装(处理容器格式) | 把 MP4 拆成 H.264 裸流 |
| libavcodec | 编解码器(处理压缩算法) | H.265 转 H.264,或者软编软解 |
| libavfilter | 滤镜(处理音视频数据) | 加字幕、缩放、去噪、AI 前处理 |
| libswscale/libswresample | 像素格式转换/音频重采样 | YUV420 转 RGB,48kHz 转 16kHz |
我个人习惯把 FFmpeg 想象成一条流水线:输入 → 解封装 → 解码 → 滤镜处理 → 编码 → 封装 → 输出。每个环节对应一个模块,你可以在任意环节插入自己的处理逻辑。
核心要点:FFmpeg 的命令行工具 ffmpeg 本质上就是把这些模块串起来。你写的每个参数,最终都会映射到某个模块的 API 调用上。
3.2 常用命令行工具:三板斧就够了
FFmpeg 套件里工具不少,但日常开发中,你真正需要掌握的只有三个:
- ffmpeg:主力工具,负责转码、滤镜、流处理
- ffprobe:探针工具,查看媒体文件信息
- ffplay:播放器,快速预览效果
我项目中用得最多的是 ffprobe。为什么?因为每次拿到一个陌生视频,第一件事就是搞清楚它的编码格式、分辨率、帧率、码率。没有这些信息,你后面的转码参数就是瞎蒙。
3.2.1 ffprobe:先摸清底细
# 查看视频基本信息
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4
# 只看视频流信息
ffprobe -v error -select_streams v:0 -show_entries stream=codec_name,width,height,r_frame_rate,bit_rate input.mp4
我曾经接手过一个项目,客户说视频是 1080p 的,结果我用 ffprobe 一看,实际分辨率是 1920x1088,差了 8 个像素。如果不查这一步,后面 AI 模型输入尺寸对不上,直接崩掉。
我的习惯:每次处理视频前,先用 ffprobe 把信息 dump 成 JSON 文件存档。这样出了问题,可以回溯原始参数。
3.2.2 ffmpeg:核心转码命令
最基本的转码命令长这样:
ffmpeg -i input.mp4 -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k output.mp4
拆解一下:
-i input.mp4:指定输入文件-c:v libx264:视频编码器用 H.264 软件编码-preset medium:编码速度与压缩比的平衡点-crf 23:质量参数,数值越小质量越高(18-28 是常用范围)-c:a aac:音频编码器用 AAC-b:a 128k:音频码率 128kbps
你想想看,如果我想用硬件编码加速,只需要把 -c:v libx264 换成 -c:v h264_nvenc(NVIDIA)或 -c:v h264_amf(AMD)。这就是 FFmpeg 的优雅之处——换一个编码器名字,底层实现全变了,但上层逻辑不变。
避坑指南:我曾经在服务器上用 -preset ultrafast 想加快速度,结果输出文件体积大了 3 倍,码率飙升。后来才明白,ultrafast 适合实时推流,不适合离线转码。离线场景用 medium 或 slow 更合理。
3.3 编译与安装:自己动手,丰衣足食
为什么我要强调自己编译?因为官方预编译包往往缺少一些关键组件,比如:
- 硬件编码器支持(NVENC、AMF、QSV)
- 特定滤镜(比如 AI 模型需要的
dnn_processing) - 第三方库(如 libx265、libvpx)
我个人的建议是:开发环境用包管理器安装,生产环境自己编译。
3.3.1 快速安装(开发用)
# Ubuntu/Debian
sudo apt install ffmpeg ffprobe
# macOS
brew install ffmpeg
# Windows
# 下载 BtbN 的编译包:https://github.com/BtbN/FFmpeg-Builds/releases
3.3.2 完整编译(生产用)
这里我给出一个我常用的编译脚本,支持 NVIDIA 硬件加速和大部分常用编码器:
#!/bin/bash
# 安装依赖
sudo apt update
sudo apt install -y \
build-essential cmake git pkg-config \
libx264-dev libx265-dev libvpx-dev \
libfdk-aac-dev libmp3lame-dev libopus-dev \
libssl-dev libsdl2-dev
# 克隆 FFmpeg 源码
git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg
cd ffmpeg
# 配置(开启 NVIDIA 硬件加速)
./configure \
--enable-gpl \
--enable-nonfree \
--enable-libx264 \
--enable-libx265 \
--enable-libvpx \
--enable-libfdk-aac \
--enable-libmp3lame \
--enable-libopus \
--enable-cuda \
--enable-cuvid \
--enable-nvenc \
--enable-ffnvcodec \
--extra-cflags=-I/usr/local/cuda/include \
--extra-ldflags=-L/usr/local/cuda/lib64
# 编译(使用 8 核加速)
make -j8
# 安装
sudo make install
编译过程中最容易出问题的是依赖缺失。我记得有一次在 CentOS 上编译,缺了 libfdk-aac,结果编译出来的 FFmpeg 不支持 AAC 编码,折腾了我半天才找到原因。
小技巧:编译完成后,用 ffmpeg -encoders | grep nvenc 检查硬件编码器是否生效。如果输出为空,说明 CUDA 路径没配对。
3.4 基本转码流程:从输入到输出
好了,架构懂了,命令会了,编译也搞定了。现在咱们走一遍完整的转码流程。我会用实际项目中的例子来说明。
3.4.1 流程概览
一个标准的转码流程包含 6 个步骤:
- 打开输入文件:ffmpeg 读取容器格式,解析流信息
- 查找解码器:根据流的编码类型,找到对应的解码器
- 解码:将压缩数据解压为原始帧(YUV 或 PCM)
- 滤镜处理:对原始帧进行缩放、裁剪、色彩空间转换等
- 编码:将处理后的原始帧重新压缩
- 写入输出文件:将编码后的数据封装到目标容器中
你想想看,这个流程跟工厂流水线一模一样。每个环节都可以替换组件,比如把软件解码换成硬件解码,或者插入一个 AI 滤镜。
3.4.2 实战:H.264 转 H.265,同时缩放
假设我有一个 4K 的 H.264 视频,想转成 1080p 的 H.265,同时降低码率:
ffmpeg -i input_4k.mp4 \
-vf "scale=1920:1080" \
-c:v libx265 -preset medium -crf 28 \
-c:a copy \
output_1080p_hevc.mp4
解释一下关键点:
-vf "scale=1920:1080":视频滤镜,把分辨率缩到 1080p-c:v libx265:用 H.265 编码器-crf 28:H.265 的 CRF 28 相当于 H.264 的 CRF 23,压缩率更高-c:a copy:音频直接复制,不重新编码(省时间)
经验之谈:我在做视频存档项目时,发现 H.265 的 CRF 28 在 1080p 下,肉眼几乎看不出画质损失,但文件体积只有 H.264 的 40%-50%。如果你对画质要求高,可以降到 CRF 24。
3.4.3 常见问题与排查
转码过程中最容易遇到三个问题:
| 问题 | 现象 | 我的排查方法 |
|---|---|---|
| 编码器不支持 | Unknown encoder 'libx265' | 用 ffmpeg -encoders 检查编译时是否开启了该编码器 |
| 滤镜语法错误 | Error initializing filter 'scale' | 检查滤镜参数格式,用 ffmpeg -filters 查看支持的滤镜 |
| 硬件加速失败 | Device creation failed | 检查驱动版本,用 nvidia-smi 确认 CUDA 可用 |
我曾经在客户现场遇到一个诡异的问题:同样的命令,在开发服务器上跑得好好的,在客户机器上就报编码器不支持。最后发现是客户机器上的 FFmpeg 是包管理器安装的旧版本,没有 libx265 支持。重新编译后问题解决。
重要提醒:生产环境中,永远不要用 ffmpeg -i input.mp4 output.mp4 这种不带任何参数的转码命令。它会使用默认参数,而默认参数往往不是最优的。我见过有人用默认参数转码,结果输出文件比输入还大,画质还变差了。
好了,这一章的内容就到这里。FFmpeg 的核心基础其实就这些:架构是骨架,命令是手脚,编译是准备工作,转码流程是工作流。把这四个点吃透,后面讲 AI 协同处理时,你就能把精力放在算法上,而不是被工具卡住。
下一章,我们会深入滤镜系统,看看怎么用 FFmpeg 的滤镜链来实现 AI 前处理。到时候你会看到,FFmpeg 和 AI 的结合,比想象中要简单得多。