0%

FFmpeg 实用指南

FFmpeg 实用指南

视频太大,需要压缩后再发送;录屏太长,只想保留其中一段;想给教程加上字幕,或把几个片段拼成一个文件。这些日常的音视频处理需求,都可以用 FFmpeg 完成。

FFmpeg 是一个开源、跨平台的音视频处理项目,提供转码、剪切、缩放、音频提取等功能。它既可以通过命令行使用,也被许多图形界面工具用于实际处理音视频。将操作写成命令后,同样的处理过程可以重复执行,也方便放进脚本里批量运行。

不过,无论使用命令行还是图形界面,都需要理解一些基本概念:换成 MP4 为什么不一定能缩小文件?什么时候可以直接复制音视频,什么时候必须重新编码?CRF 和编码预设又会怎样影响画质、体积与处理时间?弄清这些问题,才能根据素材和用途选择参数,减少没有方向的反复尝试。

本文从编码与容器的区别讲起,介绍 Windows 下的安装方法、媒体信息查看和命令结构,再通过转码压缩、片段截取、水印、字幕、拼接与变速等常用操作,说明命令该怎么写、参数该怎么改,以及使用时需要注意哪些条件。

一、先分清编码、编码器和容器

1. H.264 与 MP4 描述的是不同东西

看 B 站视频时,可能会遇到 AVC、HEVC、AV1 这些名称:

播放器中的视频编码信息

它们是视频编码标准,规定画面数据如何编码、如何解码还原。AVC 也叫 H.264,HEVC 也叫 H.265。不同标准在压缩效率、处理开销和设备支持上各有差异,不能只凭编码名称判断某个视频更清晰或更小。

MP4、MKV 是容器格式,负责把视频、音频、字幕等内容组织在一个文件里。其中一条独立的视频、音频或字幕数据,称为一条“流”。同样是 MP4 文件,里面可能是 H.264 视频,也可能是 HEVC 视频,因此后缀不能说明全部播放要求。

编码器则是实际执行编码的软件或硬件实现。在 FFmpeg 命令里,libx264 是生成 H.264 视频的编码器,libx265 用于生成 HEVC 视频。本文主要使用 libx264。

名称 属于哪一类 在本文中的作用
H.264 / AVC 视频编码标准 输出视频采用的编码
libx264 编码器 把画面编码为 H.264
AAC 音频编码 常与 H.264 一起用于 MP4 文件
MP4、MKV 容器格式 存放音视频流等内容

硬件编码也是编码器的一种实现。例如,h264_nvenc 可以调用 NVIDIA GPU 的硬件编码能力来生成 H.264 视频,是否可用取决于显卡、驱动和 FFmpeg 构建。播放时的硬件解码与导出时的硬件编码是两种能力,需要分别确认。

2. 改后缀、换容器和压缩视频有什么区别

直接改文件后缀,不会改变文件内部结构。用 FFmpeg 换容器时,如果直接复制原有音视频数据,通常处理很快,也不会因重新编码损失画质,但文件体积一般不会明显减小。

压缩视频通常需要重新编码。文件体积主要取决于时长和平均总码率,忽略封装开销后,可以这样估算:

文件体积(字节)≈ 时长(秒)× 平均总码率(比特/秒)÷ 8

例如,60 秒的视频,音视频平均总码率为 8 Mb/s,体积约为 60 MB。分辨率只表示画面的像素尺寸,不能单独决定体积或清晰度;把模糊视频放大到 1080p,也不会补回丢失的细节。

所以,处理前先明确目的:只是更换容器,可以尝试流复制;需要提高播放兼容性或缩小体积,再考虑重新编码。

二、安装 FFmpeg,并查看素材信息

1. Windows 安装

FFmpeg 官方只提供源代码,不直接提供编译好的 Windows 可执行程序。普通用户无需自行编译,可以下载第三方提供的预编译版本。

打开 FFmpeg 下载页,找到 Windows EXE Files 栏目,通过其中的链接进入 gyan.dev 或 BtbN,下载适合自己系统的静态构建版本并解压。后续使用的是压缩包中的 ffmpeg.exe 和 ffprobe.exe。

FFmpeg 下载页的 Windows 构建入口

我习惯把个人命令行工具统一放在 %USERPROFILE%\.local\bin。其中 %USERPROFILE% 表示当前用户的主目录,例如 C:\Users\chris;.local\bin 是自己创建的工具目录,在 Windows 中没有特殊作用。

  1. 创建这个目录,把静态构建包 bin 目录中的 ffmpeg.exe 和 ffprobe.exe 放进去。如果下载的是 shared 构建,需要连同依赖的 DLL 一起保留。
  2. 打开“系统属性 → 高级 → 环境变量”,编辑用户变量中的 Path,添加 %USERPROFILE%\.local\bin。这里填写程序所在目录,不是某个 .exe 的路径。
  3. 保存后重新打开终端,运行下面两条命令:
1
2
ffmpeg -version
ffprobe -version

能显示版本信息,就说明终端可以找到程序。若提示找不到命令,先检查文件位置与 Path 设置。

后面的操作都在素材文件夹中执行。

可以在文件资源管理器中打开该文件夹,在地址栏输入 powershell 并回车,或者直接右键选择打开”PowerShell”

文件名包含空格时,用双引号包住,例如 "my video.mp4";输出另取一个文件名。

2. 先看文件里有什么

转码前先确认素材的编码、分辨率和音轨,避免只看扩展名就决定处理方式。ffprobe 专门用来查看这些信息:

1
ffprobe -v error -show_format -show_streams input.mp4

-show_format 显示容器、时长等整体信息,-show_streams 显示每条流的参数;-v error 隐藏普通日志,保留错误信息。

开始时重点看 codec_name(编码)、codec_type(流类型)、width / height(视频宽高)、duration(时长)和音轨语言标签即可。

也可以用 ffmpeg -i input.mp4 查看信息。下面的截图展示了另一种输出形式:

截图中的信息 含义
Input #0 第一个输入文件
Duration: 00:33:17.33 时长为 33 分 17.33 秒
Stream #0:0、HEVC 第一条流是 HEVC 视频
3840x2160、60 fps 4K UHD 分辨率,显示帧率为 60 帧/秒
yuv420p10le 10 位色深、4:2:0 色度采样
bt2020nc/bt2020/smpte2084 BT.2020 与 PQ 色彩标记,涉及 HDR
Stream #0:1、AAC 第二条流是 AAC 音频

这张截图中的素材带有 HDR 色彩标记,后文的普通 SDR 转码命令不能直接当作它的 HDR 转 SDR 方案。保留 HDR 或转换为 SDR,都需要另外处理色彩设置。

只运行 ffmpeg -i input.mp4 而不指定输出,最后会提示 At least one output file must be specified。它表示缺少输出文件,不表示素材损坏。日常查看信息,使用上面的 ffprobe 命令更直接。

常用查看参数选择

1
ffprobe -hide_banner .\input.mp4

三、看懂命令的三个部分

对于本文的单输入、单输出操作,命令结构可以写成:

1
ffmpeg [输入选项] -i 输入文件 [选流和处理选项] 输出文件

这是结构示意,不能直接执行。阅读时依次看:读取哪个文件、保留哪些流、如何处理后写入输出。

1. 用 -i 指定输入,用 -map 选择内容

-i 后面是输入文件,输出文件写在命令末尾。如果有多个输入,每个输入都要写 -i,并按出现顺序从 0 开始编号。

-map 决定哪些流进入输出。例如,-map 0:a:1 表示“第一个输入文件中的第二条音轨”:第一个 0 是输入文件编号,a 表示音频,最后的 1 是音频内部编号。

常见写法 选择的内容
-map 0:v:0 第一个输入中的第一条视频流
-map 0:a:0? 第一个输入中的第一条音轨,没有则跳过
-map 0:a 第一个输入中的全部音轨
-map 0 第一个输入中的全部流

-map 0:a:0? 末尾的 ? 表示:如果第一个输入文件有音轨,就选择其中的第一条;如果没有音轨,就跳过这一项,不因缺少音轨而报错。去掉 ? 后,找不到这条音轨就会报错。

例如,-map 0:v:0 -map 0:a:0? 将两项选择组合起来:第一项选择第一条视频流,第二项选择第一条音轨。有音轨就一并输出,没有音轨就只输出视频。第一项没有加 ?,因此输入文件必须包含视频流。

? 只影响对应的这项选流操作。文件无法打开、输入文件编号写错,或所选编码无法写入目标容器时,仍然会报错。

全部流的编号与音频内部的编号要分清。 假设 Stream #0:0 是视频,Stream #0:1、Stream #0:2 是两条音轨,那么 -map 0:1 选择第一条音轨,-map 0:a:1 选择第二条音轨。

不写 -map 时,FFmpeg 会按规则自动选流,并不等于保留全部内容。后面的示例会明确选择第一条视频和第一条音轨,其他音轨、字幕等流不在保留范围内。

2. 用 -c 决定复制还是重新编码

选好流后,-c 决定如何处理它们,:v 和 :a 分别限定视频与音频。

写法 处理方式
-c copy 复制所有已选中的流,不重新编码
-c:v copy 复制已选中的视频流
-c:a copy 复制已选中的音频流
-c:v libx264 将视频编码为 H.264
-c:a aac 将音频编码为 AAC

-map 与 -c 分工不同:-c copy 不会自动选中全部音轨,-c:v copy 也不会自动删除声音。未指定编码方式的流,还可能使用输出格式的默认编码器,不能理解为自动复制。

视频和音频可以分别处理。例如,缩放画面时视频需要重新编码,未修改的音频仍可复制;只调整音频时,也可以保留原视频数据。

3. 参数位置有作用范围

输入选项放在对应的 -i 前,输出选项放在输出文件名前。后文的 -map、-c:v、-c:a 都用于输出,因此放在输入文件之后。

例如,把 -c:v libx264 移到 -i 前,就会变成指定输入解码器,含义已经改变。命令可以调整同一作用范围内的参数顺序,但不能随意跨越输入和输出的边界。

四、十二类常用操作

以下涉及视频重新编码和截图的示例,按普通 SDR 素材编写。除编码方案对照外,其余视频重新编码示例主要使用 H.264 与 yuv420p;音频根据操作需要直接复制或转为 AAC。具体参数仍需结合素材和播放设备调整。

1. 换容器:MKV 转 MP4

原来的音视频编码已经适合播放,只想换成 MP4 容器,可以直接复制:

第一步:查看轨道信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ffprobe -hide_banner .\input.mp4

# 返回
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '.\input.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomav01iso2mp41
encoder : Lavf59.16.100
description : Packed by Bilibili XCoder v2.0.2
Duration: 02:13:59.62, start: 0.000000, bitrate: 917 kb/s
Stream #0:0[0x1](und): Video: av1 (libdav1d) (Main) (av01 / 0x31307661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 744 kb/s, 60 fps, 60 tbr, 16k tbn (default)
Metadata:
handler_name : VideoHandler
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 161 kb/s (default)
Metadata:
handler_name : SoundHandler

这里有一个误区,千万不要混淆了“全部流的编号”和“音频内部的编号”。

我的文件里有两条流:

日志显示 内容 按全部流编号选择 按类型选择
Stream #0:0 第一条视频 -map 0:0 -map 0:v:0
Stream #0:1 第一条音频 -map 0:1 -map 0:a:0

加了 a,最后的数字就只在音频流中计数,而且从 0 开始。 所以:

  • -map 0:1:选择第一个输入中的第 2 条流,这里是 AAC 音频。
  • -map 0:a:0:选择第一个输入中的第 1 条音轨,也是这条 AAC 音频。
  • -map 0:a:1:选择第 2 条音轨,我的文件里不存在。

第二步:转换

1
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:0? -c copy -movflags +faststart remux.mp4

这条命令保留第一条视频和第一条音轨,不重新编码。前提是 MP4 支持所选流的编码;如果播放器不支持原视频编码,仅换容器仍无法解决,需要转码。

-c copy:直接复制音视频,速度快,不会因重新编码损失画质或音质。

-movflags +faststart:将 MP4 索引移到文件前部,便于边下载边播放。

MP4 的 moov 部分保存了轨道信息和定位音视频数据所需的索引,通常在文件写完后位于末尾。加上这个参数,FFmpeg 会在封装完成后把它移到文件前部,方便播放器在文件尚未下载完整时获取索引并开始播放。

它不会重新编码,不改变画质或音质,也不用于压缩体积;会增加一次文件整理的时间。这里的“second pass”是移动索引,不是两遍编码。

本地播放通常不必加;准备通过网页下载播放或分享 MP4 时,加上更有意义

2. 转码与压缩:先确定一组基础参数

下面是普通 SDR 视频转为 H.264+AAC+MP4的通用基础方案

1
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:0? -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -c:a aac -b:a 128k -movflags +faststart output.mp4

视频使用 libx264 编码,音频转为 AAC。

注意:原音频已经是适合 MP4 的 AAC 时,可以考虑 -c:a copy,避免再次有损压缩

-pix_fmt yuv420p 指定常见像素格式;-movflags +faststart 将 MP4 索引移到文件前部,便于边下载边播放。

如果主要目的是压缩,仍然使用这条命令,先调整 -crf 即可,不需要另记一套写法。

参数 怎样调整
-crf 23 对 libx264,数值越大通常文件越小、细节损失越多。可以先试 23,更在意体积时试 28,再比较效果
-preset medium 控制编码速度与压缩效率的取舍。需要更快可试 fast,愿意多花时间可试 slow
-b:a 128k 设置音频目标码率,音乐或多声道素材需要按需求调整

CRF(Constant Rate Factor,恒定码率因子)按质量目标控制压缩,并不固定每秒的数据量。编码器会根据画面内容分配码率:静止、简单的画面通常需要较少数据,运动、纹理复杂的画面则需要更多。因此,同一个 CRF 不保证不同素材的输出体积相同,不同编码器的 CRF 数值也不能直接比较。

CRF 和 preset 控制的是不同方面。以 libx264 为例,CRF 主要决定质量取舍;preset 则决定编码器采用哪些分析方法,以及为此花多少计算时间。画质不满意时,先调整 CRF;编码太慢时,再尝试更快的 preset。较慢的预设通常有助于提高压缩效率,但不保证同一 CRF 下文件一定更小,仍需结合素材比较。

先选一小段素材试编码,再决定是否处理全片。比较参数时,始终使用同一段原始素材,每次只改一个参数,同时记录输出体积和处理时间。先按正常速度观看,再暂停检查文字、运动边缘和暗部细节。不要拿上一次压缩后的文件继续试,否则会混入重复有损编码的影响,也难以判断差异究竟来自哪个参数。

原文件已经压得很小时,再编码甚至可能变大。如果有严格的文件大小上限,需要根据时长分配码率,不能只靠 CRF。

关键总结

以下均面向普通 SDR 视频,质量参数作为试编码起点。

CPU 软件编码

1. H.265(HEVC)+AAC+MP4

1
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:0? -c:v libx265 -crf 24 -preset medium -pix_fmt yuv420p10le -tag:v hvc1 -c:a aac -b:a 128k -movflags +faststart cpu_hevc.mp4

2. AV1+AAC+MP4

1
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:0? -c:v libsvtav1 -crf 30 -preset 6 -pix_fmt yuv420p10le -c:a aac -b:a 128k -movflags +faststart cpu_av1.mp4

3. H.264(AVC)+AAC+MP4

1
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:0? -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -c:a aac -b:a 128k -movflags +faststart cpu_h264.mp4

NVIDIA 硬件编码(以 RTX 4070 Ti 为例)需要 FFmpeg 构建包含对应的 NVENC 编码器,并安装兼容的 NVIDIA 驱动。不同显卡支持的编码格式不同,使用 AV1 前应确认显卡支持 AV1 硬件编码。

4. H.265(HEVC)+AAC+MP4

1
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:0? -c:v hevc_nvenc -preset p7 -rc vbr -cq 30 -pix_fmt p010le -tag:v hvc1 -c:a aac -b:a 128k -movflags +faststart nvenc_hevc.mp4

5. AV1+AAC+MP4

1
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:0? -c:v av1_nvenc -preset p7 -rc vbr -cq 36 -pix_fmt p010le -c:a aac -b:a 128k -movflags +faststart nvenc_av1.mp4

6. H.264(AVC)+AAC+MP4

1
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:0? -c:v h264_nvenc -preset p7 -rc vbr -cq 23 -pix_fmt yuv420p -c:a aac -b:a 128k -movflags +faststart nvenc_h264.mp4

注意:

  • NVIDIA 三条命令使用 GPU 编码,未强制使用 GPU 解码;p7 偏重质量,需要更快可试 p5。
  • 不同编码器的 CRF、CQ 数字不代表相同画质,建议先加 -t 30 试转。
  • HEVC、AV1 示例输出 10 位视频,H.264 输出 8 位;10 位不等于 HDR。
  • 原音频已经是合适的 AAC 时,可将 -c:a aac -b:a 128k 换成 -c:a copy。

上面的命令可以作为转码的基础方案,但没有一套参数能同时适合所有视频。动画、实拍、屏幕录制的画面特点不同,对画质、文件大小和处理时间的要求也各不相同,因此需要结合实际结果调整。

也不必每次都从零开始。FFmpegFreeUI 等图形工具提供预设管理功能,可以保存、导入和复用参数方案。

截图中的开发者内置预设,就包含 x264、x265、SVT-AV1 软件编码,以及面向特定显卡的硬件编码方案。社区分享的预设、压制团队公开的教程和参数示例,也可以作为参考。选择时先看清适用的编码器、硬件和素材类型,尤其要区分 SDR 与 HDR;面向某代显卡或某类动画片源的方案,未必适合直接套用到自己的视频。

实际使用时,先从原片中选取运动、暗部和细节较多的代表性片段试压,比较画质、体积和耗时,再按需要调整,每次尽量只改一个参数。达到自己的要求后,就可以保存为预设,供同类素材复用,不必为了追求“最佳参数”无限试调。

3. 截取片段:按是否需要准确起点选择

例如,从视频第 1 分钟附近开始,快速截取约 10 秒的片段:

1
ffmpeg -ss 60 -i input.mp4 -t 10 -map 0:v:0 -map 0:a:0? -c copy rough-cut.mp4

-ss 60 指定从第 60 秒开始定位,-t 10 指定截取时长为 10 秒,-c copy 直接复制音视频数据,不重新编码。

注意:**-ss 配合 -c copy,不能保证从指定的那一帧开始截取。** 因为视频帧之间可能存在依赖,FFmpeg 通常需要先定位到目标时间之前的可寻址点,直接复制时会保留这段额外内容。

下面是截取后片段与原片段比对,证明开始时间在60秒前,总的持续时间只是接近10秒

常见视频会利用前后帧的相似之处减少数据量:许多帧需要参考其他帧,再结合自身保存的预测和差异信息才能还原。因此,截取时不能随意丢掉它们依赖的内容。流复制通常需要从较早的可解码位置开始,起点会受关键帧等因素限制;重新编码则可以先还原画面,再从目标位置生成新的片段。

需要更准确地控制起点时,改为重新编码:

1
ffmpeg -ss 60 -i input.mp4 -t 10 -map 0:v:0 -map 0:a:0? -c:v libx264 -crf 20 -preset medium -pix_fmt yuv420p -c:a aac -b:a 128k exact-cut.mp4

默认启用精确定位时,FFmpeg 会解码并丢弃目标起点之前的部分。是否准确不能只看 -ss 在 -i 前还是后,还要看是否重新编码;视频帧和音频边界也会使最终时长存在少量偏差。

重新编码的代价是处理时间更长,画质和音质也会因再次压缩而有所损失,输出体积不一定更小。如果只是粗略截取,优先使用流复制;需要准确控制片段起点时,再采用重新编码。

截取片段是高频操作,目前高质量主流的软件例如LosslessCut也是调用ffmpeg命令

选择软件菜单工具-上一批ffmpeg 命令可以显示实际的调用参数

4. 提取音频:保留原编码,或转成 MP3

用 ffprobe 确认原音轨是 AAC 后,可以直接保存为 M4A:

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

这里只选择第一条音轨,保留原编码,不会再次压缩。若原音频不是 AAC,先确认它能否写入目标容器。

设备或软件明确要求 MP3 时,再使用下面的转码命令:

1
ffmpeg -i input.mp4 -map 0:a:0 -c:a libmp3lame -q:a 2 audio.mp3

-q:a 2 是 MP3 编码器的质量设置,不是 2 kb/s。从有损音频转成 MP3 会再次损失信息,提高输出质量也不能恢复原来丢失的细节。

5. 去掉声音,只保留视频

1
ffmpeg -i input.mp4 -map 0:v:0 -c:v copy silent.mp4

只映射视频流,输出就没有音轨。-c:v copy 保留原视频数据,不重新编码;原视频编码仍需能写入 MP4。

提取音频和提取视频,同样也可以选择GUI工具,例如优秀的FFmpegFreeUI进行GUI操作,本质还是调用ffmpeg命令

6. 截取一帧作为封面

将第 60 秒的一帧保存成 JPEG:

1
ffmpeg -ss 60 -i input.mp4 -map 0:v:0 -frames:v 1 -q:v 2 -update 1 cover.jpg

-frames:v 1 限制为一帧,-q:v 2 设置 JPEG 质量,-update 1 按单张图片写入。截到黑屏或转场时,调整 -ss 的时间。

如果要选择“无损压缩的”PNG格式,保存为采用无损压缩的 PNG 图片,避免 JPEG 压缩带来的额外画质损失。

1
ffmpeg -ss 60 -i input.mp4 -map 0:v:0 -frames:v 1 -update 1 cover.png

这两种截图方式都需要先解码视频。FFmpeg 默认会解码并丢弃目标时间之前的内容,再输出选中的一帧,因此 -ss 放在 -i 前也能精确定位。截取精度以视频实际帧的时间位置为限。

7. 缩小分辨率

例如,将宽度缩到 1280 像素,高度按比例计算:

1
ffmpeg -i input.mp4 -map 0:v:0 -map 0:a:0? -vf "scale=1280:-2" -c:v libx264 -crf 23 -pix_fmt yuv420p -c:a copy resized.mp4

-vf 设置视频滤镜,scale=1280:-2 固定宽度,并让计算出的高度可被 2 整除,以适配这里的像素格式。源视频宽度小于 1280 时,这条命令会放大画面;执行前应先查看尺寸,按需要换成更小的偶数宽度。

注意:这条命令使用了 scale 缩放滤镜,视频必须重新编码,不能使用 -c:v copy。

缩放改变了画面,所以视频必须重新编码。音频没有修改,示例用 -c:a copy 复制;如果原音频不能写入 MP4,改成 -c:a aac -b:a 128k。

8. 横屏转竖屏:保留完整画面并补边

将横屏录屏或教程片段放进 9:16 的竖屏画布时,可以先等比缩放,再居中补边。这样能保留两侧的文字和操作区域,适合不方便裁掉画面的素材。下面以常见的方形像素视频(sample_aspect_ratio=1:1)为例,输出 1080×1920 的画面:

1
ffmpeg -i input.mp4 -map 0:v:0 -map 0:a:0? -vf "scale=1080:1920:force_original_aspect_ratio=decrease:force_divisible_by=2,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:color=black,setsar=1" -c:v libx264 -crf 23 -pix_fmt yuv420p -c:a copy vertical.mp4

scale 将画面按比例放入 1080×1920 的范围,force_divisible_by=2 让宽高保持偶数;pad 补足画布并居中放置,空白区域填充黑色。最后的 setsar=1 将输出像素宽高比设为 1:1。

横屏素材通常会在上下留下较大的黑边。若希望画面铺满竖屏,就需要裁剪两侧,并检查人物、字幕或界面是否被裁掉;低分辨率素材放大后也不会增加真实细节。音频复制的容器兼容条件与上一节相同。

9. 在画面右下角添加图片水印

给演示视频添加作者标识或项目 Logo 时,先准备一张 logo.png,与视频放在同一目录。需要透明背景,就使用带透明通道的 PNG:

1
ffmpeg -i rough-cut.mp4 -i logo.png -filter_complex "[1:v:0]scale=160:-1[logo];[0:v:0][logo]overlay=W-w-24:H-h-24:repeatlast=1[v]" -map "[v]" -map 0:a:0? -c:v libx264 -crf 23 -pix_fmt yuv420p -c:a copy watermarked.mp4

这里有视频和图片两个输入,所以使用 -filter_complex 组合处理。[1:v:0] 读取第二个输入中的图片,将宽度调整为 160 像素,高度按比例计算;[logo] 是这一步的结果标签。随后,overlay 将它叠加到第一个输入的视频上。

W、H 是主画面宽高,w、h 是水印宽高,因此 W-w-24:H-h-24 表示距右侧和底部各 24 像素。repeatlast=1 让这张静态图片持续显示到视频结束,-map "[v]" 选择叠加后的画面。

可以按视频尺寸调整水印宽度和边距,预览时检查是否遮挡主体或字幕。水印会成为输出画面的一部分,不能像独立图层那样关闭;视频需要重新编码,音频继续复制。

10. 将 SRT 字幕烧录到画面

希望视频在转发或播放时始终显示字幕,可以把字幕直接绘制到画面里。先准备 UTF-8 编码的 sub.srt,与视频放在同一目录,并确认字幕时间与当前视频一致;下面的命令读取已有字幕文件,不会自动识别语音生成字幕。

1
ffmpeg -i input.mp4 -map 0:v:0 -map 0:a:0? -vf "subtitles=filename=sub.srt" -c:v libx264 -crf 23 -pix_fmt yuv420p -c:a copy subtitled.mp4

subtitles 滤镜按 SRT 中的时间显示文字,再由 libx264 对画面重新编码。烧录后,字幕无法单独关闭或切换语言;如果希望观众自行开关字幕,应使用平台提供的字幕上传功能,或保留独立字幕文件。

Windows 下先使用示例中的相对文件名,可以减少盘符和路径转义问题。提示找不到 subtitles 滤镜时,需要使用包含 libass 支持的 FFmpeg 构建;中文字幕显示为方框时,应检查系统是否安装了包含这些汉字的字体。

11. 按顺序拼接多个视频

同一设备或同一套导出参数生成的片段,可以先尝试直接拼接。使用前确认各段的视频、音频编码及参数一致,流的数量、顺序和时间基也要匹配;仅仅都是 MP4 文件,并不足以判断能否这样拼接。

把片段放在同一目录,新建 UTF-8 编码、无 BOM 的 list.txt,按播放顺序填写文件名:

1
2
3
file 'part1.mp4'
file 'part2.mp4'
file 'part3.mp4'

在该目录运行:

1
ffmpeg -f concat -safe 1 -i list.txt -map 0:v:0 -map 0:a:0? -c copy joined.mp4

-f concat 按清单依次读取片段,-c copy 直接复制音视频数据,通常比重新编码快。清单中的相对路径以 list.txt 所在目录为起点;示例使用简单的英文文件名,适用于 -safe 1 的路径检查。

输出保留第一条视频和第一条音轨,所选编码仍需能写入 MP4。如果各段分辨率、音频采样率等参数不同,应先统一规格,再拼接;

LosslessCut同样提供了合并/连接文件的GUI操作

12. 调整播放速度,同时处理画面和声音

将课程片段或操作演示加速为两倍速,需要一起调整视频与音频。下面的示例要求输入包含音轨,且音画原本从同一起点对齐:

1
ffmpeg -i input.mp4 -map 0:v:0 -map 0:a:0 -vf "setpts=(PTS-STARTPTS)/2" -af "asetpts=PTS-STARTPTS,atempo=2" -c:v libx264 -crf 23 -pix_fmt yuv420p -fps_mode vfr -c:a aac -b:a 128k speed2x.mp4

setpts 调整视频帧的显示时间,除以 2 后,画面的播放时间约减半;atempo=2 把音频加速为两倍,并尽量保持原有音高。PTS-STARTPTS 将对应流的起点归零,-fps_mode vfr 允许输出按调整后的帧时间写入。

修改速度时,视频与音频的倍率要一起调整:

播放速度 视频滤镜 音频滤镜
1.5 倍速 setpts=(PTS-STARTPTS)/1.5 asetpts=PTS-STARTPTS,atempo=1.5
2 倍速 setpts=(PTS-STARTPTS)/2 asetpts=PTS-STARTPTS,atempo=2
0.5 倍速 setpts=(PTS-STARTPTS)/0.5 asetpts=PTS-STARTPTS,atempo=0.5

音画都经过处理,所以都要重新编码。两倍速的输出时长约为原来的一半,半速则约为两倍;帧间隔和音频处理边界可能带来少量偏差。如果原音轨有刻意保留的延迟,不要直接套用这条分别归零的命令,否则会改变原有的音画时间关系。