Saturday 18 August 2012

iPod/iPhone Video Encoding with ffmpeg and mplayer

Up until fairly recently, I've been transcoding videos for playback on my (ancient, 1st-gen) iPod Touch using mencoder. But it's less than ideal. mencoder is, by admission of core mplayer devs, an unsupported, unmaintained piece of software that may or may not work at any given moment, and which isn't particularly high on the fixit list. When it comes to transcoding, ffmpeg is the better platform.


ffmpeg isn't too great with subtitles, and I watch a great deal of subtitled content. So what's really required is something that's as good at playback and subtitle rendering as MPlayer, but with FFmpeg's encoding capabilities. So the answer really is to use both: mplayer to write raw video frames to a pipe, and ffmpeg to transcode from that pipe. As a final step, package the encoded video in an iPod-ready m4v file and copy the audio stream(s) from the original source:

mkfifo a-named-pipe.fifo

mplayer a-source-file.mkv -noconfig all -vf-clr -nosound -benchmark -ass -vf scale=480:-10 -vo yuv4mpeg:file=a-named-pipe.fifo

This will block immediately, as there's nothing reading from the pipe that mplayer is writing to, and the pipe only has a small buffer. In another terminal (in the same directory), run this to pull video frames from the pipe into ffmpeg:

ffmpeg -i a-named-pipe.fifo -vcodec libx264 -b:v 768k -flags +loop+mv4 -cmp 256 -partitions +parti4x4+parti8x8+partp4x4+partp8x8+partb8x8 -me_method hex -subq 7 -threads auto -trellis 1 -refs 5 -bf 0 -coder 0 -me_range 16 -profile:v baseline -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qmin 10 -qmax 51 -qdiff 4 -y video-only-file.avi

Once mplayer terminates at end-of-file, you'll have video-only-file.avi, a silent-movie AVI encapsulating a video stream that's iPod-ready. If you had subtitles, they're burned into the video. You can discard a-named-pipe.fifo. Now, you just need to take the encoded video in the AVI, splice in an AAC version of the audio stream from the original source, and pack it into an M4V container that your device can work with.

ffmpeg -i a-source-file.mkv -i video-only-file.avi -acodec libfaac -b:a 128k -ac 2 -vcodec copy -f ipod -map 0:a -map 1:v -metadata title=My Video -y output-video.m4v

Once you've checked that output-video.m4v is good, you can discard the intermediate video-only-file.avi.

Now, this all looks like a lot of hassle (and it kind of is), but it's far more resilient and reliable than the mencoder-only version. It even gives you chapters and multiple audio streams, if they were in the source.

If all that's a bit too fussy, I've wrapped it up in a Perl script hosted on GitHub, meaning that you can do everything with just:

perl --title='My Video Title' --standalone input-video.mkv

Feedback and improvement suggestions are always welcome.