如何指定无序图像列表?

时间:2012-04-28 18:01:53

标签: ffmpeg

我正在试图找出如何指定要转换为视频的特定图像列表。我知道我们可以做类似的事情:

ffmpeg -i image_04%d.png

这将从文件夹中选择与序列匹配的所有图像。但是在我的情况下,图像文件不一定按照其名称暗示的顺序。原因是订单保存在数据库中,文件名本质上是数据库行ID。

如何指定正确的输入序列?我基本上是从代码调用ffmpeg而不是从命令行调用。因此,对代码的任何改变想法也都受到欢迎。

谢谢!

4 个答案:

答案 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.jpgframes的这种用法将无效。将删除除第一次指定之外的其他格式的图像,并抛出错误,如:

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帧。但这无论如何都是浪费而且不利。