Reversing a video file on Linux
How to use the commands ffmpeg & sox to reverse a video file on the Linux command line.
A good video editing effect is the reverse. It works well in action shots where the video is paused for a moment before being reversed. Later versions of my preferred video editor kdenlive, supports reversing videos directly from the clips within the project tree. However, the current version I’m using with my Linux distribution doesn’t have the feature, so I looked into how to reverse the video using only command line tools.
Let’s take a look at the finished effect. Below is a short clip where my son jumps into a cupboard and his clothes fall to the floor. This is achieved using a rotoscoping technique. I wanted the video to reverse so that the clothes jump back up from the floor and my son jumps backwards out of the cupboard.
It makes him laugh every time he watches it.
To reverse any video on the Linux command line, you need to do it five simple steps which are outlined below. However, before you start you’ll need to ensure that you have both the
sox commands installed on your machine. On a Debian/Ubuntu Linux distribution use the following
apt-get commands to update your packages and install the required tools.
sudo apt-get update sudo apt-get install ffmpeg sox
Step 1 - Exact the audio from the video
Beside reversing the video, we also need to reverse the audio. So the first step in the process is to extract the audio track from the video and save it as a
.wav file. We use
ffmpeg to process the video file
input.mp4 and dump the audio to its own file.
ffmpeg -i input.mp4 -vn -ac 2 audio.wav
Step 2 - Reverse the audio
The second step involves using the
sox command to reverse the audio. We pass in the audio file created in step 1 and produce a new audio file called
sox -V audio.wav backwards.wav reverse
Step 3 - Extract each video frame as an image
The third step involves extracting each frame of the video and saving it as an image file. As the
ffmpeg command reads the video file it creates sequentially numbered jpg files starting from one. This will create a lot of jpg files depending on how long your video clip is. For example a ten second clip filmed at thirty frames per second will produce 300 image files.
We create the numbered image files so that when we reassemble the video we can feed the images back into the
ffmpeg command in reverse order.
So this is how you create the individual images for each frame
ffmpeg -i input.mp4 -an -qscale 1 %06d.jpg
Step 4 - Reassemble the images & audio
The forth step is to reassemble all the images back into a video merging in the reversed audio. As the individual frame images were created in order, the later frames will have the latest modification date/time. So in the command below we are using the list command with the
-t switch which sorts the jpg files by modification time, with the newest files being first in the list.
cat $(ls -t *.jpg) | ffmpeg -f image2pipe -vcodec mjpeg -r 30 -i - -i backwards.wav -vcodec libx264 -vpre slow -crf 20 -threads 0 -acodec flac reversed.mkv
We then pipe the list of files into the
ffmpeg command supplying the backwards.wav file as the audio input. After the command has run we are left with a new video file called reversed.mkv
You also need to supply the frame rate that the original video was captured in. In the above example I’m using a frame rate of thirty frames per second
-r 30. If the video was originally filmed on an action camera like the GoPro and you’d used sixty frames per second, then you would need to change the value of the
-r switch to
Step 5 - Delete all the image files
Finally you can delete all the frame image files by using the
Slowing down the reverse
Sometimes it’s fun to do a slow motion reverse. To achieve this you also need to slow down the audio. You can use an additional
sox command after step two to slow the backwards.wav file to half its original speed.
sox -V backwards.wav halfspeed.wav speed 0.5
Then when you’re reassembling the video you would include the halfspeed.wav file and reduce the frame rate by half.
cat $(ls -t *.jpg) | ffmpeg -f image2pipe -vcodec mjpeg -r 15 -i - -i halfspeed.wav -vcodec libx264 -vpre slow -crf 20 -threads 0 -acodec flac reversed.mkv