How to Automate FFmpeg and Bento4 With Bash Scripts
In this tutorial, you will learn how to write Bash scripts that run on Ubuntu and encode and package multiple files to HLS/DASH output using open-source tools FFmpeg and Bento4. You’ll learn how to run the scripts directly on folders of content and to set up a watch folder operation. While this is beginner-level stuff, some familiarity with FFmpeg and Bento4 will be helpful, as will some experience with batch processing and working on the command line in Linux or Windows.
You can download all scripts shown in this article here.
The operative catchphrase for this tutorial is "Don’t let perfect be the enemy of the good," which, in various forms, has been attributed to Voltaire, Confucius, Shakespeare, and Mark Zuckerberg ("Done is better than perfect"). This is my way of saying that I know the scripts detailed herein aren’t the most elegant or highly optimized, particularly the script shown in Figure 5. However, they get the job done and should be relatively simple, even for Bash newbies, to understand and implement.
Why Ubuntu?
I spend most of my time on Windows workstations but created this tutorial using Ubuntu because Bash scripting is simpler and more powerful than Windows command-line programming. I use Ubuntu because it’s free, it’s installed on several computers in my office, and it’s easy to create a dual boot to run Windows and Ubuntu on the same computer. Ubuntu also has an easy-to-use GUI that simplifies operations like moving files from one drive or folder to another and a simple text editor that’s ideal for creating Bash scripts.
In this regard, you may be able to run these scripts on the Linux Bash Shell now available for Windows 10, but getting a Linux GUI running on Windows 10 to access file and text editor operations seemed challenging, so I didn’t try. If you have an older workstation around, it should be relatively simple to install Ubuntu and have it function as your encoding server.
Getting Installed
There are multiple LTS (Long Term Support) versions of Ubuntu available. At this point, I would install version 18.04 LTS rather than 16.04 LTS because it’s newer and generally faster, though the instruction here should work on both versions. Just be sure to install the desktop version of Ubuntu, which includes the GUI, rather than the server version, which doesn’t (though you can add it later).
To install Ubuntu on a Windows machine, you’ll download a bootable version of Ubuntu onto a USB drive, boot the computer from that drive, and then install Ubuntu. There are dozens of tutorials to show you how, including one at go2sm.com/ubuntuinstall. If you want to create a dual boot system, be sure to find a tutorial that includes this.
After installing Ubuntu, you’ll have to install FFmpeg 4.x, which you can learn how to do at go2sm.com/ffmpeginstall, and Bento4, which is documented at go2sm.com/ubuntubento4. In both cases, once you install the program, you can call it from a command line or script from any drive location; you don’t need to include the specific address to the executable.
Ubuntu Terminal Navigation Basics
Though you can perform most of the file-related heavy lifting via Ubuntu’s GUI Files application, you’ll have to navigate the Terminal using keyboard commands to execute Bash scripts. There are four commands you absolutely need to know:
pwd
– shows your present working directory
ls
– lists files and folders in current working directory
cd directory
– to change to the listed directory; capitalization matters
cd ..
– to navigate into a lower directory
You can see several of these commands used in Figure 1.
A couple of additional functions will help speed up operation. First, as with Windows, pressing the up and down arrow keys shuttles through batch commands that you’ve used before in the current Terminal session. So, if you’re debugging a batch file, you don’t have to type it in each time you want to run it; just press the up arrow until it appears and click Enter.
The second useful function relates to the Tab key, which attempts to complete whatever command you’re typing. Say you’re switching folders to the Videos folder from the root folder. Assuming that there’s only one folder that starts with capital V, if you type cd V
and press the Tab key, the command will auto-complete to cd Videos/
. Press Enter to navigate to that folder. You can use the same procedure to complete the names of batch scripts in Terminal, saving some keystrokes and avoiding errors.
Obviously, there are dozens of other useful Terminal commands, and you can download a handy cheat sheet for command-line references at go2sm.com/terminalcheats. There are actually two reference sheets at that URL, but when I checked they were reversed, so click the Ubuntu Reference to download the Linux Command Reference (which is the one you want) and vice versa.
Your First Bash Script
Let’s eschew the typical echo=hello world
first Bash script and jump directly into a useful, FFmpeg-related script. Here’s the scenario. I created a 13-video PowerPoint-based tutorial series in Premiere Pro and exported the 720p files at 10Mbps because Adobe Premiere Pro doesn’t offer constant rate factor (CRF) encoding. I want to re-encode these files using CRF encoding because it will dramatically reduce the data rate and upload time with no visible quality hit.
The FFmpeg command for this is simple:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 input_crf.mp4
This tells FFmpeg to input the file, encode using the x264 codec to a CRF value of 23, and to append _crf
to the input file name to name the output file. The 64Kbps mono AAC audio track will automatically copy over, but I could configure audio output as well. It would be simple to create a Windows batch file with entries for each file, but that’s both time-consuming and error-prone and painful to edit if you want to perform the same operation for different files in the future. It’s much easier in Bash. Here are the steps.
1. Open Terminal.
There are many different ways to open the Terminal application. For example, in Figure 1, I opened Terminal in Ubuntu 18.04 LTS by clicking it in the Favorites bar on the left. Once in Terminal, I run through some navigational commands and then create the Bash script.
- The first command is
pwd
, which shows the present working directory, or the directory that I’m currently in. - Then I type lsto list the files and folders in that directory.
- To navigate to the Videos folder and perform these batch operations, I type
cd Videos/
(or cd V
and press the Tab key to auto-complete).
Figure 1. Working in Terminal in Ubuntu 18.04
2. Create the Bash File.
To create the Bash script, I type touch crf.sh
, which creates a file using that name. Note that you don’t technically have to use the .sh
denominator for Bash files, but it’s common practice. Then I type ls
again to list the files in the Videos folder, which include the video files I’ll be converting and the crf.sh
script file I just created.
3. Create the Bash Script.
Create the script in a basic text editor since it won’t insert any funky characters like word processors do. In Figure 2, I opened crf.sh
in the Ubuntu Text Editor by right-clicking crf.sh
and choosing Open with Text Editor. The Text Editor application is shown on the bottom of Figure 2.
- Line 1 – All Bash files need to start with what’s called the shebang, or
#!/bin/bash
.This tells Ubuntu that it’s a Bash script. - Line 3 – We’re using a "for loop" for this Bash file that has two components. First you identify which files you’ll process. The command shown on line 3 identifies these as files with an .mp4 extension in the folder in which I’ll run the script.
- Then we add "do" in line 4 and type the FFmpeg command string to run on those files on line 5.
- The
-i
string identifies the file to be encoded; we add the quotes around the word file and the dollar sign ("$file")
to indicate that we’re retrieving the list of files in the folder, not simply using the word file
in the script. - We do the same in the file name at the end of the command string with the
%.*
added to strip the extension from the output file name and add _crf to the file name ("$[file%.*}_crf".mp4)
. If the input file was inputfile.mp4
, the script would output a file named inputfile_crf.mp4
. -
Done
on line 6 ends the "for" loop.
Figure 2. Working in Files and the Ubuntu Text Editor
Related Articles
FFmpeg was designed as a cross-platform solution for video and audio recording, conversion, and streaming using simple static command lines. Using variables and "for loops" in a command string simplifies the reuse of existing scripts and helps automate their operation. While you can't use these scripts in the Windows Command window, you can use Microsoft PowerShell in Windows and Bash on Linux and the Mac. In this tutorial, you'll learn how to create and run such scripts with PowerShell and Bash.
14 Mar 2023
Rather than focusing on random tasks, this tutorial will walk you through the fundamentals of encoding with the latest version of FFmpeg.
27 Mar 2022
Anyone who does performance or benchmark testing, please take a look: The six commands in this article help with essential tasks that crop up in any studio or encoding facility.
22 Jul 2019
AV1 delivers equivalent quality to HEVC, but with a lower data rate. For now, though, it's slow. A five-second clip took 23 hours and 46 minutes to encode.
27 Sep 2018
Building on previous DIY articles, this installment will walk you through capturing audio, encoding and packaging with FFmpeg, then playing out through the Icecast server you set up in the last article
15 Jun 2018
FFmpeg might be a free download, but there's still a cost that goes with it. Robert Reinhardt explains why this encoder isn't right for every company.
21 Jan 2014