FFmpeg 常用命令详解:多媒体处理的瑞士军刀
在数字多媒体领域,FFmpeg 是一个无可争议的强大工具集。它是一个开源项目,包含了一系列用于处理音频、视频和其他多媒体文件的程序库和命令行工具。无论是进行格式转换、编解码、剪辑、合并、流媒体传输,还是进行复杂的滤镜处理,FFmpeg 都能胜任。它因其强大的功能、灵活性和广泛的格式支持而被广泛应用于各种场景,从开发者到视频编辑爱好者,几乎无人不知。
本文将深入探讨 FFmpeg 的常用命令行操作,帮助读者理解其基本结构、核心概念以及如何通过简单的命令完成常见的多媒体处理任务。
FFmpeg 的基本结构
FFmpeg 的命令行工具通常遵循以下基本结构:
bash
ffmpeg [global_options] {[input_options] -i INPUT} ... {[output_options] OUTPUT} ...
理解这个结构至关重要:
ffmpeg
: 这是调用 FFmpeg 程序的命令本身。[global_options]
: 全局选项,影响整个 FFmpeg 进程,例如-y
(覆盖输出文件)、-n
(不覆盖输出文件)、-v
(设置日志级别)等。这些选项通常放在命令的最前面。{[input_options] -i INPUT} ...
: 输入文件部分。-i INPUT
: 指定一个输入文件。一个 FFmpeg 命令可以指定多个输入文件,每个文件前都需要一个-i
。[input_options]
: 针对 特定输入文件 的选项,例如-ss
(设置输入文件的起始时间)等。这些选项必须放在其对应的-i
前面。
{[output_options] OUTPUT} ...
: 输出文件部分。OUTPUT
: 指定一个输出文件的路径和名称。[output_options]
: 针对 特定输出文件 的选项,例如-c:v
(视频编解码器)、-c:a
(音频编解码器)、-vf
(视频滤镜)、-af
(音频滤镜)等。这些选项必须放在其对应的输出文件名称前面。一个命令也可以输出到多个文件。
重要提示: 选项的位置很重要。影响输入的选项通常放在-i
前面,而影响输出的选项通常放在输出文件名称 前面。全局选项放在最前面。
FFmpeg 核心概念及常用选项
在深入具体命令之前,了解几个核心概念和常用选项是基础。
- 流 (Stream): 多媒体文件通常包含多个流,最常见的是视频流、音频流。还可能包含字幕流、数据流等。每个流都有一个索引,通常从 0 开始。例如,第一个输入文件的第一个视频流是
0:v:0
,第一个音频流是0:a:0
。 - 编解码器 (Codec): 用于编码或解码音视频数据的算法。例如,H.264 (libx264)、H.265 (libx265)、VP9 (libvpx-vp9) 是常见的视频编解码器;AAC (aac)、MP3 (libmp3lame)、Opus (libopus) 是常见的音频编解码器。
- 格式 (Format): 文件的容器格式,决定了如何封装音视频流、元数据等。例如,MP4 (
mp4
)、MKV (matroska
)、WebM (webm
)、AVI (avi
) 等。 - 滤镜 (Filter): 用于处理音视频数据的操作,如缩放 (
scale
)、裁剪 (crop
)、旋转 (transpose
)、添加水印 (overlay
)、调整音量 (volume
) 等。滤镜可以单独使用(简单滤镜),也可以组合使用(复杂滤镜,通过-filter_complex
)。
常用选项:
-i <input_file>
: 指定输入文件。-c <codec>
或-codec <codec>
: 指定编解码器。可以使用-c:v <video_codec>
指定视频编解码器,-c:a <audio_codec>
指定音频编解码器,-c:s <subtitle_codec>
指定字幕编解码器。-c copy
: 特殊的编解码器选项,表示直接复制输入流到输出,不进行重新编码。这速度快且无质量损失,但要求输出格式支持输入流的编解码器。-f <format>
: 指定输出文件的格式。FFmpeg 通常能根据文件扩展名自动猜测格式,但有时需要显式指定。-map <input_stream_specifier>
: 选择要包含在输出文件中的输入流。例如,-map 0:v:0
选择第一个输入文件的第一个视频流,-map 0:a:1
选择第一个输入文件的第二个音频流。这在处理包含多个音轨或字幕轨的文件时非常有用。-ss <position>
: 设置开始处理的位置。可以指定时间码(例如00:01:30
或90
)或帧号。如果放在-i
前面,FFmpeg 会快速 seek 到指定位置(可能不够精确,但在关键帧处开始);如果放在-i
后面,FFmpeg 会精确 seek,但需要解码到指定位置,速度较慢。-t <duration>
: 设置处理的持续时间。可以指定时间码或秒数。-to <position>
: 设置结束处理的位置(相对于输入的开始)。-vf <video_filter_graph>
: 应用视频滤镜。-af <audio_filter_graph>
: 应用音频滤镜。-metadata <key>=<value>
: 添加或修改元数据。-vn
: 禁用视频流处理,输出将只有音频。-an
: 禁用音频流处理,输出将只有视频。-sn
: 禁用字幕流处理。-y
: 自动覆盖已存在的输出文件。-n
: 如果输出文件已存在,则不覆盖并退出。-v <level>
: 设置日志级别,如error
,warning
,info
,verbose
,debug
。
常用 FFmpeg 命令示例与详解
接下来,我们将通过具体的命令示例来演示 FFmpeg 的常见用法。
1. 查看媒体文件信息 (使用 ffprobe)
虽然是 FFmpeg 工具集的一部分,但查看文件信息通常使用 ffprobe
命令。
bash
ffprobe input.mp4
详解: 这会打印出 input.mp4
文件的详细信息,包括容器格式、比特率、编码信息、包含的流(视频、音频、字幕等)、每个流的编码器、分辨率、帧率、采样率、声道数、时长、元数据等。这些信息对于后续处理非常重要,可以帮助你确定使用哪些选项。
你也可以指定输出格式,例如输出为 JSON 格式:
bash
ffprobe -v quiet -print_format json -show_streams -show_format input.mp4
详解:
* -v quiet
: 抑制 ffprobe 本身的日志输出。
* -print_format json
: 指定输出格式为 JSON。
* -show_streams
: 显示流的详细信息。
* -show_format
: 显示容器格式的详细信息。
2. 格式转换 (不改变编解码器)
如果只是改变文件的容器格式,同时保持原有的音视频编码不变,可以使用-c copy
选项。这速度快且不会损失质量。
bash
ffmpeg -i input.mp4 -c copy output.mkv
详解:
* -i input.mp4
: 指定输入文件。
* -c copy
: 告诉 FFmpeg 直接复制所有的流(视频、音频、字幕等)到输出文件。
* output.mkv
: 指定输出文件为 MKV 格式。前提是 MKV 容器支持 MP4 中的音视频编码(通常都支持常见的)。
类似的,你可以将 MKV 转为 MP4(如果内部编码兼容 MP4 容器),或者将 WAV 无损转为 FLAC 等。
bash
ffmpeg -i input.mkv -c copy output.mp4 # 如果MKV内部编码兼容MP4
ffmpeg -i input.wav -c copy output.flac # 无损音频格式转换
3. 格式和编解码器转换 (重新编码)
当需要将视频或音频转换为另一种编码格式时,或者目标容器不支持源文件的编码时,就需要进行重新编码。
示例:MP4 (H.264 AAC) 转 WebM (VP9 Opus)
bash
ffmpeg -i input.mp4 -c:v libvpx-vp9 -c:a libopus output.webm
详解:
* -i input.mp4
: 输入 MP4 文件。
* -c:v libvpx-vp9
: 指定视频编解码器为 VP9 (通过 libvpx 库实现)。
* -c:a libopus
: 指定音频编解码器为 Opus (通过 libopus 库实现)。
* output.webm
: 输出 WebM 格式文件。
示例:MP4 (H.264 AAC) 转 AVI (MPEG-4 MP3)
bash
ffmpeg -i input.mp4 -c:v mpeg4 -c:a libmp3lame output.avi
详解:
* -c:v mpeg4
: 指定视频编解码器为 MPEG-4 Part 2 (divx/xvid 类型的编码)。
* -c:a libmp3lame
: 指定音频编解码器为 MP3 (通过 libmp3lame 库实现)。注意,使用 MP3 编码通常需要安装 third-party 库,编译 FFmpeg 时需要启用 --enable-libmp3lame
。
4. 调整视频分辨率 (缩放)
使用 scale
视频滤镜来改变视频的尺寸。
bash
ffmpeg -i input.mp4 -vf scale=640:-1 output_640w.mp4
详解:
* -vf scale=640:-1
: 应用视频滤镜 scale
。scale
滤镜的参数是 width:height
。
* 640
: 将视频宽度设置为 640 像素。
* -1
: 表示自动计算高度,以保持原始的宽高比。这非常有用,可以避免视频变形。
* -c:v libx264 -preset medium -crf 23
: 在缩放的同时进行重新编码。这里使用了 H.264 编码器,并指定了编码质量 (CRF) 和预设 (preset)。通常缩放操作都需要重新编码。如果想保持原有音频编码,可以加上 -c:a copy
。
示例:缩小到宽度为 320,保持宽高比,并将音频也重新编码为 AAC。
bash
ffmpeg -i input.mp4 -vf scale=320:-1 -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k output_320w_reencode_audio.mp4
详解:
* -b:a 128k
: 设置音频比特率为 128 kbps。
5. 裁剪视频 (Cropping)
使用 crop
视频滤镜来裁剪视频画面。
bash
ffmpeg -i input.mp4 -vf crop=w:h:x:y output_cropped.mp4
详解:
* -vf crop=w:h:x:y
: 应用视频滤镜 crop
。
* w
: 输出画面的宽度。
* h
: 输出画面的高度。
* x
: 裁剪区域左上角的 x 坐标(距离左边缘)。
* y
: 裁剪区域左上角的 y 坐标(距离上边缘)。
* 坐标系原点在视频左上角。
示例:从左上角 (100, 50) 开始,裁剪一个 640×480 的区域。
bash
ffmpeg -i input.mp4 -vf crop=640:480:100:50 -c:a copy output_cropped.mp4
详解: 视频会被重新编码,音频被复制。
6. 旋转视频 (Rotating/Flipping)
使用 transpose
视频滤镜来旋转或翻转视频。
bash
ffmpeg -i input.mp4 -vf transpose=1 output_rotated.mp4
详解:
* -vf transpose=<param>
: 应用视频滤镜 transpose
。
* 0
: 顺时针 90 度和垂直翻转。
* 1
: 顺时针 90 度。
* 2
: 逆时针 90 度和垂直翻转。
* 3
: 逆时针 90 度。
示例:顺时针旋转 90 度。
bash
ffmpeg -i input.mp4 -vf transpose=1 -c:a copy output_rotated_90.mp4
7. 剪辑视频 (Trimming/Cutting)
使用 -ss
和 -t
或 -to
选项来剪辑视频。
示例:从第 30 秒开始,截取时长为 10 秒的片段。
bash
ffmpeg -i input.mp4 -ss 30 -t 10 -c copy output_clip.mp4
详解:
* -i input.mp4
: 输入文件。
* -ss 30
: 从输入的第 30 秒开始。这里 -ss
放在 -i
后面,进行精确剪辑(较慢)。如果对精度要求不高,可以放在 -i
前面:ffmpeg -ss 30 -i input.mp4 -t 10 -c copy output_clip_fast.mp4
(这种方式速度快,但可能从 30 秒附近的关键帧开始)。
* -t 10
: 截取从开始时间算起,时长为 10 秒的内容。
* -c copy
: 无损复制音视频流,避免重新编码带来的质量损失和时间消耗。这种方法要求剪辑的起始点和结束点是关键帧,否则可能会出现画面不同步或花屏。对于精确剪辑且不关心重编码耗时,或者需要确保无损剪辑到任意时间点,通常结合重新编码使用。
示例:从 1 分钟 30 秒开始,截取到 2 分钟 0 秒结束。
bash
ffmpeg -i input.mp4 -ss 00:01:30 -to 00:02:00 -c copy output_clip_to.mp4
详解: -to
指定结束时间点。这里 -ss
在 -i
后面,精确剪辑。
示例:精确剪辑,并重新编码。
bash
ffmpeg -i input.mp4 -ss 00:01:30 -to 00:02:00 -c:v libx264 -crf 23 -c:a aac output_clip_reencode.mp4
8. 合并/拼接视频 (Concatenating)
合并视频有两种主要方法:一种是简单合并(要求视频有相同的编解码器、分辨率、帧率等属性),另一种是复杂合并(可以使用滤镜处理不同属性的视频)。
简单合并 (Concat Demuxer): 适用于属性完全相同的视频文件。创建一个文本文件(例如 mylist.txt
),列出要合并的文件路径,每行一个文件,格式为 file 'your_video_file.mp4'
。
mylist.txt
内容示例:
file 'input1.mp4'
file 'input2.mp4'
file 'input3.mp4'
然后使用 FFmpeg 命令:
bash
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output_concat.mp4
详解:
* -f concat
: 指定输入格式为 concat
。
* -safe 0
: 允许文件中包含相对或绝对路径。如果文件列表中的路径包含特殊字符或不是当前目录,可能需要这个选项。
* -i mylist.txt
: 指定包含文件列表的文本文件作为输入。
* -c copy
: 无损复制所有流。
复杂合并 (Concat Filter): 使用 concat
滤镜,可以处理不同属性的视频,FFmpeg 会在合并前进行转码或缩放等处理。这需要使用 -filter_complex
。
bash
ffmpeg -i input1.mp4 -i input2.mp4 -filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0]concat=n=2:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output_complex_concat.mp4
详解:
* -i input1.mp4 -i input2.mp4
: 指定两个输入文件。
* -filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0]concat=n=2:v=1:a=1[outv][outa]"
: 使用复杂滤镜 graph。
* [0:v:0]
: 第一个输入文件的第一个视频流。
* [0:a:0]
: 第一个输入文件的第一个音频流。
* [1:v:0]
: 第二个输入文件的第一个视频流。
* [1:a:0]
: 第二个输入文件的第一个音频流。
* concat=n=2:v=1:a=1
: 应用 concat
滤镜。n=2
表示输入流组数为 2 (每个输入文件一组)。v=1
表示输出一个视频流。a=1
表示输出一个音频流。
* [outv]
: concat
滤镜输出的视频流别名。
* [outa]
: concat
滤镜输出的音频流别名。
* -map "[outv]" -map "[outa]"
: 将滤镜输出的视频流和音频流映射到输出文件。
9. 提取音轨或视频轨
使用 -vn
禁用视频或 -an
禁用音频,并指定目标编码器和格式。
示例:从 MP4 中提取音频为 MP3 格式。
bash
ffmpeg -i input.mp4 -vn -acodec libmp3lame output.mp3
详解:
* -vn
: 不处理视频流。
* -acodec libmp3lame
: 指定音频编码器为 MP3。
示例:从 MP4 中提取视频为 H.264 编码的 MP4 格式 (移除音频)。
bash
ffmpeg -i input.mp4 -an -c:v copy output_video_only.mp4
详解:
* -an
: 不处理音频流。
* -c:v copy
: 复制视频流。
10. 从图片序列创建视频
可以从一系列按顺序命名的图片文件(例如 img001.png
, img002.png
, …)创建视频。
bash
ffmpeg -framerate 25 -i img%03d.png -c:v libx264 -pix_fmt yuv420p output.mp4
详解:
* -framerate 25
: 设置输出视频的帧率为 25 fps。
* -i img%03d.png
: 指定输入文件模式。%03d
表示一个三位数的数字,前面补零。FFmpeg 会查找 img001.png
, img002.png
, … 等文件。
* -c:v libx264
: 指定视频编码器为 H.264。
* -pix_fmt yuv420p
: 指定像素格式。yuv420p
是许多播放器和平台广泛支持的格式,有助于兼容性。
11. 为视频添加水印或叠加图片
使用 overlay
视频滤镜在视频上叠加另一张图片或视频(作为水印)。
bash
ffmpeg -i input.mp4 -i watermark.png -filter_complex "[0:v][1:v]overlay=10:10" output_watermarked.mp4
详解:
* -i input.mp4
: 第一个输入文件(主视频)。
* -i watermark.png
: 第二个输入文件(水印图片)。
* -filter_complex "[0:v][1:v]overlay=10:10"
: 使用复杂滤镜 graph。
* [0:v]
: 第一个输入文件的视频流。
* [1:v]
: 第二个输入文件的视频流 (水印)。
* overlay=10:10
: 将水印叠加到主视频上,左上角坐标为 (10, 10)。
* 视频会被重新编码。音频可以使用 -c:a copy
复制。
12. 调整音频音量
使用 volume
音频滤镜。
bash
ffmpeg -i input.mp4 -af volume=2.0 output_louder.mp4
详解:
* -af volume=2.0
: 应用音频滤镜 volume
,将音量增加到原来的 2 倍。0.5
是减半。
13. 控制输出质量和大小
控制输出视频的质量和文件大小是常见的需求,主要通过比特率或质量参数实现。
-
固定比特率 (CBR) 或平均比特率 (ABR): 使用
-b:v
指定视频比特率,-b:a
指定音频比特率。bash
ffmpeg -i input.mp4 -c:v libx264 -b:v 1000k -c:a aac -b:a 128k output_bitrate.mp4详解:
*-b:v 1000k
: 设置视频比特率为 1000 kbps (1 Mbps)。
*-b:a 128k
: 设置音频比特率为 128 kbps。 -
恒定质量 (CRF – Constant Rate Factor): 对于 H.264 (libx264) 和 H.265 (libx265) 等编码器,CRF 是更推荐的控制质量的方法。较低的 CRF 值意味着更高的质量和更大的文件大小。对于 H.264, CRF 0 是无损, CRF 23 是默认值, CRF 51 是最低质量。
bash
ffmpeg -i input.mp4 -c:v libx264 -crf 20 output_crf20.mp4详解:
*-crf 20
: 设置 CRF 值为 20,比默认的 23 质量更高,文件更大。 -
预设 (Preset): 影响编码速度和压缩效率的权衡。更慢的预设(如
slow
,slower
,veryslow
)可以实现更好的压缩(文件更小,相同质量下),但编码时间更长。更快的预设(如fast
,faster
,veryfast
,superfast
,ultrafast
)编码速度快,但压缩效率较低。bash
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset slow output_preset_slow.mp4详解:
*-preset slow
: 使用slow
预设进行编码。
14. 改变视频帧率
使用 -r
选项来设置输出视频的帧率。
bash
ffmpeg -i input.mp4 -r 30 output_30fps.mp4
详解:
* -r 30
: 将输出视频的帧率设置为 30 帧/秒。如果原始视频帧率不同,FFmpeg 会通过丢弃或复制帧来调整。
15. 添加字幕流
可以将外部字幕文件(如 .srt
, .ass
)添加到视频文件中作为一个独立的流。
bash
ffmpeg -i input.mp4 -i subtitles.srt -map 0 -map 1 -c copy -c:s mov_text output_with_subs.mp4
详解:
* -i input.mp4
: 第一个输入,视频文件。
* -i subtitles.srt
: 第二个输入,字幕文件。
* -map 0
: 包含第一个输入文件 (input.mp4) 的所有流(视频、音频等)。
* -map 1
: 包含第二个输入文件 (subtitles.srt) 的所有流(字幕)。
* -c copy
: 复制视频和音频流。
* -c:s mov_text
: 将字幕流编码为 mov_text
格式,这是 MP4 容器常用的字幕格式。对于 MKV 容器,通常可以直接 -c:s copy
复制 SRT 或 ASS 字幕。
16. 烧录字幕到视频 (硬字幕)
使用 subtitles
或 ass
视频滤镜将字幕直接渲染到视频画面上。
bash
ffmpeg -i input.mp4 -vf subtitles=subtitles.srt -c:a copy output_hardcoded_subs.mp4
详解:
* -vf subtitles=subtitles.srt
: 使用 subtitles
滤镜,将 subtitles.srt
文件中的字幕烧录到视频画面上。这会触发视频的重新编码。
* -c:a copy
: 复制音频流。
高级概念简述
- 滤镜图 (Filtergraphs): 使用
-vf
,-af
应用的是简单滤镜。当需要将多个滤镜链式组合或并行处理,甚至从多个输入生成一个输出时,就需要使用-filter_complex
构建复杂的滤镜图。例如上面的复杂合并和水印叠加就是例子。滤镜图的语法是一个强大的主题,值得深入学习。 - 流选择和映射 (Stream Selection and Mapping): 使用
-map
选项可以精确控制哪些输入流进入输出文件,以及它们的顺序。这对于处理包含多个音轨、字幕轨或者需要从一个文件提取特定流并与另一个文件合并的场景非常重要。 - 流媒体 (Streaming): FFmpeg 可以作为流媒体客户端(接收流)或服务器(发送流)。例如,可以将本地文件推送到 RTMP 服务器 (
-f flv rtmp://server/live/stream_key
),或者生成 HLS/DASH 流。
实用技巧与注意事项
- 使用
ffprobe
查看文件信息: 在处理任何文件之前,先用ffprobe
查看其详细信息,了解其编码、分辨率、帧率、流信息等,这有助于选择正确的命令和选项。 - 注意
-ss
位置: 放在-i
前用于快速但不精确的 seek,放在-i
后用于精确 seek 但较慢。 - 理解
-c copy
的局限性: 并非所有格式转换或剪辑都可以使用-c copy
。如果目标容器不支持源流的编码,或者需要进行滤镜处理、精确剪辑,则必须重新编码。 - 文件名中的特殊字符: 如果文件名包含空格或特殊字符,请用单引号或双引号将文件名括起来。
- 性能与质量的权衡: 重新编码是一个计算密集型任务。使用更慢的预设、更低的 CRF 值或更高的比特率可以提高质量,但会显著增加处理时间。根据你的需求找到平衡点。
- 查看帮助: FFmpeg 的文档非常详尽。可以通过
ffmpeg -h
查看基本帮助,ffmpeg -h full
查看所有选项,ffmpeg -encoders
,ffmpeg -decoders
,ffmpeg -formats
,ffmpeg -filters
查看支持的编码器、解码器、格式和滤镜列表。 - 逐步构建复杂命令: 对于复杂的任务,先从简单的命令开始,逐步添加选项和滤镜,测试每一步的结果。
结论
FFmpeg 是一个极其强大和灵活的多媒体处理工具。通过掌握其基本的命令行结构和常用选项,你可以完成绝大多数常见的音视频处理任务,如格式转换、剪辑、合并、缩放、加水印等。对于更高级的应用,如复杂的滤镜组合、流媒体推拉流等,FFmpeg 也提供了丰富的选项和强大的滤镜系统来支持。
本文只是 FFmpeg 庞大功能的冰山一角。但通过对这些常用命令的深入理解和实践,你已经迈出了高效进行多媒体处理的重要一步。随着经验的积累和对 FFmpeg 文档的进一步探索,你将能够驾驭这个“瑞士军刀”,解决各种复杂的多媒体挑战。不断尝试、学习新的滤镜和选项,你将发现 FFmpeg 的无限可能。