FFmpeg poster

需求

我想将一个视频每隔 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.52.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" 等等,其它命令亦如是,可互相尝试借鉴。