FFmpeg 多媒体处理教程 / 转码技术
转码技术
概述
转码(Transcoding)是 FFmpeg 最核心的功能之一,指将视频或音频从一种编码格式转换为另一种编码格式的过程。本章详细介绍编解码器选择、质量控制、码率设置等转码技术。
转码基础
转码流程
输入文件 → 解封装 → 解码 → 处理 → 编码 → 封装 → 输出文件
│ │ │ │ │ │ │
│ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼
MP4 Demuxer Decoder Filter Encoder Muxer MKV
复制 vs 转码
| 方式 | 命令 | 优点 | 缺点 |
|---|---|---|---|
| 复制 | -c copy | 速度快、无质量损失 | 不能改变编解码参数 |
| 转码 | -c:v libx264 | 可调整参数 | 速度慢、有质量损失 |
# 复制流(不重新编码)
ffmpeg -i input.mp4 -c copy output.mkv
# 转码(重新编码)
ffmpeg -i input.mp4 -c:v libx264 -c:a aac output.mkv
编解码器选择
视频编解码器对比
| 编解码器 | 类型 | 压缩率 | 速度 | 兼容性 | 适用场景 |
|---|---|---|---|---|---|
| libx264 | H.264 | 高 | 中 | 极好 | 通用视频 |
| libx265 | H.265 | 极高 | 慢 | 好 | 4K/8K 视频 |
| libvpx-vp9 | VP9 | 高 | 慢 | 好 | Web 视频 |
| libaom-av1 | AV1 | 极高 | 极慢 | 中 | 未来格式 |
| libsvtav1 | SVT-AV1 | 极高 | 中 | 中 | 批量 AV1 |
| h264_nvenc | H.264 | 中 | 极快 | 极好 | 实时处理 |
| hevc_nvenc | H.265 | 高 | 极快 | 好 | GPU 加速 |
# 使用 H.264
ffmpeg -i input.mp4 -c:v libx264 -preset medium -crf 23 output.mp4
# 使用 H.265
ffmpeg -i input.mp4 -c:v libx265 -preset medium -crf 28 output.mp4
# 使用 VP9
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 output.webm
# 使用 AV1
ffmpeg -i input.mp4 -c:v libaom-av1 -crf 30 -b:v 0 -cpu-used 4 output.mkv
音频编解码器对比
| 编解码器 | 类型 | 质量 | 速度 | 兼容性 | 适用场景 |
|---|---|---|---|---|---|
| aac | AAC | 高 | 快 | 极好 | 通用音频 |
| libfdk-aac | AAC | 极高 | 快 | 极好 | 高质量音频 |
| libmp3lame | MP3 | 中 | 快 | 极好 | 兼容性需求 |
| libopus | Opus | 极高 | 快 | 好 | 低延迟音频 |
| libvorbis | Vorbis | 高 | 快 | 好 | 开源格式 |
| flac | FLAC | 无损 | 快 | 好 | 无损音频 |
# 使用 AAC
ffmpeg -i input.wav -c:a aac -b:a 192k output.m4a
# 使用 libfdk-aac(更高质量)
ffmpeg -i input.wav -c:a libfdk-aac -b:a 192k output.m4a
# 使用 MP3
ffmpeg -i input.wav -c:a libmp3lame -q:a 2 output.mp3
# 使用 Opus
ffmpeg -i input.wav -c:a libopus -b:a 128k output.opus
# 使用 FLAC(无损)
ffmpeg -i input.wav -c:a flac output.flac
质量控制
CRF(恒定质量因子)
CRF(Constant Rate Factor)是最推荐的质量控制方式,它在保证视觉质量的同时最小化文件大小。
CRF 值范围:
| 编解码器 | 范围 | 推荐值 | 说明 |
|---|---|---|---|
| libx264 | 0-51 | 18-23 | 值越小质量越高 |
| libx265 | 0-51 | 22-28 | 值越小质量越高 |
| libvpx-vp9 | 0-63 | 30-35 | 值越小质量越高 |
| libaom-av1 | 0-63 | 25-35 | 值越小质量越高 |
# 高质量(大文件)
ffmpeg -i input.mp4 -c:v libx264 -crf 18 output.mp4
# 标准质量(推荐)
ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4
# 低质量(小文件)
ffmpeg -i input.mp4 -c:v libx264 -crf 28 output.mp4
# H.265 CRF(推荐值略高于 H.264)
ffmpeg -i input.mp4 -c:v libx265 -crf 28 output.mp4
CRF 与视觉质量对应:
| CRF 范围 | 视觉质量 | 适用场景 |
|---|---|---|
| 0-17 | 无损/近无损 | 存档、后期制作 |
| 18-22 | 高质量 | 高清视频、蓝光 |
| 23-27 | 标准质量 | 网络视频、日常使用 |
| 28-32 | 中等质量 | 移动设备、带宽受限 |
| 33-51 | 低质量 | 预览、草稿 |
预设(Preset)
预设控制编码速度和压缩效率的平衡:
| 预设 | 速度 | 压缩效率 | 适用场景 |
|---|---|---|---|
| ultrafast | 最快 | 最低 | 实时编码 |
| superfast | 很快 | 很低 | 快速预览 |
| veryfast | 快 | 低 | 日常使用 |
| faster | 较快 | 较低 | 快速编码 |
| fast | 快 | 中 | 一般用途 |
| medium | 中 | 中 | 默认设置 |
| slow | 慢 | 高 | 高质量 |
| slower | 很慢 | 很高 | 存档 |
| veryslow | 最慢 | 最高 | 最高质量 |
# 使用 ultrafast 预设
ffmpeg -i input.mp4 -c:v libx264 -preset ultrafast output.mp4
# 使用 medium 预设(默认)
ffmpeg -i input.mp4 -c:v libx264 -preset medium output.mp4
# 使用 slow 预设
ffmpeg -i input.mp4 -c:v libx264 -preset slow output.mp4
Tune 参数
Tune 参数用于针对特定内容优化:
| Tune | 说明 | 适用场景 |
|---|---|---|
| film | 电影内容 | 电影、电视剧 |
| animation | 动画内容 | 动画片、卡通 |
| grain | 胶片颗粒 | 老电影、胶片 |
| stillimage | 静态图像 | 幻灯片 |
| fastdecode | 快速解码 | 低端设备 |
| zerolatency | 零延迟 | 直播、实时 |
# 电影优化
ffmpeg -i input.mp4 -c:v libx264 -preset slow -tune film output.mp4
# 动画优化
ffmpeg -i input.mp4 -c:v libx264 -preset slow -tune animation output.mp4
# 零延迟(直播)
ffmpeg -i input.mp4 -c:v libx264 -preset ultrafast -tune zerolatency output.mp4
Profile 和 Level
Profile 定义编码特性集合,Level 定义性能限制:
H.264 Profile:
| Profile | 特性 | 兼容性 | 适用场景 |
|---|---|---|---|
| baseline | 基础特性 | 最好 | 移动设备 |
| main | 主要特性 | 好 | 标清视频 |
| high | 高级特性 | 好 | 高清视频 |
H.264 Level:
| Level | 最大分辨率 | 最大帧率 | 最大码率 |
|---|---|---|---|
| 3.0 | 720×480 | 30fps | 10Mbps |
| 3.1 | 1280×720 | 30fps | 14Mbps |
| 4.0 | 1920×1080 | 30fps | 20Mbps |
| 4.1 | 1920×1080 | 30fps | 50Mbps |
| 5.0 | 1920×1080 | 60fps | 25Mbps |
| 5.1 | 1920×1080 | 60fps | 50Mbps |
# 基线配置(移动设备)
ffmpeg -i input.mp4 -c:v libx264 -profile:v baseline -level 3.0 output.mp4
# 主配置(标清)
ffmpeg -i input.mp4 -c:v libx264 -profile:v main -level 3.1 output.mp4
# 高配置(高清)
ffmpeg -i input.mp4 -c:v libx264 -profile:v high -level 4.1 output.mp4
码率控制
固定码率(CBR)
# 固定视频码率
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M output.mp4
# 固定音频码率
ffmpeg -i input.mp4 -c:a aac -b:a 128k output.mp4
# 固定总码率
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -c:a aac -b:a 128k output.mp4
可变码率(VBR)
# 使用 CRF 模式(推荐)
ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4
# 使用 CQ 模式(硬件编码器)
ffmpeg -i input.mp4 -c:v h264_nvenc -cq 23 output.mp4
# 使用 QP 模式
ffmpeg -i input.mp4 -c:v libx264 -qp 23 output.mp4
码率限制
# 设置最大码率
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -maxrate 2.5M -bufsize 5M output.mp4
# 使用 VBV 模型(流媒体推荐)
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -maxrate 2M -bufsize 4M output.mp4
码率推荐
按分辨率推荐码率:
| 分辨率 | H.264 码率 | H.265 码率 | VP9 码率 |
|---|---|---|---|
| 480p | 1-2 Mbps | 0.5-1 Mbps | 0.5-1 Mbps |
| 720p | 2-4 Mbps | 1-2 Mbps | 1-2 Mbps |
| 1080p | 4-8 Mbps | 2-4 Mbps | 2-4 Mbps |
| 1440p | 8-12 Mbps | 4-8 Mbps | 4-8 Mbps |
| 4K | 15-30 Mbps | 8-15 Mbps | 8-15 Mbps |
两遍编码
原理
两遍编码(Two-Pass Encoding)通过两次扫描视频来优化码率分配:
- 第一遍:分析视频内容,生成统计信息
- 第二遍:根据统计信息分配码率
使用方法
# 两遍编码(第一遍)
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 1 -an -f null /dev/null
# 两遍编码(第二遍)
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 2 -c:a aac -b:a 128k output.mp4
完整两遍编码脚本
#!/bin/bash
# two_pass_encode.sh
INPUT=$1
OUTPUT=$2
VIDEO_BITRATE=${3:-2M}
AUDIO_BITRATE=${4:-128k}
# 第一遍
ffmpeg -y -i "$INPUT" \
-c:v libx264 \
-b:v "$VIDEO_BITRATE" \
-pass 1 \
-an \
-f null /dev/null
# 第二遍
ffmpeg -y -i "$INPUT" \
-c:v libx264 \
-b:v "$VIDEO_BITRATE" \
-pass 2 \
-c:a aac \
-b:a "$AUDIO_BITRATE" \
"$OUTPUT"
# 清理临时文件
rm -f ffmpeg2pass-0.log ffmpeg2pass-0.log.mbtree
echo "编码完成: $OUTPUT"
两遍编码 vs CRF
| 方面 | 两遍编码 | CRF |
|---|---|---|
| 码率控制 | 精确控制目标码率 | 无法精确控制 |
| 质量 | 均匀质量分布 | 可能不均匀 |
| 速度 | 两倍时间 | 单次处理 |
| 适用场景 | 带宽限制严格 | 质量优先 |
高级转码技巧
分辨率调整
# 缩放到 720p
ffmpeg -i input.mp4 -vf scale=1280:720 -c:v libx264 -c:a copy output.mp4
# 保持宽高比
ffmpeg -i input.mp4 -vf "scale=1280:720:force_original_aspect_ratio=decrease" -c:v libx264 output.mp4
# 填充黑边
ffmpeg -i input.mp4 -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" -c:v libx264 output.mp4
帧率调整
# 降低帧率
ffmpeg -i input.mp4 -vf fps=24 -c:v libx264 output.mp4
# 提高帧率(不推荐)
ffmpeg -i input.mp4 -vf fps=60 -c:v libx264 output.mp4
# 去除重复帧
ffmpeg -i input.mp4 -vf "fps=fps=source_fps:round=near" -c:v libx264 output.mp4
像素格式转换
# 转换为 yuv420p(兼容性最好)
ffmpeg -i input.mp4 -pix_fmt yuv420p -c:v libx264 output.mp4
# 转换为 yuv422p10le(10bit)
ffmpeg -i input.mp4 -pix_fmt yuv422p10le -c:v libx265 -profile:v main10 output.mp4
HDR 到 SDR 转换
# HDR 到 SDR 色调映射
ffmpeg -i input_hdr.mp4 -vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" -c:v libx264 output_sdr.mp4
质量对比脚本
#!/bin/bash
# compare_quality.sh
INPUT=$1
# 不同 CRF 值编码
for crf in 18 20 22 24 26 28 30; do
ffmpeg -y -i "$INPUT" -c:v libx264 -crf "$crf" -preset slow "output_crf${crf}.mp4"
# 计算 PSNR
ffmpeg -i "$INPUT" -i "output_crf${crf}.mp4" -lavfi psnr -f null - 2>&1 | grep PSNR
# 显示文件大小
ls -lh "output_crf${crf}.mp4" | awk '{print $5}'
done
批量转码
批量转码脚本
#!/bin/bash
# batch_transcode.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
CODEC=${3:-libx264}
CRF=${4:-23}
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file")
output="$OUTPUT_DIR/${filename%.mp4}_transcoded.mp4"
echo "转码: $file -> $output"
ffmpeg -y -i "$file" -c:v "$CODEC" -crf "$CRF" -c:a aac -b:a 128k "$output"
done
echo "批量转码完成"
并行转码
#!/bin/bash
# parallel_transcode.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-output}
MAX_JOBS=${3:-4}
mkdir -p "$OUTPUT_DIR"
transcode() {
local file=$1
local filename=$(basename "$file")
local output="$OUTPUT_DIR/${filename%.mp4}_transcoded.mp4"
ffmpeg -y -i "$file" -c:v libx264 -crf 23 -c:a aac -b:a 128k "$output"
echo "完成: $filename"
}
export -f transcode
export OUTPUT_DIR
find "$INPUT_DIR" -name "*.mp4" -print0 | xargs -0 -P "$MAX_JOBS" -I {} bash -c 'transcode "$@"' _ {}
echo "并行转码完成"
常见转码场景
场景 1:Web 视频优化
# 为 Web 播放优化
ffmpeg -i input.mp4 \
-c:v libx264 \
-preset slow \
-crf 23 \
-profile:v high \
-level 4.1 \
-movflags +faststart \
-c:a aac \
-b:a 128k \
output_web.mp4
场景 2:移动设备兼容
# 移动设备兼容格式
ffmpeg -i input.mp4 \
-c:v libx264 \
-profile:v baseline \
-level 3.0 \
-vf scale=640:480 \
-c:a aac \
-b:a 96k \
-ar 44100 \
-ac 2 \
output_mobile.mp4
场景 3:4K 视频压缩
# 4K 视频压缩
ffmpeg -i input_4k.mp4 \
-c:v libx265 \
-preset slow \
-crf 26 \
-tag:v hvc1 \
-c:a aac \
-b:a 192k \
output_4k_compressed.mp4
场景 4:直播转码
# 低延迟直播转码
ffmpeg -re -i input.mp4 \
-c:v libx264 \
-preset ultrafast \
-tune zerolatency \
-b:v 2M \
-maxrate 2M \
-bufsize 4M \
-c:a aac \
-b:a 128k \
-f flv rtmp://server/live/stream
场景 5:存档级转码
# 高质量存档
ffmpeg -i input.mp4 \
-c:v libx264 \
-preset veryslow \
-crf 18 \
-profile:v high \
-c:a flac \
output_archive.mkv
注意事项
- 编解码器选择:H.264 兼容性最好,H.265 压缩率更高但兼容性稍差
- CRF 值选择:不同编解码器的 CRF 值不能直接对比
- 预设选择:预设越慢质量越好,但编码时间越长
- 两遍编码:需要精确码率控制时使用两遍编码
- 硬件加速:GPU 编码速度快但质量略低于 CPU 编码
扩展阅读
- FFmpeg H.264 编码指南
- FFmpeg H.265 编码指南
- FFmpeg VP9 编码指南
- FFmpeg AV1 编码指南
- Video Encoding Settings for Top UGC Platforms
总结
本章介绍了 FFmpeg 的转码技术,包括:
- 编解码器选择
- 质量控制(CRF、预设、Tune)
- 码率控制(CBR、VBR)
- 两遍编码
- 高级转码技巧
- 批量转码方法
掌握这些技术可以帮助您在不同场景下选择合适的转码策略。