I recently had reason to convert some video files to a format that would be friendly to iDevices, and so I spent some time figuring out a formula that worked nicely. Now you can use it, if you like, so you don’t have to do the same trawling through the internets.
Here’s the command, in bash
format:
vid2m4v () {
ffmpeg \
-i $1 \
-vcodec libx264 -crf 20 -preset slow \
-acodec libfdk_aac -vbr 4 \
-pix_fmt yuv420p \
-movflags +faststart \
-profile:v high -level 4.2 \
${1%.*}.m4v
}
I’ll go through the options line by line. I’m not going to include
the continuation character (\
) since that gets tiresome. You know
what to do with those already, I hope.
vid2m4v () {
This just defines a bash function, so you can call it nicely instead of having to remember all the options every time.
ffmpeg
The name of the command, of course.
-i $1
This tells ffmpeg which file to use as input. The $1
means, use
the first argument to the function. So you would call the bash
function like vid2m4v my_cool_video_file.avi
or whatever.
-vcodec libx264 -crf 20 -preset slow
OK, now we’re getting into the real stuff. This tells ffmpeg to
use the libx264
encoder for the video channel (thus the vcodec
bit), meaning we want H.264 video, which iDevices like.
The -crf 20
part indicates the Constant Rate Factor, which basically
just means what quality level we want. The range varies for this
parameter, depending on what codec you’re using, but 20 is a nice
reliable value.
The -preset slow
part tells ffmpeg how hard to work on squeezing
our precious video down before writing it into the output file.
There are a bunch of different presets, but the slow one is my favorite.
-acodec libfdk_aac -vbr 4
This line tells ffmpeg to use the FDK AAC encoder for our audio channels, and to use variable bit rate encoding, with a quality level of 4, which is pretty good without being obsessive about it. You may not have the FDK library compiled into your version of ffmpeg, since it has had some legal shenanigans swirling around it in the past, thanks to software patents and all the nastiness that they entail. If ffmpeg complains that it doesn’t know what the libfdk_aac encoder is, look at the ffmpeg help page listed below to find which AAC library to use instead.
-pix_fmt yuv420p
This line specifies which format of pixels ffmpeg should use when writing out the video. Apple devices only recognize this format, apparently, so it’s kind of important to specify it here.
-movflags +faststart
This line enables “web-optimized” MP4 output–in other words, it moves the metadata for the file to the beginning so the player knows the important stuff before the rest of the file has to be downloaded.
-profile:v high -level 4.2
This line specifies which kind of H.264 video we want, compatibility-wise. This particular specification is for fairly recent devices (iPhone 5s and later, for example.) You may need to adjust this if your video might be viewed by people with older hardware. See the ffmpeg help page listed below for details.
${1%.*}.m4v
This bizarre-looking piece of line noise (just dated myself I guess)
is a bit of bash syntax that chops off the file extension to keep things
tidy, and then adds on the m4v
extension that belongs with the kind of
H.264/AAC data we’re generating. You can use that part before the .m4v
in other bash scripts too–there’s a whole range of wonderful
weirdness you can do with bash to extract various parts of a variable’s
value. Google “bash parameter expansions” for all the gory details.
OK, that should work. At least it did for me. Hopefully it produces decent-quality video for you.
Here are the aforementioned ffmpeg help pages in regard to H.264 and AAC encoding:
H.264: https://trac.ffmpeg.org/wiki/Encode/H.264
AAC: https://trac.ffmpeg.org/wiki/Encode/AAC
Happy encoding!
Update 2018-05-03: For more detail than you ever wanted to know about ffmpeg settings for good H.264 encoding results, take a look at this article from Jason Robert Carey Patterson.