这一篇先解决最常见的文件任务。命令默认输入结构简单;遇到多条视频、音频或字幕时,先看第 04 篇。

先分清:Stream Copy 还是转码

对已选中的压缩音视频流,常见的文件处理有两种方式:

转封装: Packet ── -c copy ──► Muxer(换容器,不改压缩数据)
转码: Packet → Decode → Filter(可选)→ Encode → Muxer
flowchart LR
I[输入文件] --> D[Demuxer<br/>解封装]
D --> P[Packet<br/>压缩数据]
P -->|Stream Copy<br/>-c copy| M[Muxer<br/>重新封装]
P -->|要改画面或编码| DE[Decode]
DE --> F1[Frame]
F1 --> FL[Filter<br/>scale / fps / volume]
FL --> F2[处理后的 Frame]
F2 --> EN[Encode]
EN --> P2[新的 Packet]
P2 --> M
M --> O[输出文件]

-c copy 复制压缩后的 Packet,不会缩放、加水印、调整音量或换编码。这些操作需要对相应的流解码并重新编码。压缩数据本身也可以由 Bitstream Filter 处理,例如转换 H.264 的边界格式,见编码与格式篇。

你想做的事关键配置实际走哪条路
只换容器-c copyPacket → Muxer(Stream Copy)
缩放、裁剪、抽帧-vf + -c:vDecode → Filter → Encode
调整音量-af + -c:a音频 Decode → Filter → Encode;视频未改可 -c:v copy
只要某一类流-map、-an / -vn先选流,再复制或编码

换容器(转封装)

Terminal window
ffmpeg -i input.mkv -c copy output.mp4

FFmpeg 打开 MKV,将自动选中的压缩流写进 MP4(Stream Copy),不会自动保留全部轨道。前提是 MP4 支持选中的编码。失败时先查编码和流类型:

Terminal window
ffprobe -v error -show_entries "stream=index,codec_type,codec_name:format=format_name" -of json input.mkv

不要把改后缀当成换容器。Rename-Item 不会改媒体字节。

基本转码

Terminal window
ffmpeg -i input.mkv -c:v libx264 -c:a aac output.mp4

视频和音频都会解开再重压。编码器名称必须出现在本机 ffmpeg -encoders 里。目标播放器不认当前像素格式或音频参数时,再按第 05 篇补充。

缩放视频

将视频宽度设为 1280,高度按比例计算并取偶数。输入较小时也会放大:

Terminal window
ffmpeg -i input.mp4 -vf "scale=w=1280:h=-2" -c:v libx264 -c:a copy output.mkv
片段它在做什么
scale=...处理解码后的画面,所以视频不能再用 -c:v copy
h=-2按比例算高度,并让结果能被 2 整除,方便常见编码器
-c:a copy声音没改,对该音频做 Stream Copy

如果要放进固定的 1280×720 画布并补黑边,见Filter 篇。force_original_aspect_ratio=decrease 约束的是输出尺寸框,不表示禁止放大小视频。

只要视频、不要音频:

Terminal window
ffmpeg -i input.mp4 -vf "scale=1280:-2" -an -c:v libx264 output.mp4

截取一段视频

官方把 -ss 分成输入选项和输出选项,效果不一样(见 ffmpeg.texi -ss)。

放在 -i 前面(输入选项):在这个输入里 seek。多数格式无法精确落到任意时间,会落到目标前最近的 seek point。

Terminal window
ffmpeg -ss 00:01:00 -i input.mp4 -t 00:00:30 -c copy fast-clip.mp4

和 Stream Copy 一起用时,seek point 到目标之间的数据会保留,所以开头可能比 1 分 00 秒更早,但速度快、不重编码。

放在 -i 后面并转码(输出选项):本例从文件开头解码,丢弃到目标时间戳。输入侧定位后转码也能准确裁剪,不需要为了精确一律从头解码。

Terminal window
ffmpeg -i input.mp4 -ss 00:01:00 -t 00:00:30 -c:v libx264 -c:a aac accurate-clip.mp4
文件时间轴: ----seek point---- 1:00 -------- 1:30 ----
copy 切点: ^从 seek point 开始,前面多出来一截
输出侧 -ss: ^解码丢弃到 1:00

两种写法还需要注意:

  • 若 -ss 放在输入前,但后面是转码,默认开启的 -accurate_seek 会把“seek point 到目标”多出来的那一段解码后丢掉,切点也可以比较准。
  • -t 和 -to 都可以作输入或输出选项。写在 -i 前约束从这个输入读取多久/读到何时;写在输出文件前约束输出。官方规定二者互斥,且 -t 优先;实践中只选一个。

首尾画面和声音仍应实际播放检查。关键帧为什么会挡住 copy 切片,见 码流篇。

提取一张图片

Terminal window
ffmpeg -ss 00:00:10 -i input.mp4 -frames:v 1 -q:v 2 -update 1 snapshot.jpg

-frames:v 1 限制为一帧;-update 1 让 image2 把输出名解释为单个文件名。它本身不会限制帧数,多帧时会反复更新同一文件。没有 -update 1 的单帧输出也可能成功,但会提示缺少序列模式。-q:v 的含义由具体编码器决定,不是统一的百分比画质。

按固定频率抽帧

Terminal window
New-Item -ItemType Directory -Force .\frames | Out-Null
ffmpeg -i input.mp4 -vf "fps=1" .\frames\frame-%05d.jpg

每 10 秒一张:

Terminal window
ffmpeg -i input.mp4 -vf "fps=1/10" .\frames\frame-%05d.jpg

fps=1/10 是 Filter 阶段的时间采样。%05d 只是从 00001 起的文件编号,不是原始时间戳。输入很长时先加 -t,避免一次生成过多图片。

提取音频

把第一条音频重新编码为 AAC:

Terminal window
ffmpeg -i input.mp4 -map 0:a:0 -c:a aac -b:a 192k audio.m4a

源音频本来就是 AAC、目标容器也兼容时,可以直接复制:

Terminal window
ffmpeg -i input.mp4 -map 0:a:0 -c:a copy audio.m4a

有多条音频时,不要假设“第一条就是要的那条”。先用第 02 篇的 ffprobe 看,再用第 04 篇的 -map 指定。

调整音量

音量改的是解码后的采样,必须重新编码音频:

Terminal window
ffmpeg -i input.mp4 -af "volume=1.5" -c:v copy -c:a aac -b:a 128k output.mkv

Filter 只作用在音频上,视频仍可以复制。若目标容器不接受源视频编码,再给视频选编码器。

输出文件的最小验收

每个任务至少做这三步:

Terminal window
ffprobe -v error -show_format -show_streams -of json output.mp4
ffmpeg -v error -i output.mp4 -map 0:v? -map 0:a? -f null -
ffplay output.mp4
检查它能证明什么
ffprobe容器和流结构对不对
映射全部音视频后 -f null -检查整段解码是否报错
ffplay观察画面、声音和切点;交付时还应使用目标播放器

退出码为 0 只说明进程没报失败,不能代替上面三项。

选错音轨、缺少字幕、两个输入合成,进入第 04 篇;要理解参数位置、CRF 和 Filter 组合,进入第 05 篇。

依据:FFmpeg 命令与转码说明、scale、fps、image2。