如何使用FFmpeg从图片创建视频?

362
ffmpeg -r 1/5 -start_number 2 -i img%03d.png -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4

这一行代码运行得很好,但我想从另一个文件夹中的图像创建视频文件。 我的文件夹中有以下图像名称:

img001.jpg
img002.jpg
img003.jpg
...

我该如何从不同的文件夹输入图片文件?例如:C:\mypics

我尝试了这个命令,但是ffmpeg只生成了一个视频,里面只包含第一张图片(img001.jpg)。

ffmpeg -r 1/5 -start_number 0 -i C:\myimages\img%03d.png -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4

4
有关-从单张图片制作视频。在FFmpeg中,可以使用以下命令将一张图片转换为指定时长的视频: ffmpeg -loop 1 -i input.jpg -c:v libx264 -t 10 output.mp4其中,input.jpg是输入图片的路径,-loop 1表示循环播放该图片,-c:v libx264表示以H.264编解码格式输出视频,-t 10表示输出视频的时长为10秒,output.mp4则是输出视频的文件名和格式。 - barlop
9个回答

427

-pattern_type glob

这个很好的选项在许多情况下使选择图像变得更加容易。

以30 FPS每帧只有一个图像的正常速度视频

ffmpeg -framerate 30 -pattern_type glob -i '*.png' \
  -c:v libx264 -pix_fmt yuv420p out.mp4

这是它的外观:

使用以下命令生成GIF:https://askubuntu.com/questions/648603/how-to-create-an-animated-gif-from-mp4-video-via-command-line/837574#837574

为其添加一些音频:

ffmpeg -framerate 30 -pattern_type glob -i '*.png' \
  -i audio.ogg -c:a copy -shortest -c:v libx264 -pix_fmt yuv420p out.mp4

结果: https://www.youtube.com/watch?v=HG7c7lldhM4

这些是我使用的测试媒体:

wget -O opengl-rotating-triangle.zip https://github.com/cirosantilli/media/blob/master/opengl-rotating-triangle.zip?raw=true
unzip opengl-rotating-triangle.zip
cd opengl-rotating-triangle
wget -O audio.ogg https://upload.wikimedia.org/wikipedia/commons/7/74/Alnitaque_%26_Moon_Shot_-_EURO_%28Extended_Mix%29.ogg

使用以下方式生成的图像:如何使用GLUT / OpenGL渲染到文件?

观察到视频在专门的算法帮助下跨帧压缩,比ZIP压缩图像序列要好得多:

  • opengl-rotating-triangle.mp4:340K
  • opengl-rotating-triangle.zip:7.3M

将一个音乐文件转换为固定图像的视频,以用于上传到YouTube

答案位于:https://superuser.com/questions/700419/how-to-convert-mp3-to-youtube-allowed-video-format/1472572#1472572

每秒钟播放一张图片的幻灯片视频

ffmpeg -framerate 1 -pattern_type glob -i '*.png' \
  -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4

加入一些音乐,当图像结束时,停止较长的音频:

ffmpeg -framerate 1 -pattern_type glob -i '*.png' -i audio.ogg \
  -c:a copy -shortest -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4

这里有两个YouTube演示:

成为嬉皮士,使用Theora专利未受限制的视频格式,存储在OGG容器中

ffmpeg -framerate 1 -pattern_type glob -i '*.png' -i audio.ogg \
  -c:a copy -shortest -c:v libtheora -r 30 -pix_fmt yuv420p out.ogv

您的图片应按字母顺序排序,通常为:

0001-first-thing.jpg
0002-second-thing.jpg
0003-and-third.jpg

等等其他内容。

我首先会确保所有要使用的图像具有相同的纵横比,可能通过使用imagemagicknomacs进行裁剪,以便ffmpeg不必做出艰难的决定。特别是,宽度必须可以被2整除,否则转换将失败并显示“宽度不能被2整除”。

逐步设置完整现实幻灯片案例研究

创建幻灯片秀需要的步骤比运行单个ffmpeg命令多一些,因此这里提供了一个更详细、更有趣的例子,受到这个时间线的启发。

获取输入媒体:

mkdir -p orig
cd orig
wget -O 1.png https://upload.wikimedia.org/wikipedia/commons/2/22/Australopithecus_afarensis.png
wget -O 2.jpg https://upload.wikimedia.org/wikipedia/commons/6/61/Homo_habilis-2.JPG
wget -O 3.jpg https://upload.wikimedia.org/wikipedia/commons/c/cb/Homo_erectus_new.JPG
wget -O 4.png https://upload.wikimedia.org/wikipedia/commons/1/1f/Homo_heidelbergensis_-_forensic_facial_reconstruction-crop.png
wget -O 5.jpg https://upload.wikimedia.org/wikipedia/commons/thumb/5/5a/Sabaa_Nissan_Militiaman.jpg/450px-Sabaa_Nissan_Militiaman.jpg
wget -O audio.ogg https://upload.wikimedia.org/wikipedia/commons/7/74/Alnitaque_%26_Moon_Shot_-_EURO_%28Extended_Mix%29.ogg
cd ..

# Convert all to PNG for consistency.
# https://unix.stackexchange.com/questions/29869/converting-multiple-image-files-from-jpeg-to-pdf-format
# Hardlink the ones that are already PNG.
mkdir -p png
mogrify -format png -path png orig/*.jpg
ln -P orig/*.png png

现在我们快速查看所有图像大小,以决定最终的纵横比:

identify png/*

输出结果为:

png/1.png PNG 557x495 557x495+0+0 8-bit sRGB 653KB 0.000u 0:00.000
png/2.png PNG 664x800 664x800+0+0 8-bit sRGB 853KB 0.000u 0:00.000
png/3.png PNG 544x680 544x680+0+0 8-bit sRGB 442KB 0.000u 0:00.000
png/4.png PNG 207x238 207x238+0+0 8-bit sRGB 76.8KB 0.000u 0:00.000
png/5.png PNG 450x600 450x600+0+0 8-bit sRGB 627KB 0.000u 0:00.000

因此,经典的480p(640x480 == 4/3)宽高比看起来比较合适。

进行一次最小的转换以使宽度变为偶数(TODO自动化任何宽度的转换,在这里我只是手动查看了identify输出并将宽度和高度减小了1):

mkdir -p raw
convert png/1.png -resize 556x494 raw/1.png
ln -P png/2.png png/3.png png/4.png png/5.png raw
ffmpeg -framerate 1 -pattern_type glob -i 'raw/*.png' -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p raw.mp4

这会产生糟糕的输出,因为从下面可以看到:

ffprobe raw.mp4

ffmpeg会直接采用第一张图片的尺寸,即556x494,并将其它所有图片转换为该精确尺寸,破坏它们的宽高比。

现在,我们可以通过像ImageMagick: how to minimally crop an image to a certain aspect ratio?中所述的自动裁剪方法将图像转换为目标480p宽高比。

mkdir -p auto
mogrify -path auto -geometry 640x480^ -gravity center -crop 640x480+0+0 png/*.png
ffmpeg -framerate 1 -pattern_type glob -i 'auto/*.png' -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p auto.mp4

现在,纵横比例很好,但不可避免地需要进行一些裁剪,这样就切掉了图像的一些有趣部分。

另一个选择是用黑色背景填充,以获得与此处所示相同的纵横比,如:Resize to fit in a box and set background to black on "empty" part

mkdir -p black
mogrify -path black -thumbnail 640x480 -background black -gravity center -extent 640x480 png/*.png
ffmpeg -framerate 1 -pattern_type glob -i 'black/*.png' -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p black.mp4

一般来说,最好能选择相同或类似纵横比的图像,以避免出现这些问题。

关于CLI选项

请注意,尽管名为-glob,但这不像shell Glob模式那样通用,例如:-i '*' 会失败:https://trac.ffmpeg.org/ticket/3620(显然是因为文件类型由扩展名推断出来)。

-r 30 使-framerate 1 视频成为每秒30帧,以解决像VLC这样播放器在低帧率下的故障: 使用ffmpeg从图像创建低1 FPS视频时,VLC冻结 因此,它会将每个帧重复30次,以保持所需的每秒1张图片的效果。

下一步操作

您还需要:

ffmpeg -i in.mp3 -ss 03:10 -to 03:30 -c copy out.mp3

或者,您还可以通过在音频-i之前添加-ss来直接在转换命令中剪切它:

ffmpeg -framerate 1 -pattern_type glob -i 'raw/*.png' -ss 0:36 -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p raw.mp4

TODO: 学习如何将多个音频文件剪切和拼接到视频中,而不需要中间文件。我相信这是可能的:

每张图片的持续时间不同

https://video.stackexchange.com/questions/23530/use-ffmpeg-to-create-a-video-from-a-few-images 提供了一种解决方案。

您可以创建一个名为in.txt的文件,内容如下:

file png/1.png
outpoint 5
file png/2.png
outpoint 2
file png/3.png
outpoint 7

outpoint 设置前一图像的持续时间(以秒为单位)。

然后,我们只需从先前的转换命令中移除 -framerate

ffmpeg -f concat -i in.txt -framerate 1 -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p black.mp4

我也喜欢文件名在一个文件中的这种方法,比重新命名输入文件以获得正确的顺序更好,这使得在文本编辑器中快速重新排序图像变得更容易(多个-i无法工作)。每个输入文件有两行会使这个过程有点更麻烦,我没有成功将fileoutpoint组合成一行,但还是很好知道。

如果你只想转换图像的子集,则这种方法也很方便。然后,为了节省ImageMagick的时间,您可以重复使用in.txt文件,仅循环处理您关心的图像:

grep -E '^file ' in.txt | sed -E 's/^file //; s/\..*//' | while read f; do
  echo $f
  convert -thumbnail 1280x720 -background black -gravity center -extent 1280x720 "$(command ls -1 ../$f.* | grep -v .xcf | head -n1)" "out/$f.jpg"
done

测试环境

ffmpeg 3.4.4,vlc 3.0.3,Ubuntu 18.04。

参考文献


1
如果您正在使用Python和subprocess.call启动FFmpeg,则不应在输入和输出文件名中使用单引号'。否则,它将无法找到文件。 - RunOrVeith
7
这对我来说很有用,但我从npm包ffmpeg-static构建的程序中没有实现glob。(选择了“glob”模式类型,但此libavformat构建不支持globbing) - Sebi
-pix_fmt 导致出现了 命令行上发现了尾随选项 的错误。 - Anthony Kong
14
在 Windows 版本中无法使用 glob 模式 - Zimba
1
@oarfish仍在处理ffmpeg 4.4.2,Ubuntu 22.04。你用的是哪个版本? - Ciro Santilli OurBigBook.com
显示剩余3条评论

295

请参阅使用FFmpeg从图像创建视频幻灯片

如果您的视频无法正确显示帧 如果遇到问题,例如跳过第一张图像或仅显示一个帧,则使用fps视频过滤器而不是输出帧率的-r

ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p out.mp4

或者,可以将格式视频过滤器添加到过滤器链中,以替换-pix_fmt yuv420p,例如"fps=25,format=yuv420p"。这种方法的优势在于您可以控制哪个过滤器先执行。

ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf "fps=25,format=yuv420p" out.mp4

我测试了以下参数,对我有效

"e:\ffmpeg\ffmpeg.exe" -r 1/5 -start_number 0 -i "E:\images\01\padlock%3d.png" -c:v libx264 -vf "fps=25,format=yuv420p" e:\out.mp4

以下参数也可以使用,但它总是跳过第一张图片。

"e:\ffmpeg\ffmpeg.exe" -r 1/5 -start_number 0 -i "E:\images\01\padlock%3d.png" -c:v libx264 -r 30 -pix_fmt yuv420p e:\out.mp4

从不同文件夹中的图像制作视频

首先,将图像路径添加到imagepaths.txt中,如下所示。

# this is a comment details https://trac.ffmpeg.org/wiki/Concatenate

file 'E:\images\png\images__%3d.jpg'
file 'E:\images\jpg\images__%3d.jpg'

以下是示例用法:

"h:\ffmpeg\ffmpeg.exe" -y -r 1/5 -f concat -safe 0 -i "E:\images\imagepaths.txt" -c:v libx264 -vf "fps=25,format=yuv420p" "e:\out.mp4"

-safe 0参数可以避免不安全的文件名错误。

相关链接

使用FFmpeg将放置在不同文件夹中的图像制作成视频

FFMPEG中级指南/图像序列

连接 - FFmpeg


如果您的视频无法正确显示帧,例如第一幅图像被跳过或仅显示一帧,请使用fps视频滤镜解决问题。抱歉,能否请您详细解释一下“fps视频滤镜”是什么意思? - arnuschky
4
据我所知,“-r”参数是可变帧率,这意味着FFMPEG可能会删除或复制帧以实现所需的输出帧率。使用fps过滤器“-vf fps=value”可以强制FFMPEG生成恒定的帧率。请参见从图像创建视频幻灯片 - FFmpeg,以及这个“-r”和fps过滤器之间的(技术)区别是什么?。因此,有时使用**-r**参数会导致第一张图像被跳过。 - khan
1
这个列表中的第一个命令 ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p out.mp4 看起来是有效的,但最终生成的视频无法被任何播放器(在Ubuntu上)读取。VNC显示“未找到moov原子”。尝试使用 qt-faststart 解决此问题时出现错误“文件中的最后一个原子不是moov原子”。 - sh37211
当你在ddg上搜索“从图像创建视频幻灯片 - FFmpeg”时,这个问题/答案是第一个链接。做得好!(也许是ddg)。 - tpb261
concat示例需要持续时间才能正常工作(根据文档),这些持续时间必须是(1/25=)0.04秒的倍数(否则它们将被四舍五入)。如果没有持续时间,帧将被丢弃。 - Arnon Weinberg
显示剩余2条评论

43

文档中的简化版

对于Google Earth Studio图像效果特别好:

ffmpeg -framerate 24 -i Project%03d.png Project.mp4

2
无法播放此输出:[h264 @ 0x7f148cc3cc40] 硬件加速器无法解码图片。 - Bram
1
你是在使用 %3d 还是 %03d - Joshua Pinter
@AnthonyKong你的输出文件名是否和输入文件名相同?请在此处发布你的代码,这样我们才知道你正在尝试做什么。 - Joshua Pinter
1
在我在“-i”后面的文件名规范周围加上引号之后,提示符就不再出现了。 - Anthony Kong
1
@AnthonyKong 你的输入或输出文件名中有空格吗? - Joshua Pinter
显示剩余6条评论

41

cat *.png | ffmpeg -f image2pipe -i - output.mp4

来自维基


我的救星!谢谢你。 - random6174
1
Windows cmd怎么样? - Oli
3
我后来使用这个命令 ffmpeg -i output.mp4 -filter:v "setpts=60.0*PTS" output_slowed.mp4 将它减速了。 - user238607
1
在Mac上使用ffmpeg 5.1.2时,结果为“输出文件#0不包含任何流”。 - Can Poyrazoğlu
1
生成了一个特定大小的.mp4文件,但无法播放,屏幕是黑色的。 - rearThing
显示剩余2条评论

4

由于Windows系统不支持POSIX实现的glob命令,因此需要使用sequence作为模式来解决问题。为了使其正常工作,需要将文件重命名为序列号的形式 - 如

gym01.jpg
gym02.jpg
...

然后我们可以在Windows上使用以下命令 - 注意gym%02d.jpg,如果您的序列包含超过2个字符(例如,gym00001.jpg),请相应更改(gym%05d.jpg

ffmpeg -framerate 1 -pattern_type sequence -i gym%02d.jpg -s:v 1920x1080 -c:v libx264 -pix_fmt yuv420p out.mp4

2

您的文件应该命名为depth_00001.png depth_00002.png等,这样可以确保正确的顺序。

步骤1)如果它们被称为depth_1.png depth_2.png,那么您可以使用此命令批量重命名它们为所需的命名。

for f in depth_[0-9]*; do mv "$f" "$(printf 'depth_%05d' "${f#depth_}" 2> /dev/null)"; done; for f in depth_[0-9]*; do mv "$f" "$f.png"; done;

步骤2)然后使用标准选项运行ffmpeg。
ffmpeg -framerate 30 -i depth_%05d.png -pix_fmt yuv420p -c:v libx264 depth.mp4

步骤三)如果失败了(在Windows上对我来说确实是这样),那么请尝试使用以下方法。
cat depth_*.png | ffmpeg -f image2pipe -framerate 30 -i - -pix_fmt yuv420p -c:v libx264 depth.mp4

注意:当我使用PNG时,步骤2失败了 - 但是当我使用ImageMagick将PNG转换为JPG时,步骤2成功了。
下面是我用于进行转换的命令。
for image in *.png; do magick convert "$image" "${image%.*}.jpg"; done;

此外,我发现这个命令很有用,可以验证输出视频的长度是否符合预期。
ffprobe -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 depth.mp4

2
要创建带有音频的视频,您需要指定以下内容:
普通帧速率:-framerate 30 音频:-i audio/audio.ogg 库:libx264
   system("ffmpeg -framerate 30 -i #{out_dir}/%03d.png -i audio/audio.ogg 
-c:a copy -shortest -c:v libx264 -pix_fmt yuv420p out/final
/#{out_dir.sub("out/", "")}.mp4")

如果您想创建一个循环,例如3次 -stream_loop 2,因为从0开始计数,所以循环2次即可(0,1,2)

    system("ffmpeg -stream_loop 2 -framerate 30 -i 
#{out_dir}/%03d.png -i audio/audio.ogg -c:a copy -shortest -c:v 
libx264 -pix_fmt yuv420p -b:v 50M  out/final/#{out_dir.sub("out/", 
"")}.mp4")

1

从视频中创建帧:

ffmpeg\ffmpeg -i %video% test\thumb%04d.jpg -hide_banner

可选:删除您不想在输出视频中显示的帧
(比使用-ss-t剪辑视频更准确)

然后从图像/帧创建视频,例如:

ffmpeg\ffmpeg -framerate 30 -start_number 56 -i test\thumb%04d.jpg -vf format=yuv420p test/output.mp4

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接