Sunday, September 30, 2012

Batch Processing Movies with Ruby and the HandBrake Command Line Interface

A project I was recently working on required a lot of video transformation work, of which, 98% could be automated with the right tools.  More importantly, I was constantly tweaking video settings (aspect ratio, quality), which required me to reprocess the whole batch of videos.  After a serious case of carpal tunnel from repetitively clicking the same commands in HandBrake, I decided I needed to find a better strategy.

Back in the day, I used to be pretty savvy with encoding tools, but ever since I discovered HandBrake (http://handbrake.fr/), I've never really had the need to keep up.  After looking at FFMPEG and a couple of other CLI tools, I discovered HandBrake had a CLI interface (http://handbrake.fr/downloads2.php) that was, like the GUI, ridiculously easy to use.

For example, my task included shrinking a movie to 560x416 pixels and stripping the audio:
HandBrakeCLI -i input.mp4 -o output.mp4 -e x264 -2 -O -q 20 \
  -a none -w 560 -l 416 --modulus 16 --loose-anamorphic
This is a breakdown of the task's parameters:
  • -i = input file
  • -o = output file
  • -e = encoder
  • -2 = two pass encoding
  • -O = optimize for HTTP streaming
  • -q = quality
  • -a = audio
  • -w = width
  • -l = height
  • --modulus = ratio for resizing the video
  • --loose-anamoprhic = ensures dimensions are resized cleanly by the modulus
The CLI is pretty simple, and the documentation is uncharacteristically (for open source)  complete.  To see a more complete list of arguments for the CLI, please see:  https://trac.handbrake.fr/wiki/CLIGuide.

Now all we need to do is throw in some automation.  This could be done in a number of languages (BASH, Python, Perl, NodeJS), but for tasks like this, I prefer Ruby.

The following is an easy little script for looping over all of the mp4's in a directory and executing a HandBrake encoding (in my case two):
def get_base_name(video)

  video[0, video.index(".mp4")]
end

Dir.glob("*.mp4") do |input_video|

  base_name = get_base_name input_video

  output_video_med = "../#{base_name}_560x416.mp4"

  output_video_sml = "../#{base_name}_224x160.mp4"

  settings = "-e x264 -2 -O -q 20 -a none"

  picture_med = "-w 560 -l 416 --modulus 16 --loose-anamorphic"

  picture_sml = "-w 224 -l 160 --modulus 16 --loose-anamorphic"

  command_med = "HandBrakeCLI -i #{input_video} -o #{output_video_med} #{settings} #{picture_med}"

  command_sml = "HandBrakeCLI -i #{input_video} -o #{output_video_sml} #{settings} #{picture_sml}"

  puts `#{command_med}`

  puts `#{command_sml}`

end
If you aren't familiar with Ruby, a statement encapsulated with back-ticks (`statement`) will be executed on the command line.

As you can see, the process is pretty simple and is likely to save you a "boat load" of time if you have to perform repetitive video processing tasks.  I can also see this process being integrated into a solution that involves automatically transcoding videos for a rich media site that allows users to upload videos.


1 comment:

  1. Can't you accomplish the same thing in the HandBrake GUI by adding encoding jobs to the queue and applying a custom preset? That's how I processed all the videos we filmed for the "about us" video.

    ReplyDelete

Note: Only a member of this blog may post a comment.