How to use FFMPEG to Convert Multiple Media Files At Once on Linux

Objective

Write a simple Bash script for FFMPEG batch file conversion.

Distributions

This will work on all Linux distributions.

Requirements

A working Linux install with FFMPEG installed.

Conventions

  • # – requires given linux commands to be executed with root privileges either directly as a root user or by use of sudo command
  • $ – requires given linux commands to be executed as a regular non-privileged user

Introduction

FFMPEG immensely powerful when it comes to manipulating and converting media files, but it’s lacking one important feature. FFMPEG doesn’t have the ability to handle multiple files at once. So, what can you do about it? You’re a Linux user. You’re not going to sit there and manually type in the same command over and over, are you?

FFMPEG is entirely scriptable. So, you can write a simple Bash script to loop through the contents of a specified directory and perform the conversion that you want on each file. While that might sound like a lot, it really isn’t. The script will be less than 20 lines of Bash.

Set Up The File

Start by setting up your file. Make it anywhere that you like.

$ touch ffmpeg-batch.sh

Then, make it executable.

$ chmod +x ffmpeg-batch.sh

Open the file up, and set it up to start writing.

#! /bin/bash

Plan Your Variables

You’re going to need to pass multiple arguments to your script if you want it to be flexible enough to handle most scenarios that you’d use FFMPEG for. Because of that, you’re going to need quite a few variables. Sure, you can use the raw inputs, but it’ll be much harder to keep track.

srcExt=$1
destExt=$2
srcDir=$3
destDir=$4
opts=$5

You have five variables in total; a source extension, a destination or resulting extension, a source directory, a destination directory, and your options. The options are any options that you want in your FFMPEG command. There are other ways to do this, but just passing them in as a string works, and it’s super simple.

The Loop

This script centers around a for loop to iterate over the contents of the specified directory. You need to create that loop next. Begin with just setting up the idea.

for filename in FOLDER; do

done

Of course, FOLDER is nothing. You need to set up the loop to iterate over the contents of a directory, and that directory is stored in srcDir. You also need to tell it that it needs to only loop through the files with a specific extension, srcExt. So, the combination you’re looking for looks like this:

"$srcDir"/*.$srcExt

The wildcard(*) tells it to all files, then the .$srcExt gives it the complete extension to look for. The quotes are necessary around $srcDir to prevent it from treating the whole thing as a string and not working properly.

The whole thing together looks like this:

for filename in "$srcDir"/*.$srcExt; do

done

Your FFMPEG Command

You know the basic FFMPEG syntax, but that doesn’t go too far here. The whole thing is comprised of variables. Speaking of variables, you’re going to need a couple more. In order to get correct pieces for the destination folder and files, the original file names need to be chopped down and reorganized.

First, create a new variable, basePath and set it equal to this regular expression: ${filename%.*}.

basePath=${filename%.*}

The expression strips everything after the . from the path, meaning the extension.

Now, you need to get rid of the path itself. To do that, set baseName equal to ${basePath##*/}.

baseName=${basePath##*/}

That takes care of everything else, up to the filename itself.

You can put together the pieces to form the call to FFMPEG now.

ffmpeg -i "$filename" $opts "$destDir"/"$baseName"."$destExt"

As you can see, it’s the same as a normal call to FFMPEG, but using the variables. The most complicated piece is the destination, but it just combines the individual pieces of the destination to form an entire path with filename and extension.

Wrapping Up

If you want, you can tack on a success message for when the conversion is complete. Throw it at the end of your script after the for loop.

echo "Conversion from ${srcExt} to ${destExt} complete!"

The whole thing should look something like this:

#! /bin/bash

srcExt=$1
destExt=$2

srcDir=$3
destDir=$4

opts=$5

for filename in "$srcDir"/*.$srcExt; do

        basePath=${filename%.*}
        baseName=${basePath##*/}

        ffmpeg -i "$filename" $opts "$destDir"/"$baseName"."$destExt"

done

echo "Conversion from ${srcExt} to ${destExt} complete!"

Run Your Script

Finally, you can now run your script to perform batch file conversions. Take a look at this example to see what the syntax looks like.

$ ffmpeg-batch.sh flac mp3 /path/to/files /path/to/dest '-ab 320k'

It’s not all that much more than normal. Only now, you’re converting an entire directory worth of files, instead of just one.

Closing Thoughts

This script should be flexible enough for most situations, and that includes video. You can add the script to a local or system wide bin path to make it more easily accessible from outside of its directory.



Comments and Discussions
Linux Forum