次のような正しい順序でファイル名のリストがあるとします。
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 を作成したいと考えていますFPS=30
。これは、シンボリックリンクを作成することにより、他の回答と同様に実行できます。たとえば、次の名前001.png
を付けて035.png
使用します。
ffmpeg -i 03%d.png
別の方法は、ffmpeg
のconcat-featureを利用することです。残念ながら、この機能はビデオ ストリームを想定しているため、これは言うは易く行うは難しです。つまり、画像を必要なだけループさせる必要があります。
500 ミリ秒間隔で 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 demuxerは、先頭にキーワードfile
. 現在の作業ディレクトリが乱雑にならないように (または、書き込み権限がない可能性もあります)、 process substition を使用します<( ... )
。ただし、これによりファイルが作成/dev/fd/
され、相対ファイル名が使用されている場合、次のようなエラー メッセージが表示されます。
[concat @ 0xc181c0] Impossible to open '/dev/fd/5K1OCNKToUu.png'
そのため、絶対パスが指定されています。ただし、デフォルトでは絶対パスは許可されていないため、次のようになります。
[concat @ 0x17da1c0] Unsafe file name '/home/5K1OCNKToUu.png'
それを解決するために-safe 0
使用されます。
で入力フレームレートを指定しようとすると-r
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 を想定してタイムスタンプを生成します。これは、image2 や v4l2 などの一部の入力形式に使用される -framerate オプションと同じではありません (以前のバージョンの FFmpeg では同じでした)。疑わしい場合は、入力オプション -r の代わりに -framerate を使用してください。
これについての私の見解は、画像の再生長が見つからなかったことを通知する concat からの上記の警告は、 との concat 警告の後にフレームレートが強制されるため、悪い動作にはならないということです-r
。これは機能しますが、意図した方法ではありません。これは、ffmpeg コマンドを手動で記述するときにのみ使用しますが、スクリプトでは使用しません。
最初に指定されたファイル名のリストを操作する小さなスクリプトをまとめます。
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[@]}
上記のコードでコメントを外した行は、H264 でエンコードされた mkv を提供します。
異種のイメージ タイプ
イメージ リストにさまざまなタイプのイメージが含まれている場合 (たとえば、 in に置き換えhjruIcoN0aTn.png
たhjruIcoN0aTn.jpg
場合frames
)、この の使用法は機能しconcat
ません。最初に指定された以外の形式の画像はドロップされ、次のようなエラーがスローされます。
[png @ 0x1ec8260] Invalid PNG signature 0xFFD8FFE000104A46.
Error while decoding stream #0:0: Invalid data found when processing input
この場合、単純なデマルチプレクサの代わりにconcat フィルタを使用する必要があります。上記の 3 つのファイルを使用するコマンドは、次のように変更する必要があります。
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
説明:
使用される各オプションは、ここで非常によく説明されています。このオプションは画像インポーター-framerate
に固有のものであり、少なくとも技術的には とは異なることに注意してください。この場合、実際には同じ結果が得られます。-r
1 つの-thread_queue_size
イメージを非常に長い 500 ミリ秒延長すると、次のエラー メッセージが表示されるため、これが必要と思われます。
[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)
オプションの説明は、過度に大きな遅延が原因であると考える理由を与えてくれました:
-thread_queue_size サイズ (入力) このオプションは、ファイルまたはデバイスから読み取るときにキューに入れられるパケットの最大数を設定します。低遅延/高レートのライブ ストリームでは、パケットがタイムリーに読み取られない場合、パケットが破棄される可能性があります。この値を上げると回避できます。
これらすべてを再びスクリプトに入れます。
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[@]}
非常に奇妙な理由により、上記のコマンドはそのままでは機能しません!!! . 私の場合、指定された 35 フレームのうち 33 フレームが警告やエラー メッセージなしでドロップされました。
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
これが奇妙である理由は、2倍の遅延を意図したように完全に機能するためです。つまり、各画像が2フレーム表示されます。つまり、次のように変更1/$FPS
され2/$FPS
ます。
frame= 70 fps=0.0 q=-0.0 Lsize= 701kB time=00:00:02.33 bitrate=2465.4kbits/s speed= 2.9x
この事実は、簡単な回避策を示唆しています。フレームレートを 2 倍にしてエンコードし、各画像を 2 フレーム表示します。しかし、それは無駄であり、どうせ好ましいことではありません。