3

I am trying to make a quick and easy morph video using two frames (png images) with ffmpeg's minterpolate filter, in a bash script on Ubuntu Linux. The intent is to use the morphs as transitions between similar video in a different video editor later.

It will work on 3+ frames/images, but fails using just 2 frames/images.

First the code that works: 3 frames

This is using three 1080p png files:

test01_01.png test01_02.png test01_03.png

input01="test01_%02d.png"

ffmpeg -y -fflags +genpts -r 30 -i $input01 -vf "setpts=100*PTS,minterpolate=fps=24:scd=none" -pix_fmt yuv420p "test01.mp4"

This takes a bit of processing time, then creates a 414kb, roughly three second mp4 video of a morph starting with the first frame, morphing to the second, then morphing to the third.

The code that fails: 2 frames

This is using just two of the same 1080p png files:

test02_01.png test02_02.png

input01="test02_%02d.png"

ffmpeg -y -fflags +genpts -r 30 -i $input01 -vf "setpts=100*PTS,minterpolate=fps=24:scd=none" -pix_fmt yuv420p "test02.mp4"

This almost immediately creates a 262 byte corrupt mp4 file. There are no differences except the number of frames.

Things I've tried:

I have tried this with the Ubuntu default repo version of ffmpeg, and the static 64bit 5.0 and git-20220108-amd64 versions, all with the same result.

I have also tried with a 2-frame mp4 file as the input, with the same result.

Thoughts?

Is this a bug in ffmpeg or am I doing something wrong?

I am also open to any suggestions for creating a morph like this using other Linux-compatible software.

Thank you for any insight!

  • It's not documented, but it looks like `minterpolate` filter requires at least 3 input frames. – Rotem Feb 19 '22 at 09:40
  • why not use a dedicated morphing tool: https://stackoverflow.com/questions/13734714/given-a-pair-of-images-how-to-automatically-create-an-animation-sequence-morphi/71198395#71198395 – kallaballa Jul 28 '22 at 09:07

1 Answers1

4

It is not documented, but it looks like minterpolate filter requires at least 3 input frames.

We may create a longer video using 5 input frames, and keep the relevant part.

For getting the same output as applying Minterpolate filter with only two input images, we may use the following solution:

  • Define two input streams:
    Set test02_01.png as the first input and test02_02.png as the second input.
  • Loop each image at least twice, using -stream_loop
    (test02_01.png is repeated twice and test02_02.png is repeated 3 times).
  • Set the input frame rate to 0.3 fps (it is equivalent to -r 30 and setpts=100*PTS).
    The input arguments are as follows: -r 0.3 -stream_loop 1 -i test02_01.png -r 0.3 -stream_loop 2 -i test02_02.png.
  • Concatenate the two input streams using concat filter.
  • Apply minterpolate filer to the concatenated output.
    The output of the above stage is a video with few redundant seconds at the beginning, and few redundant seconds at the end.
  • Apply trim filter for keeping the relevant part.
    Add setpts=PTS-STARTPTS at the end (as recommended when using trim filter).

Suggested command:

ffmpeg -y -r 0.3 -stream_loop 1 -i test02_01.png -r 0.3 -stream_loop 2 -i test02_02.png -filter_complex "[0][1]concat=n=2:v=1:a=0[v];[v]minterpolate=fps=24:scd=none,trim=3:7,setpts=PTS-STARTPTS" -pix_fmt yuv420p test02.mp4

Sample output (as animate GIF):
enter image description here


test02_01.png:
enter image description here

test02_02.png:
enter image description here

Rotem
  • 30,366
  • 4
  • 32
  • 65
  • Wow! Never would have figured that out! Thank you! And great choice of demo images! :3 – InverseTelecine Feb 23 '22 at 03:15
  • I want to make this work for a variable number of files. I tried this, but it doesn't work. ``` ffmpeg -y -r 0.3 -stream_loop 1 -i %d.jpg -r 0.3 -stream_loop 2 -filter_complex "[0][1]concat=n=2:v=1:a=0[v];[v]minterpolate=fps=24:scd=none,trim=3:7,setpts=PTS-STARTPTS" -pix_fmt yuv420p test02.mp4 ``` Do you have an idea how to solve this? – Christian Dec 16 '22 at 09:20
  • 1
    @Christian Try starting with simple command first: `ffmpeg -y -r 0.3 -i %03d.jpg -vf "minterpolate=fps=24:scd=none" -pix_fmt yuv420p test02.mp4`. Most of the complexities of the above answer are due to the fact that `minterpolate` filter fails to work with just two input frames. – Rotem Dec 16 '22 at 10:58
  • Awesome, that works. However, the effect itself is extremely mushy.. When it morphs from 1 image to another, the time in between it looks actually pretty scare and distracts from the actual image. Is it possible, to a) make the animation a bit clener and b) make the animation faster while showing the actual image longer? – Christian Dec 16 '22 at 13:14
  • And one last question. It seems like the pattern %d.jpg only takes images 0-9. What pattern do I have to use if I want to read picture 0-999.jpg? – Christian Dec 16 '22 at 13:21
  • @Christian about the morph, I didn't know. For file pattern, in Linux try glob pattern. In Windows, I don't know - rename the files to 001.jpg, 002.jpg, ... And use %03d. Using concat demuxer with a text file may also work – Rotem Dec 16 '22 at 13:53