ffmpeg: A recipe for HD video on portables
The first thing people are likely to ask about this article is how to rip a blu-ray disk. Unfortunately, I’ll have to leave that task for you to figure out. There are plenty of places on the net to find this information. I’d suggest you visit www.doom9.org and poke around there to find your answer. Once you have your HD video ripped, that’s where this article will help you produce a high quality portable video experience for your tablet or phone.
What is ffmpeg?
I’ll start with an analogy. What sox is to audio, ffmpeg is to video (and audio). Sox is a great tool if you need to manage wave files, mp3s or au files. But, these audio formats are not so great when you want to use it as a soundtrack in a video. That’s where ffmpeg shines.
Ffmpeg is a tool that converts one video + audio format into another. For example, a blu-ray disk contains a file format known as m2ts. This is a type of container that holds various types of video, audio, chapter and subtitle information (many times, several of these). However, the m2ts file, while playable with VLC, is not so playable on an iPad, iPod or a Samsung Galaxy Tab. In fact, portables won’t play the formats contained in an m2ts container. Of course, it’s not that you’d want to play this format on your tablet because an m2ts file can be 25G-40G in size. Considering an iPad has, at most, 128GB, you’d only be able to store about 3 of these honking videos.. not that you’d actually be able to play them as the format is incompatible. To the rescue, ffmpeg.
ffmpeg and video containers
The format of choice that Apple prefers is H264 + AAC. The first thing I will say about this is that the libraries needed to get ffmpeg to produce this format are not in the pre-compiled version. Instead, you’ll need to set aside a weekend to compile up the latest version of ffmpeg with the non-free libraries. By ‘non-free’, that means these libraries are potentially encumbered by copyrighted or patented code. For this reason, the pre-compiled versions do not contain such code. Therefore, it’s impossible to produce an H264 + AAC mp4 video file with the pre-compiled versions. This means you have to compile it yourself.
Explaining how to compile ffmpeg is a bit beyond the scope of this article. If you are interested in this topic, please leave a comment below and let me know that you’re interested in such an article. I will state, of compiling this, that the –enable-free option when running configure on ffmpeg is only half the battle. You first need to go get the non-free libraries and compile them up separately. Then, when compiling ffmpeg, reference the already compiled non-free AAC shared libraries so that ffmpeg can link with them. ‘Nuf said about compiling it.
The good thing about ffmpeg is that this tool understands nearly every video container type out there. This includes VOB (DVD format) and m2ts (blu-ray format). For what it’s worth, it also understands HD-DVD format even though this format is long dead.
Converting with ffmpeg
There are what seem like a ton of options when you type in ‘ffmpeg –help’. In fact, the help is so daunting as to turn off many beginners who might look for something else. Yes, there are tons of options that can tweak the resulting video file output. That’s why this article is here. I have found what I believe to be the perfect video conversion method from 30GB m2ts format to around 3GB files that fit quite comfortably on an iPad or Galaxy TabS and still retain HD quality. Without further adieu, let’s get to the recipe:
/usr/local/bin/ffmpeg -y -i “/path/to/input.m2ts” -f mp4 -metadata title=”movie_title” -vcodec libx264 -level 31 -s 1920×1080 -vf crop=1920:800:0:140 -b:v 3600k -bt 1024k -bufsize 10M -maxrate 10M -g 250 -coder 0 -partitions 0 -me_method dia -subq 1 -trellis 0 -refs 1 -flags +loop -cmp +chroma -me_range 16 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qcomp 0.6 -qmin $qmin -qmax $qmax -qdiff 4 number_of_cpu_cores -pass 1 -acodec libfdk_aac -cutoff 20000 -ab 192k -ac 2 “/path/to/output.mp4”
/usr/local/bin/ffmpeg -y -i “/path/to/input.m2ts” -f mp4 -metadata title=”movie_title” -vcodec libx264 -level 31 -s 1920×1080 -vf crop=1920:800:0:140 -b:v 3600k -bt 1024k -bufsize 10M -maxrate 10M -g 250 -coder 0 -partitions 0 -me_method dia -subq 1 -trellis 0 -refs 1 -flags +loop -cmp +chroma -me_range 16 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qcomp 0.6 -qmin $qmin -qmax $qmax -qdiff 4 number_of_cpu_cores -pass 2 -acodec libfdk_aac -cutoff 20000 -ab 192k -ac 2 10 “/path/to/output.mp4”
Note that the libfdk_aac is a non-free library which will not be in the free and pre-compiled version.
Two Passes? Doesn’t that take longer?
Yes, it does. Two passes are necessary to provide the best motion quality in the video. The first pass retrieves statistics about each frame transition of the film and stores it in a statistics file. The second pass reads this very large first-pass-created (~2 GB) statistic file and uses it to creates smooth transitions between each frame of the output video. For this reason, you need to make sure to have plenty of disk space free. This two-pass system removes the herky-jerky video experience (especially with horizontal camera pans). Ultimately, what you’ll find is that the recipe above gives the absolute best quality and size I’ve yet to find from any conversion. For a 90-120 minute film, you’re looking at around a 2.5G-4G resulting mp4 for full 1080p + stereo audio. This file is compatible with the iPad and the Samsung Galaxy series.
Conversion of 90-120 minute films can take anywhere between 40 to 70 minutes for each movie conversion. You can run them in parallel on your system, but you’ll need to run them in separate directories to keep the statistics files in the first pass separate.
Stereo audio? Why Stereo?
I always convert down to stereo for good reason. These videos are intended to be used on portable devices. I’ve yet to see any tablet, computer or phone support 5.1 or 7.1 audio with the built-in audio hardware. Leaving the multi-channel audio intact is basically pointless and consumes extra disk space. Sure, if you want to export the video and audio to something like the Apple TV, it might be handy to have. But then, you’d probably want to stream the m2ts file rather than a slightly more sucky mp4. After all, converting to mp4 is equivalent to ripping a CD audio to mp3. It makes the size of the file much smaller, but is also lossy. However, in this case, sucky isn’t sucky at all and most portable devices support stereo.
In other words, the output is stereo because portable devices don’t support multichannel audio. At least, not yet.
How good is the video quality?
Excellent. It’s will not be exactly the same quality as the m2ts file (that’s not possible considering it is being compressed), but when viewing on a portable, it’s practically like watching a blu-ray disk. The video is still 1080p. It’s that good, all in about 3GB size. Note the crop size above. It is designed to remove the black bars from the top and bottom. When blu-rays are encoded, they are encoded full 16:9 even when the video may be wide screen. This means that the black bars are stored as extra video information in the video file. Removing this unnecessary black space eliminates encoding this blank video, thus reducing the size of the output file. Because these black bars are totally unnecessary, it also makes for a better viewing experience when watching the video in a picture-in-picture style window.
However, the crop value given is intended to be used with widescreen 2.35:1 and 2.39:1 films that have been produced since the mid-1970s. Widescreen films produced in the 1960s and before have a different aspect ratio and using this crop value will cut off pieces of the top and bottom. There are also some films that use unique and creative aspect ratios that may not work with that crop value. Also, many animated films are full 16:9, so you’ll want to remove the -vf crop=1920:800:0:140 argument entirely to prevent ffmpeg from cropping.
To calculate crop, here’s how to do it. The arguments are crop=:::. Here’s the table:
- hwidth = horizontal width of input video
- vheight = vertical height of video
- hoffset = how much to move the video horizontally (into frame)
- voffset = how much to move the video vertically (into frame)
Note that my crop recipe above does no horizontal cropping, but it can be done just as vertical cropping. For the vertical cropping, note that I’ve reduced the frame canvas size from 1080 to 800 to make the frame the proper aspect ratio. But, reducing the frame size from 1080 to 800 only changes the size of the video canvas. It doesn’t move the content back into frame, yet. To do that, you need hoffset and voffset. To calculate the voffset value and move the video into the newly sized canvas, you need to fill in the voffset value. To do that, subtract 800 from 1080. So, 1080 – 800 = 280. Then, divide that subtracted value by 2. So, 280 / 2 = 140. The voffset value is 140. About cropping, one thing is important to note. If you divide the value and get floating point number like 141.2222. You can’t use this. You need to adjust the voffset value so that it is always a whole number. To do this, ensure when you subtract your vertical size from 1080, it always results in an even number so that the division by 2 also results in a whole number.
VBV underflow warnings?
Note that when converting some content, the conversion output may occasionally show VBV underflow. This is intentional. While it is possible to get rid of these warnings by raising or removing the -bufsize and -maxrate options, raising this value may also increase the size of the output movie file. This underflow warning means that there’s just too much input to be stored in the requested output bitrate. That’s why I say this video won’t be exactly identical to the input file. This selected settings given provide the perfect marriage between size, quality and functionality. If you raise or eliminate the -maxrate option to get rid of the warnings, so too will the size increase of the output video file. Because I prefer the mp4 file sizes to remain in the 2.5-4GB size range and because the VBV underflow warnings do not materially impact the resulting output file, I have chosen not fix this issue. However, if you would like to get rid of these warnings, you can remove the arguments -bufsize 10M -maxrate 10M or increase these values as you see fit. However, you might want to read this wiki article describing the interrelationships between -b:v, -bufsize and -maxrate.
Because I also want the final videos to have the most steady bitrate possible (very important for any kind of streaming), I allow the VBV underflow warnings. Removing the -maxrate and -bufsize options (to get rid of the warnings) will allow the bitrate to vary wildly at times. This can cause unsteady or choppy playback in some players, especially when network streaming. To avoid wild variability in the bitrate, I intentionally force -bufsize and -maxrate to be a specific size.
Enjoy the recipe. Hopefully, it’s helpful. If you get good results from these ffmpeg recipes, please leave a comment below. Also, feel free to tweak the recipes with however you see fit. If you find something even better than what I show above, please post a comment below and let me know what you did. I’m always interested in seeing what people can do with ffmpeg.