Reputation: 2110
As of 2020 ffmpeg has the xfade filter which can combine videos with a transition. Combining two videos is easy enough:
ffmpeg -i vid1.mp4 -i vid2.mp4 \
-filter_complex [0][1]xfade=transition=pixelize:duration=1:offset=4,format=yuv420p" \
out.mp4
But I don't understand how to combine three videos (so that v1 fades into v2 and v2 then fades into v3. I tried something like this:
ffmpeg -i vid1.mp4 -i vid2.mp4 -i vid3.mp4 \
-filter_complex [0][1]xfade=transition=pixelize:duration=1:offset=4,format=yuv420p[0n1];[0n1][2]xfade=transition=pixelize:duration=1:offset=9,format=yuv420p" \
out.mp4
but that doesn't work. My idea was that 0 and 1, or vid1 and vid2, would be combined into a [0n1] stream with a transition by xfade, and then that 0n1 stream could be combined with vid3 with another filter. As far as I can tell, this includes the first two videos but not the third. What this of course means is that I don't understand how to specify a filtergraph correctly!
How should I use xfade to combine 3 or more videos with transitions between them?
A full example is as follows. Here I'll use three images (because then issues with combining videos at different frame rates are avoided), and smash them all to 500x500 for ease (in the final version they would be letterboxed to keep resolution and so on).
ffmpeg \
-loop 1 -t 5 -i tests/p1.jpg \
-loop 1 -t 5 -i tests/p2.jpg \
-loop 1 -t 5 -i tests/p3.jpg \
-filter_complex "[0]scale=500:500[s0];[1]scale=500:500[s1];[2]scale=500:500[s2];[s0][s1]xfade=transition=pixelize:duration=1:offset=4,format=yuv420p[s01];[s01][s2]xfade=transition=pixelize:duration=1:offset=9,format=yuv420p" out.mp4
I would expect this to create a video which was:
but what I actually get is
and then the video ends. p3 is not included at all.
The output is as follows:
ffmpeg version N-53546-g5eb4405fc5-static https://johnvansickle.com/ffmpeg/ Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 8 (Debian 8.3.0-6)
configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gmp --enable-libgme --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libdav1d --enable-libxvid --enable-libzvbi --enable-libzimg
libavutil 56. 56.100 / 56. 56.100
libavcodec 58. 97.100 / 58. 97.100
libavformat 58. 49.100 / 58. 49.100
libavdevice 58. 11.101 / 58. 11.101
libavfilter 7. 87.100 / 7. 87.100
libswscale 5. 8.100 / 5. 8.100
libswresample 3. 8.100 / 3. 8.100
libpostproc 55. 8.100 / 55. 8.100
Input #0, image2, from 'tests/p1.jpg':
Duration: 00:00:00.04, start: 0.000000, bitrate: 44845 kb/s
Stream #0:0: Video: mjpeg (Baseline), yuvj444p(pc, bt470bg/unknown/unknown), 820x1270 [SAR 150:150 DAR 82:127], 25 fps, 25 tbr, 25 tbn, 25 tbc
Input #1, image2, from 'tests/p2.jpg':
Duration: 00:00:00.04, start: 0.000000, bitrate: 22325 kb/s
Stream #1:0: Video: mjpeg (Baseline), yuvj420p(pc, bt470bg/unknown/unknown), 960x600 [SAR 1:1 DAR 8:5], 25 fps, 25 tbr, 25 tbn, 25 tbc
Input #2, image2, from 'tests/p3.jpg':
Duration: 00:00:00.04, start: 0.000000, bitrate: 15266 kb/s
Stream #2:0: Video: mjpeg (Baseline), yuvj420p(pc, bt470bg/unknown/unknown), 728x669 [SAR 96:96 DAR 728:669], 25 fps, 25 tbr, 25 tbn, 25 tbc
File 'out.mp4' already exists. Overwrite? [y/N] y
Stream mapping:
Stream #0:0 (mjpeg) -> scale
Stream #1:0 (mjpeg) -> scale
Stream #2:0 (mjpeg) -> scale
format -> Stream #0:0 (libx264)
Press [q] to stop, [?] for help
[swscaler @ 0x8228040] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0x8258640] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0x827df40] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0x829f800] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0x82c13c0] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0x82e8340] deprecated pixel format used, make sure you did set range correctly
[libx264 @ 0x77b7600] using SAR=82/127
[libx264 @ 0x77b7600] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 0x77b7600] profile High, level 3.0, 4:2:0, 8-bit
[libx264 @ 0x77b7600] 264 - core 161 r3018 db0d417 - H.264/MPEG-4 AVC codec - Copyleft 2003-2020 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=6 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'out.mp4':
Metadata:
encoder : Lavf58.49.100
Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv420p, 500x500 [SAR 82:127 DAR 82:127], q=-1--1, 25 fps, 12800 tbn, 25 tbc (default)
Metadata:
encoder : Lavc58.97.100 libx264
Side data:
cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
frame= 101 fps=100 q=28.0 size= 0kB time=00:00:01.92 bitrate= 0.2kbits/s speed=[swscaler @ 0x8291d80] deprecated pixel format used, make sure you did set range correctly
Last message repeated 2 times
[swscaler @ 0x82b3000] deprecated pixel format used, make sure you did set range correctly
Last message repeated 2 times
[swscaler @ 0x82fc200] deprecated pixel format used, make sure you did set range correctly
Last message repeated 2 times
frame= 153 fps=101 q=28.0 size= 0kB time=00:00:04.00 bitrate= 0.1kbits/s speed=[swscaler @ 0x82fc200] deprecated pixel format used, make sure you did set range correctly
Last message repeated 2 times
frame= 225 fps=111 q=28.0 size= 256kB time=00:00:06.88 bitrate= 304.9kbits/s dup=0 frame= 225 fps= 95 q=-1.0 Lsize= 267kB time=00:00:08.88 bitrate= 245.9kbits/s dup=0 drop=125 speed=3.74x
video:263kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.293847%
[libx264 @ 0x77b7600] frame I:2 Avg QP:21.03 size: 19928
[libx264 @ 0x77b7600] frame P:66 Avg QP:21.18 size: 2453
[libx264 @ 0x77b7600] frame B:157 Avg QP:29.72 size: 427
[libx264 @ 0x77b7600] consecutive B-frames: 5.3% 4.4% 1.3% 88.9%
[libx264 @ 0x77b7600] mb I I16..4: 29.0% 27.8% 43.2%
[libx264 @ 0x77b7600] mb P I16..4: 10.8% 3.2% 7.5% P16..4: 2.6% 0.9% 0.3% 0.0% 0.0% skip:74.8%
[libx264 @ 0x77b7600] mb B I16..4: 1.1% 0.5% 1.6% B16..8: 1.0% 0.5% 0.1% direct: 0.3% skip:94.9% L0:37.4% L1:43.5% BI:19.1%
[libx264 @ 0x77b7600] 8x8 transform intra:16.5% inter:55.3%
[libx264 @ 0x77b7600] coded y,uvDC,uvAC intra: 31.4% 71.7% 31.8% inter: 1.1% 1.4% 0.1%
[libx264 @ 0x77b7600] i16 v,h,dc,p: 45% 46% 9% 1%
[libx264 @ 0x77b7600] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 25% 30% 27% 6% 1% 1% 2% 1% 7%
[libx264 @ 0x77b7600] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 56% 31% 9% 1% 1% 1% 1% 1% 1%
[libx264 @ 0x77b7600] i8c dc,h,v,p: 46% 27% 23% 4%
[libx264 @ 0x77b7600] Weighted P-Frames: Y:10.6% UV:7.6%
[libx264 @ 0x77b7600] ref P L0: 61.9% 17.1% 13.9% 6.8% 0.3%
[libx264 @ 0x77b7600] ref B L0: 76.3% 22.8% 0.9%
[libx264 @ 0x77b7600] ref B L1: 97.6% 2.4%
[libx264 @ 0x77b7600] kb/s:238.88
Upvotes: 3
Views: 2467
Reputation: 92928
The offset for the 2nd xfade is wrong. With 5 seconds clips, and 1 second transition at the tail of each clip, the 2nd clip starts at 4s and ends at 9s, so the offset for the 2nd xfade should be 8, not 9.
So,
ffmpeg \
-loop 1 -t 5 -i tests/p1.jpg \
-loop 1 -t 5 -i tests/p2.jpg \
-loop 1 -t 5 -i tests/p3.jpg \
-filter_complex "[0]scale=500:500[s0];[1]scale=500:500[s1];[2]scale=500:500[s2];[s0][s1]xfade=transition=pixelize:duration=1:offset=4,format=yuv420p[s01];[s01][s2]xfade=transition=pixelize:duration=1:offset=8,format=yuv420p" out.mp4
Upvotes: 2