FFmpeg – How to Transition Smoothly Between Two Videos Using Command Line

avconvcommand lineffmpegscriptingvideo

I want to output a video using two videos as input, where these two videos fade (or dissolve) into each other in a smooth and repetitive manner, every second or so. I'm assuming a combination of ffmpeg with melt, mkvmerge, or another similar tool might produce the effect I'm after. Basically, I want to use ffmpeg to cut up video A according to a specific interval, discarding every second cut up (automatically). Likewise for video B, but in this case inverting the process to retain the discarded parts. I wish to then interweave these parts.

The file names should be correctly formatted so that I can then concatenate the result using a wild card command argument or batch processing list, as per one of the aforementioned tools. The transition effect (e.g. a "lapse dissolve") isn't absolutely necessary, but it would be great if there were a filter to achieve that too. Lastly, it would also be great if this process could be done with little to no re-encoding, to preserve the video quality.

I've read through this thread and the Melt Framework documentation, in addition to the ffmpeg manual.

Best Answer

Assuming both videos have the same resolution and sample aspect ratio, you can use the blend filter in ffmpeg.

A couple of examples,


ffmpeg -i videoA -i videoB -filter_complex \
       "[0][1]blend=all_expr=if(mod(trunc(T),2),A,B);\
        [0]volume=0:enable='mod(trunc(t+1),2)'[a]; [1]volume=0:enable='mod(trunc(t),2)'[b];\
        [a][b]amix"  out.mp4

Straight cuts.

Output:

time,  in seconds,
[0,1) -> videoB
[1,2) -> videoA
[2,3) -> videoB
...
[2N  ,2N+1) -> videoB
[2N+1,2N+2) -> videoA

ffmpeg -i videoA -i videoB -filter_complex \
       "[0][1]blend=all_expr='if(mod(trunc(T/2),2),min(1,2*(T-2*trunc(T/2))),max(0,1-2*(T-2*trunc(T/2))))*A+if(mod(trunc(T/2),2),max(0,1-2*(T-2*trunc(T/2))),min(1,2*(T-2*trunc(T/2))))*B';\
        [0]volume='if(mod(trunc(t/2),2),min(1,2*(t-2*trunc(t/2))),max(0,1-2*(t-2*trunc(t/2))))':eval=frame[a]; [1]volume='if(mod(trunc(t/2),2),max(0,1-2*(t-2*trunc(t/2))),min(1,2*(t-2*trunc(t/2))))':eval=frame[b];\
        [a][b]amix"  out.mp4

Each input's video/audio for 2 seconds with a 0.5 second transition.

Output:

time,  in seconds,
[0,0.5) -> videoA fades out 1 to 0 + videoB fades in from 0 to 1
[0.5,2) -> videoB
[2,2.5) -> videoB fades out 1 to 0 + videoA fades in from 0 to 1
[2.5,4) -> videoA
[4,4.5) -> videoA fades out 1 to 0 + videoB fades in from 0 to 1
[4.5,6) -> videoB
[6,6.5) -> videoB fades out 1 to 0 + videoA fades in from 0 to 1
[6.5,8) -> videoA
...
[4N    ,4N+0.5) -> videoA fades out 1 to 0 + videoB fades in from 0 to 1
[4N+0.5,4N+2)   -> videoB
[4N+2  ,4N+2.5) -> videoB fades out 1 to 0 + videoA fades in from 0 to 1
[4N+2.5,4N+4)   -> videoA
Related Question