I have no idea what I'm doing.

Monday, February 15, 2010

Script for bulk encoding videos to H.264 with Handbrake

I'm writing this because I needed a simple way to drop a batch file onto a computer, let it run for a few days, and when I come back all my files have been magically converted to H.264. So before we begin, I'm going to assume you have some knowledge of computers, scripts, and video encoding (Windows, Mac, or Linux). Be careful with the word wraps on this post, the command lines being executed are quite long!

Why H.264?
Much like MPEG2 for DVD video or MP3 for audio, H.264 is a flexible video standard for all sorts of media, such as Blu-ray Discs, web streaming, and portable video devices (iPod Touch or iPhone). Here's a little background information for H.264 and x264:
H.264 is a form of video compression - http://en.wikipedia.org/wiki/H264
x264 is a method(software) for encoding video into H.264 - http://en.wikipedia.org/wiki/X264

One of the things I like so much about H.264 is that it's very flexible. You can encode videos into very high quality HD videos, or something low resolution for use with a phone. The x264 software allows us to make these these adjustments very easily. We'll be using the command line version of Handbrake to do all our encoding. http://handbrake.fr It's free, available for Windows, Mac, and Linux. I'll assume you have the latest version installed at this location: "C:\Program Files (x86)\Handbrake\Handbrake.exe"

Bulk encoding
There's more than a few ways to do this. If you're on a Windows PC probably the simplest way is to use a batch file. If you're like most people, your videos are stored in a particular location. For example, you may have a directory structure like this:
c:\videos
c:\videos\video1\video1.mpeg
c:\videos\video2\video2.avi
c:\videos\video3\video3.xvid
We'll use a batch file to start at the base directory (c:\videos) and work ourselves down through all the subdirectories and encode the video files into H.264. Here's an example batch file that can traverse subdirectories and do something along the way, convert.bat:
@for /r %%F in (*.filetype) do (
 some command here
 some command here
 some command here)

Encoding methods
Handbrake is quite flexible when it comes to importing various file types. I've been able to import DivX, XviD, wmv, etc. One of the most important components of video encoding is the quality. With Handbrake you can handle this three ways:
- setting an average bitrate (1500 kbps for example)
- setting a target file size (Handbrake will adjust the bit rate to fit the requested size)
- setting a constant quality
For our encoding process we'll be using the constant quality method. The first two methods work well if all your videos are from the same source, the same resolution, and using the same codec, but if you have a mixed bag of videos then constant quality is easier to work with.

What quality level should we use?
I'd suggest running a few tests first. Find a video file (the shorter the better, such as a movie trailer), and lets encode it with various levels of quality. In Handbrake, 100% quality is an extreme amount and you'll probably never use something this high. So we'll start with 40%, 50%, 60%, and 70%. After the encoding process is complete, take a look at the file sizes and the level of quality. It may be that you'll need to adjust the level to 65%, or 55%.

I'm encoding my videos for playback on Apple TV, iPhone and iPod Touch. The iPhone\Touch can playback video with a resolution up to 640 x 480 (even though the displayed video is only 480 x 320). You can adjust these settings as well. For example you may want to encode video to 720p or 1080p, to do so just read up on Handbrake's command line switches for -X -Y -w -l, more info here: http://trac.handbrake.fr/wiki/CLIGuide I'm also limiting the audio to 64kbps. You can bump this up as well using the -B switch, something like -B 128.

OK, so you've found a video that you'd like to test. A short video, correct? Place the video in a directory all by itself. Create a new batch with this code in the same directory. Start up a command line windows, navigate to the directory, and run the batch file. Depending on your hardware, this encoding process may take a few minutes, or a few hours if you're using a long video (I told you to use a short video).
@for /r %%F in (*.avi,*.mov,*.wmv,*.mpg,*.mpeg,*.divx) do (
"C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe" -i "%%F" -o "%%~pnF-x40.mp4" -f mp4 -2 -I -O -X 640 -Y 480 -e x264 -q .40 -a 1 -E faac -6 auto -R Auto -B 64 -D 0.0 -m -x level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=400:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subq=6:8x8dct=0:trellis=0:weightb=0:mixed-refs=0 -v 1
"C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe" -i "%%F" -o "%%~pnF-x50.mp4" -f mp4 -2 -I -O -X 640 -Y 480 -e x264 -q .50 -a 1 -E faac -6 auto -R Auto -B 64 -D 0.0 -m -x level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=500:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subq=6:8x8dct=0:trellis=0:weightb=0:mixed-refs=0 -v 1
"C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe" -i "%%F" -o "%%~pnF-x60.mp4" -f mp4 -2 -I -O -X 640 -Y 480 -e x264 -q .60 -a 1 -E faac -6 auto -R Auto -B 64 -D 0.0 -m -x level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=700:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subq=6:8x8dct=0:trellis=0:weightb=0:mixed-refs=0 -v 1
"C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe" -i "%%F" -o "%%~pnF-x70.mp4" -f mp4 -2 -I -O -X 640 -Y 480 -e x264 -q .70 -a 1 -E faac -6 auto -R Auto -B 64 -D 0.0 -m -x level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=900:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subq=6:8x8dct=0:trellis=0:weightb=0:mixed-refs=0 -v 1)

After this batch file runs you should have 4 new videos, each at a different levels of quality. If you'd like to tweak your quality level, you can adjust the -q value up or down, such as -q .55 or -q .65 and you can also adjust the maximum bitrate with the vbv-maxrate=somevalue_kbps.

For my videos, I'm going with these settings:
-2 [two-pass encode]
-T [make the first pass go turbo!]
-O [optimize for web streaming, YAAA]
-I [for 5.5G ipods]
-X 640 [maximum width]
-Y 480 [maximum height]
-q .60 [not bad, not great, good file size]
-B 64 [64kbps is enough for me]

In the batch file, we'll be looking to convert any avi file, divx file, wmv, etc. Place this file in your base video directory (such as c:\videos) and let it run (it may take a while to complete). It will crawl through all your subdirectories looking for video files to convert. We'll also dump our progress to a log file so you can see what video is currently being encoded. And when you put all this together with the other settings, here's what it looks like... aka, the TL;DR section:
@for /r %%F in (*.avi,*.mov,*.wmv,*.mpg,*.mpeg,*.divx) do (
@echo "- starting %%F"  >> convert.log
"C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe" -i "%%F" -o "%%~pnF-x60.mp4" -f mp4 -2 -T -I -O -X 640 -Y 480 -e x264 -q .60 -a 1 -E faac -6 auto -R Auto -B 64 -D 0.0 -m -x level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=700:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subq=6:8x8dct=0:trellis=0:weightb=0:mixed-refs=0 -v 1
@echo "- completed %%~pnF-x60.mp4"  >> convert.log)

If you want date & time in the log file:
@for /r %%F in (*.avi,*.mov,*.wmv,*.mpg,*.mpeg,*.divx) do (
@echo - starting %%F >> convert.log
date /t >> convert.log
time /t >> convert.log
"C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe" -i "%%F" -o "%%~pnF-x60.mp4" -f mp4 -2 -T -I -O -X 640 -Y 480 -e x264 -q .60 -a 1 -E faac -6 auto -R Auto -B 64 -D 0.0 -m -x level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=700:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subq=6:8x8dct=0:trellis=0:weightb=0:mixed-refs=0 -v 1
@echo - completed %%~pnF-x60.mp4 >> convert.log
date /t >> convert.log
time /t >> convert.log)

Other utilities
MediaInfo is an informative little app. And with it's context menu it's very handy. It's good at finding video codec information, audio codec, resolution, bit rate, etc - http://mediainfo.sourceforge.net/en