ffmpeg 视频抽帧再合成视频帧
需求
我想将一个视频每隔 5 秒就抽取一帧,然后再将这些抽取的帧合并在一起形成一个视频。
前提
- 此操作平台为 macOS 终端,其它平台可自行举一反三
- 准备好本地视频 input.mp4
- 安装好 ffmpeg
brew install ffmpeg
操作
1. 创建图片存放文件夹
mkdir output
2. 抽帧
ffmpeg -i input.mp4 -vf fps=1/5 output/frame-%04d.png
3. 合并图片成视频
将原始音频合并回去:
ffmpeg -framerate 1 -i output/frame-%04d.png -i input.mp4 -c:v libx264 -c:a copy -shortest -pix_fmt yuv420p output.mp4
-
-framerate 1
:每秒播放 1 张图片; -
-i output/frame-%04d.png
:读取图片序列;%04d
告诉 FFmpeg 这里的数字是4位数,并且有前导零(0001, 0002…)。如果你的文件名是frame-1.png
,frame-2.png
,你需要改成frame-%d.png
。 -
-i input.mp4
:添加音频; -
-c:v libx264
:指定视频的编码器 (codec)。用 H.264 编码;这是目前兼容性最好、使用最广泛的视频编码标准。 -
-c:a copy
:直接拷贝音频流,不重新编码; -
-shortest
:在音频或视频任一流结束时停止输出; -
-pix_fmt yuv420p
:指定像素格式 (pixel format)。添加这个参数可以确保生成的视频在绝大多数播放器(包括 QuickTime 和网页浏览器)上都有最好的兼容性,避免出现颜色问题。
不包含音频:
ffmpeg -framerate 1 -i output/frame-%04d.png -c:v libx264 -pix_fmt yuv420p output.mp4
控制视频质量:
libx264
编码器默认的质量已经很好了。但如果你想手动控制,可以使用 -crf
(Constant Rate Factor) 参数。
-
crf
的取值范围是 0-51,数值越低,质量越高,文件越大。 -
18
左右是视觉上接近无损的质量,文件会很大。 -
23
是默认值,在质量和文件大小之间取得了很好的平衡。 -
28
左右是较低的质量,但文件会更小。
ffmpeg -framerate 1 -i output/frame-%04d.png -c:v libx264 -crf 18 -pix_fmt yuv420p high_quality_output.mp4
对于绝大多数情况,那个合并原始音频的命令是最实用、最常用的。
按文件名顺序读取所有匹配图片(glob
模式):
如果图片文件不是从 001
开始,或命名不规则:
ffmpeg -pattern_type glob -framerate 1 -i "*.jpg" -c:v libx264 -pix_fmt yuv420p output.mp4
合成视频时缩放图片并保持比例无裁剪:
ffmpeg -pattern_type glob -framerate 24 -i '../images/*.jpg' -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black" -sws_flags lanczos -c:v libx264 -pix_fmt yuv420p output.mp4
-
-sws_flags lanczos
:最高质量的缩放。 -
-vf
:在内存中对输入图像做强制缩放处理,避免尺寸不一致,不会写回原文件。 -
scale=1920:-1:force_original_aspect_ratio=decrease
:- 按比例缩放,不拉伸;
- 确保画面完整显示;
- -1 表示自动计算高度;
-
force_original_aspect_ratio=decrease
表示“缩放到能完全放进 1920×1080 的范围内”。
-
pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black
:- 如果缩放后画面不是刚好 1920×1080;
- 就自动加黑边居中对齐;
- 避免裁剪和拉伸。
结果就是:
- ✅ 图片不被裁剪;
- ✅ 不被拉伸;
- ✅ 黑边填充到标准 16:9;
- ✅ 播放器兼容性最佳。
如果不想缩放填充,保持原图片,可移除 -vf
参数,即:
ffmpeg -pattern_type glob -framerate 24 -i '../images/*.jpg' -sws_flags lanczos -c:v libx264 -pix_fmt yuv420p output.mp4
常见操作示例和解释
1. 提取所有帧
ffmpeg -i input.mp4 output/%frame-%04d.png
-
-i input.mp4
: 指定输入文件。 -
output/frame-%04d.png
: 指定输出文件的格式,也可以换成 JPG、BMP 等其他格式。output
是存放图片的文件夹(请确保这个文件夹已存在),frame-%04d.png
会将图片命名为frame-0001.png
,frame-0002.png
…
2. 每秒提取一帧
ffmpeg -i input.mp4 -vf fps=1 output/frame-%04d.png
-
-vf fps=1
:每秒提取 1 帧。也可以设置成其它值,比如fps=1/5
,表示 “每秒 1/5 帧”, 也就是每 5 秒提取 1 帧。
3. 在指定时间点提取单帧
精确定位:
ffmpeg -i input.mp4 -ss 00:01:30 -vframes 1 output.png
-
-ss 00:01:30
: 定位到视频的 1 分 30 秒处。 -
-vframes 1
: 表示只提取 1 帧。
这条命令是「解码后跳转(精确)」,即:
ffmpeg 先解码视频,再找到 1:30 这一帧。
优点:精确到帧。
缺点:大视频可能稍慢。
快速定位:
ffmpeg -ss 00:01:30 -i input.mp4 -vframes 1 output.png
这叫「输入前跳转(快速)」,特点:
跳转非常快;
但只能到最近的关键帧(可能偏几帧)。
4. 提取指定时间段的帧
ffmpeg -ss 00:12:05 -i input.mp4 -to 00:14:32 output/frame-%04d.png
-
-to 00:14:32
:-to
参数用于指定结束时间戳。到第 14 分 32 秒时,提取过程会停止。
5. 提取指定起始时间和时长的视频帧
ffmpeg -ss 00:12:05 -i input.mp4 -t 147 output/frame-%04d.png
-
-t 147
: 从-ss
指定的开始时间起,向后处理 147 秒的内容。
性能提示:为了加快处理速度,特别是处理长视频时,建议将 -ss 参数放在 -i 之前。 这样做能让 FFmpeg 使用更快的“关键帧定位”来跳转到指定时间,而不是逐帧解码。
6. 重编码视频成较低帧率
ffmpeg -i input.mp4 -r 6 output.mp4
-
-r 6
:把 30fps 视频转成 6fps。
7. 视频快进 2 倍
ffmpeg -i input.mp4 -filter:v "setpts=0.5*PTS" output_fast.mp4
8. 视频音频同步慢放 0.5 倍
ffmpeg -i input.mp4 -filter:v "setpts=2.0*PTS" -filter:a "atempo=0.5" output_slow.mp4
或者
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]" -map "[v]" -map "[a]” output_slow.mp4
⚠️ 注意:atempo
只能支持 0.5
~2.0
倍之间;如果要快进 4 倍或慢放 0.25 倍,就要链式叠加,比如:
# 4倍快进
-filter:a "atempo=2.0,atempo=2.0"
# 0.25倍速(慢放)
-filter:a "atempo=0.5,atempo=0.5"
9. 转换视频格式
ffmpeg -i input.ts -c copy output.mp4
-
-c copy
:不重新编码,直接拷贝音视频流(速度快、无质量损失)。
10. ImageMagick 工具用例
- 安装
brew install imagemagick
- 图片尺寸统计
identify ../images/*.webp | awk '{print $3}' | sort | uniq -c
- 图片 webp 统一尺寸
mogrify -resize 1920x1080! ../images/*.jpg
!
表示强制拉伸到固定大小,不保持原比例。如果想保持比例,可以省略!
,或者用-resize 1920x1080^ -gravity center -extent 1920x1080
进行裁剪填充。
11. 将文件夹中的一堆图片做成一个 webp 格式的动图(类似于 GIF)
ffmpeg -pattern_type glob -framerate 5 -i "*.jpg" -loop 3 -c:v libwebp -q:v 80 output.webp
-
-loop 0
:输出 WebP 循环播放次数,0 表示无限循环。
🫵 可参考借鉴其它命令,自行增加或减少参数,比如 -vf "scale=1920:1080:force_original_aspect_ratio=decrease"
等等,其它命令亦如是,可互相尝试借鉴。