我正在试图找出如何指定要转换为视频的特定图像列表。我知道我们可以做类似的事情:
ffmpeg -i image_04%d.png
这将从文件夹中选择与序列匹配的所有图像。但是在我的情况下,图像文件不一定按照其名称暗示的顺序。原因是订单保存在数据库中,文件名本质上是数据库行ID。
如何指定正确的输入序列?我基本上是从代码调用ffmpeg而不是从命令行调用。因此,对代码的任何改变想法也都受到欢迎。
谢谢!
答案 0 :(得分:5)
这是凯文的想法中的一个脚本,对我有用。您可能希望替换文件名模式(shot * .png)和输出文件名movie.mp4。完成后,脚本将删除所有frame_ ...文件。
# script to create movie from multiple png files
# taken in choronoligcal order
# start at 0
count=0
# take all files named shot - something ordered by date
for f in `ls -rt shot*.png`
do
# get the index in 0000 format
printf -v counts "%04d" $count
# link file to a frame_0000 named symbolic link
ln -s $f frame_$counts.png
# increment counter
count=`expr $count + 1`
done
# create movie
# slowed down by factor 5
# ffmpeg -f image2 -i frame_%04d.png -vcodec mpeg4 -vf "setpts=5*PTS" movie.mp4
ffmpeg -i frame_%04d.png movie.mp4
# remove the links
rm frame_*.png
答案 1 :(得分:1)
您的应用程序可以创建从0001开始的符合原始帧顺序的符号链接,然后将该序列传递给ffmpeg。视频完成后,删除符号链接即可。
答案 2 :(得分:0)
嗯,解决方法是修补image2类以支持带有要选择的数字的列表。比我提供ffmpeg输入文件模式以及具有指定顺序的数字数组来读取输入。这非常有效。
答案 3 :(得分:0)
假设我们有一个正确顺序的文件名列表,如下所示:
frames=(
"5K1OCNKToUu.png" "kJuKFQS0Fgnp.png" "00v4U4JTyUn.png" "3sg9sDwPZoX.png"
"1KsuEk9mboa9.png" "qNrI8zlRBmW.png" "MOvSca3wlPsP.png" "5rXcxfGQXunY.png"
"hjruIcoN0aTn.jpg" "OhRttnWtKy.png" "e2Qj8jCixc.png" "Uze2H7vzrt4.png"
"n14qhmjiBW3.png" "ZDMvY4g1hzgS.png" "ibnb7MxELyGp.png" "9c8QGWmBEDNg.png"
"STQT0t7oqPEK.png" "jI7UvpbLDWPc.png" "6clazeaUAJHv.png" "ylJ40r9uMK9d.png"
"RICq5KV00P6.png" "zjCLrappFMPq.png" "TJQTDv313KBo.png" "Gu3pLpWylsuo.png"
"Ksym4SB6VYNv.png" "rIyj0LJIjBVX.png" "pSUm2J8xYU.png" "Rnsr0H0m7p9A.png"
"x4vVomlOolxt.png" "2W1QURLQUyE8.png" "m3JgtDzQ0VgE.png" "CrjN9TVJKMAU.png"
"IO6pnF83ivqo.png" "hY15nsYDvr4h.png" "1GagDdBM9L7.png"
)
我们希望以一定的帧速率从这些GIF中创建动画GIF,例如FPS=30
。
这可以像在其他答案中那样通过创建符号链接来完成,例如将001.png
命名为035.png
,然后使用:
ffmpeg -i 03%d.png
另一种方法是使用ffmpeg
的{{3}}。
不幸的是,这说起来容易做起来有点容易,因为该功能需要视频流,这意味着只要需要就可以对图像进行循环。
用三个图像连接三个图像的命令是:
ffmpeg -f concat -safe 0 -i <(cat <<EOF
file '$(pwd)/1KsuEk9mboa9.png'
duration 0.5
file '$(pwd)/hjruIcoN0aTn.png'
duration 0.5
file '$(pwd)/n14qhmjiBW3.png'
duration 0.5
EOF
) -framerate 2 out.gif
使用ffmpeg version 3.0.1-3
进行测试。
<强>解释强>
concat-feature期望一个文件包含关键字file
前面的相对文件名列表。为了不弄乱当前的工作目录(或者我们没有写入权限),我们使用进程替换<( ... )
。但这会在/dev/fd/
中创建一个文件,如果使用相对文件名,则会产生如下错误消息:
[concat @ 0xc181c0] Impossible to open '/dev/fd/5K1OCNKToUu.png'
这就是给出绝对路径的原因。但默认情况下不允许使用绝对路径,导致:
[concat @ 0x17da1c0] Unsafe file name '/home/5K1OCNKToUu.png'
为concat demuxer使用-safe 0
。
尝试使用solve
指定输入帧速率时ffmpeg -f concat -safe 0 -r 2 -i <(cat <<EOF
file '$(pwd)/1KsuEk9mboa9.png'
file '$(pwd)/hjruIcoN0aTn.png'
file '$(pwd)/n14qhmjiBW3.png'
EOF
) -framerate 2 out.gif
发生这样的错误:
[concat @ 0x1458220] DTS -230575710986777 < 0 out of order
DTS -230575710986777, next:40000 st:0 invalid dropping
PTS -230575710986777, next:40000 invalid dropping st:0
结果GIF的工作方式与预期一致。使用duration
concat
选项明确解决了这些警告/错误。
请注意-r
作为输入选项,忽略存储在文件中的所有时间戳 相反,假设帧速率fps恒定,则生成时间戳。这个 与某些输入格式使用的-framerate选项不同 像image2或v4l2(在旧版本中它曾经是相同的 FFmpeg的)。如果有疑问,请使用-framerate而不是输入选项-r。
我对此的看法是来自concat的上述警告,它通知您无法找到图像的播放长度,不会导致不良行为,因为在使用{{1的连接警告后强制使用帧率有效,但可能不是预期的方式。我只会在手动编写ffmpeg命令时使用它,但不能在脚本中使用。
汇总-r
小脚本以处理开头指定的文件名列表:
-r
上面代码中的未注释行将给出H264编码的mkv。
异质图像类型
如果您的图片列表包含不同类型的图片,例如将function makeGif() {
local targetName=$1; shift
local FPS=$1; shift
# concat doesn't recognize .33 as returned by bc by default
local delay=$(bc <<< "scale=5; x=1/$FPS; if (x<1) print 0; x")
local list
for file in $@; do
list+=$(printf "\nfile '$(pwd)/$file'\nduration $delay")
done
ffmpeg -f concat -safe 0 -i <(cat <<< "$list") -r $FPS "$targetName".gif
#ffmpeg -f concat -safe 0 -i <(cat <<< "$list") -r $FPS -c:v libx264 -crf 5 -pix_fmt yuv420p "$targetName".mkv
}
makeGif out 30 ${frames[@]}
替换为hjruIcoN0aTn.png
中的hjruIcoN0aTn.jpg
,frames
的这种用法将无效。将删除除第一次指定之外的其他格式的图像,并抛出错误,如:
concat
在这种情况下,您必须使用a而不是简单的分路器。然后,必须将包含上述三个文件的命令更改为:
[png @ 0x1ec8260] Invalid PNG signature 0xFFD8FFE000104A46.
Error while decoding stream #0:0: Invalid data found when processing input
<强>解释强>
使用的每个选项都得到了很好的解释concat filter。请注意,ffmpeg \
-f image2 -loop 1 -thread_queue_size 4096 -framerate 30 -t 0.5 -i "$(pwd)/1KsuEk9mboa9.png" \
-f image2 -loop 1 -thread_queue_size 4096 -framerate 30 -t 0.5 -i "$(pwd)/hjruIcoN0aTn.jpg" \
-f image2 -loop 1 -thread_queue_size 4096 -framerate 30 -t 0.5 -i "$(pwd)/n14qhmjiBW3.png" \
-filter_complex 'concat=n=3:v=1 [vmerged]' \
-map '[vmerged]' -r 30 out.gif
选项特定于here,并且至少在技术上与-framerate
不同,实际上在这种情况下,它们会产生相同的结果。
-r
似乎是必要的,因为我们将一张图片延长了相当长的500毫秒,导致出现以下错误消息:
-thread_queue_size
该选项的描述让我有理由认为过大的延迟是错误的:
-thread_queue_size大小(输入) 此选项设置从文件或设备读取时排队的最大数据包数。低 延迟/高速率直播流,如果没有及时读取数据包,则可以丢弃这些数据包; 提高这个价值可以避免它。
将所有这些再次放入脚本中:
[image2 @ 0x18856e0] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8)
[image2 @ 0x188a100] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8)
[image2 @ 0x188b9e0] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8)
出于一些非常奇怪的原因,上述命令不能像 !!! 一样工作。在我的情况下,它删除了指定的35帧中的33帧而没有警告或错误消息:
function makeGif() {
local targetName=$1; shift
local FPS=$1; shift
local delay=$(bc <<< "scale=5; x=1/$FPS; if (x<1) print 0; x")
local list=()
local nFiles=0
for file in $@; do
list+=( -f image2 -loop 1 -thread_queue_size 4096 -framerate $FPS -t $delay -i "$(pwd)/$file" )
nFiles=$((nFiles+1))
done
ffmpeg ${list[@]} -filter_complex "concat=n=$nFiles:v=1 [vmerged]" -map '[vmerged]' -r $FPS "$targetName".gif
#ffmpeg ${list[@]} -filter_complex "concat=n=$nFiles:v=1 [vmerged]" -map '[vmerged]' -r $FPS -c:v libx264 -crf 5 -pix_fmt yuv420p "$targetName".mkv
}
makeGif out 30 ${frames[@]}
这很奇怪的原因是它完全像预期的那样延迟了两倍,即每个图像显示为2帧,即将frame= 2 fps=0.0 q=-0.0 Lsize= 2kB time=00:00:00.07 bitrate= 179.7kbits/s dup=0 drop=33 speed=0.155x
更改为1/$FPS
:
2/$FPS
这一事实表明了一种简单的解决方法:以帧速率加倍编码并将每个图像显示2帧。但这无论如何都是浪费而且不利。