Saturday, 9 February 2008

Encoding videos for the Xbox 360 using ffmpeg

One of the cooler features of Microsoft's Xbox 360 console is the ability to play back video from a USB memory stick or external hard disk. Only problem is, encoding video can be a bit of a hit-and-miss affair at the best of times, and when you're limited to the codecs supported by the Xbox 360 and can't install any more, a bit of trial and error is required to get good results.

For this little exercise, I'm using a 500Gb Western Digital MyBook Essential Edition which is on special offer from amazon.co.uk, right now for £69.99, and I've got the original footage as raw MPEG-2 files.

I've played with lots of video encoders over the years, both commercial and free, and the best one I've ever used in terms of output quality and encoding speed is an open-source command line tool called ffmpeg.

So... let's say we've downloaded a Win32 binary of ffmpeg from here, we've got our source video file as a raw MPEG-2 file (or just about anything that ffmpeg will read); now it's just a matter of finding the right settings for ffmpeg.

According to the Xbox December 2007 Video Playback FAQ:

Xbox 360 supports the following for MPEG-4:

  • File Extensions: .mp4, .m4v, .mp4v, .mov
  • Containers: MPEG-4, QuickTime
  • Video Profiles: Simple & **Advanced Simple Profile
  • Video Bitrate: 5 Mbps with resolutions of 1280 x 720 at 30fps.
  • Audio Profiles: 2 channel AAC low complexity (LC)
  • Audio Max Bitrate: No restrictions.

Your basic ffmpeg command line looks something like:

C:\>ffmpeg [options] [output file]

The particular invocation we need here is:

ffmpeg -i myfile.mpg -f mp4 -vcodec mpeg4 -b 2000000 -acodec libfaac -ac 2 -ab 128000 -s 640x480 m:\output.mp4

Now let's break those options down and explain what they actually mean...

-i myfile.mpg

specifies "myfile.mpg" as the input file
-f mp4 Specifies that the output file should use the MPEG-4 container format
-vcodec mpeg4 Specifies that within the container, the video stream should be encoded using the MPEG-4 codec
-b 2000000 Specifies the video bitrate - in this case 2,000,000 bits per second, or approximately 2Mbit. Much lower and you'll notice lots of compression artefacts; much higher and you'll have problems with the filesize - see below!
-acodec libfaac Specifies that the audio stream should be encoded using the libfaac codec - an open-source implementation of the AAC audio encoding standard.
-ac 2 Specifies that the output should use two-channel (stereo) output. (The X-Box 360 will not play 5.1 audio from a USB device, apparently)
-ab 128000 Specifies the audio bitrate - roughly 128kbps in this example
-s 640x480 Specifies the size of the output file - 640x480. Output video will be resized to fit the specified size but aspect ratio will be preserved.
m:\output.mp4 The last option is the name of the output file (and the USB hard drive is installed on my system as drive M:)

The X-Box 360 only supports USB storage devices formatted using the FAT32 filesystem, and FAT32 is limited to 4Gb per file. You'll therefore need to calculate your bitrates based on the length of the video files you're encoding. 2Mbps means you're using approximately two million bits = i.e. (2000000 / 8) = 250,000 bytes per second, or 250Kb for each second of video - which equates to (250*60*60) = 900,000 Kb = 900Mb per hour, so you can happily encode movies up to 4.5 hours long at 2Mbps before you hit the FAT32 4Gb-per-file ceiling.

You also need to consider the resolution (width x height) of the output. Higher resolutions means a larger - and more detailed - picture, but costs more bandwidth to maintain the same image quality; in other words, for a specific bitrate, you'll have to choose between big and blurry, or small and sharp.

lilies_large

lilies_smallThese image files are both 12.5Kb in size; you can clearly see the compression artefacts in the larger image above, where we've had to discard more detail in the compression process to reach our target file-size. The smaller image doesn't have such pronounced artefacts - but contains less detail to begin with because it's been reduced to fit a smaller frame size.

If you're encoding video to play back on a specific device, you probably want to use the native resolution of your player. Standard HDTV resolutions are 1280x720 and 1920x1080. The iPod Touch has a native resolution of 480x320, the most recent iPod Nano has a resolution of 320x240. Normal DVD video uses a resolution of 720x576 pixels (on PAL systems) or 720x480 (on NTSC systems).

Obviously this is all highly subjective - your own definition of 'acceptable quality' depends on your equipment, your eyes, and the sort of video footage you're working with - but I find 640x480 at 2Mbps seems to work pretty well. Likewise audio bitrate - if you've got very good ears & speakers and you're encoding something like concert footage, you might want to specify an audio bitrate of 256Kbps (-ab 256000) or higher.

Finally, a note about multi-core systems. ffmpeg does not support multi-threading - this means if you've got multiple CPUs or multiple cores, it'll only run on a single core. However, if you're encoding more than one video file, you can quite happily run two instances of ffmpeg in parallel - Windows is smart enough to run each instance on it's own core, so on my quad-core box I can encode four files simultaneously with each encoder running at full speed. My box will encode about 100 frames per second on each core, so running all four cores flat-out I can encode four seperate one-hour video clips in about fifteen minutes.

Finally, plug the drive with your MP4 files into your Xbox 360, go into the Xbox Dashboard, pick "video" and choose the option to play from external device, and away you go. You may find you need to sign in to Xbox Live! to download the required media updates, but this worked perfectly well when I tried it out so it shouldn't cause any problems.

Tuesday, 5 February 2008

Reflections on Alt.Net.UK

altnetukI spent last Friday night and Saturday at the Alt.Net.UK conference here in London. Based on the "open spaces" philosophy, it was an event quite unlike anything I've ever been to...

Actually, that's not quite true. In a strange way, it was the geek equivalent of a really good jam session. If you've ever seen a bunch of musicians get together with no rehearsal and no sheet music, and just improvise a couple of hours of free-form, creative, spontaneous music, you'll know what I mean. Now imagine they're not musicians, they're software developers, and instead of grooving away in D minor they're having a variety of open and unstructured discussions about REST frameworks, MVC, mock objects, evolutionary database design, the .Net user community and suchlike.

Personally, I thought it worked very, very well. The Friday night kick-off was a great idea; an hour or so to get some idea what to expect, then a few hours of beer & chat to break the ice and generally get things moving, meant that by the time we started off on Saturday morning the feeling of standing in a room full of strangers was pretty much gone and apart from a couple of rather severe hangovers, things got moving really quickly.

I'm posting the actual technical content of the sessions on altnetpedia, but there's a couple of things I'll add here.

Firstly, a big thanks to everybody who put this together - especially Ben Hall (for sorting me out with a last-minute place after I completely missed both rounds of tickets - thanks Ben!),  Ian Cooper, Alan Dean, and Conchango and Red Gate are also providing support. (Red Gate not only make the best database tools I've ever used, they've now given me free beer as well. You guys rock.)

Second, thanks to everyone who attended. It was a pleasure meeting you all; the discussions we had were engaging, informative and enlightening, and I generally found the whole thing to be an incredibly worthwhile experience. Knowing that there's so many real people out there who''ll give up a Saturday to hang out and talk about how we can improve the whole software development process is genuinely inspiring, and I'm hoping to see you again at one .NET event or another over the coming months.

The session on improving the developer community, in particular, had some really great ideas. In particular,  Zi suggested one-off afternoons or days of "pair programming" - employers and security permitting, inviting another member of the .NET circle to spend an afternoon working with you on something you're doing, and vice versa. Given that, at any given point, I think most of us are normally working at a level slightly beyond our comfort zone (that's what keeps it challenging, right? - or is that just me...?), I think this would be a great way to share knowledge, develop skills and generally improve as developers. I'm looking forward to seeing if we can make something like this happen, and I'd be interested to hear from anyone out there who's done anything similar.

Finally - on a purely practical geek note, next time we do this, can I suggest we transpose the rows and columns on the planning board?

This (which is what we did)

  Track A Track B Track C Track D
09:30-10:30        
11:30-13:00        
14:00-15:30        
16:00-17:00        

means you've always got at least four people trying to see the entire width of the wall (that's what's going on in the photo above...), whereas if we'd done it this way round...

  09:30-10:30 11:30-13:00 14:00-15:30 16:00-17:00
Track A        
Track B        
Track C        
Track D        

everyone starts at the left - where they can see all four choices for the 09:30 session - looks up & down, picks their first track, moves to the right, picks their second, and it all just unfolds a lot more... elegantly :)