Search code examples
pythonffmpegffmpeg-python

How do I reverse a video in ffmpeg?


- Full Error:

Stream specifier 's1:v' in filtergraph description [0]split=2:outputs=2[s0][s1];[s1:v]reverse[s2];[s0][s2]concat=a=0:n=2:v=1[s3] matches no streams.

- Formatted Error

  • [0]split=2:outputs=2[s0][s1];
  • [s1:v]reverse[s2];
  • [s0][s2]concat=a=0:n=2:v=1[s3]

- Code:

instances = (
    ffmpeg
    .input(self.video_file)
    .filter_multi_output(filter_name="split", outputs=2)
)
ordered_edits = []
for i in range(2):
    if i%2 == 0:
        ordered_edits.append(
            instances[i]
        )
    else:
        ordered_edits.append(
            instances[i].video.filter(filter_name="reverse")
        )
(
    ffmpeg
    .concat(*ordered_edits, a=0, v=1)
    .output('done/output.mp4')
    .run(overwrite_output=True))

Looking at the error code, it seems like s1:v should be a valid reference. The only thing I can think of is that there is an issue saving an exclusive video input into a nonspecified output. The files don't actually have any audio, I just want the video.

I'm lost, please help ffmpeg experts of the world!


Solution

  • Using .video is redundant here.

    Per the ffmpeg documentation:

    17.33 split, asplit

    Split input into several identical outputs.

    asplit works with audio input, split with video.

    The filter accepts a single parameter which specifies the number of outputs. If unspecified, it defaults to 2.

    In other words, by using a split filter, you are implicitly stripping audio off of the video. I am not totally sure why s1:v is an error, instead of just a no-op, but it does seem to be the cause of the error.

    This works fine for me:

    instances = (
        ffmpeg
        .input("input.mp4")
        .filter_multi_output(filter_name="split", outputs=2)
    )
    ordered_edits = []
    for i in range(2):
        if i%2 == 0:
            ordered_edits.append(
                instances[i]
            )
        else:
            ordered_edits.append(
                instances[i].filter(filter_name="reverse")
            )
    (
        ffmpeg
        .concat(*ordered_edits, a=0, v=1)
        .output('output.mp4')
        .run(overwrite_output=True))
    

    This produces a video where the input video plays, then plays backwards, which I assume is what was intended.