第三章 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 适合实时推流,不适合离线转码。离线场景用 mediumslow 更合理。

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 个步骤:

  1. 打开输入文件:ffmpeg 读取容器格式,解析流信息
  2. 查找解码器:根据流的编码类型,找到对应的解码器
  3. 解码:将压缩数据解压为原始帧(YUV 或 PCM)
  4. 滤镜处理:对原始帧进行缩放、裁剪、色彩空间转换等
  5. 编码:将处理后的原始帧重新压缩
  6. 写入输出文件:将编码后的数据封装到目标容器中

你想想看,这个流程跟工厂流水线一模一样。每个环节都可以替换组件,比如把软件解码换成硬件解码,或者插入一个 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 的结合,比想象中要简单得多。