Broadcom CrystalHD Decoder support for FFmpeg and MPlayer
At the end of last year, Broadcom released open-source drivers and a library for their CrystalHD hardware video decoder; You can read the details about that at Jarod Wilson’s blog if you’re interested.
The hardware is particularly attractive because it’s low cost and can be added to any system, regardless of the GPU it uses. It provides MPEG1/2, H.264 and VC-1 decode capabilities in all hardware versions, and the latest 70015 part also adds MPEG4 Part 2 / DivX / XviD support – and, if you care about such things, it does so in a way that means all the infamous patent issues are handled in hardware.
Once the drivers and library were released, we started to see plenty of application support emerge, with XBMC, Xine and MythTV drivers under development early on, and a gstreamer plugin provided by Broadcom with the library. In the last couple of months, a VLC patch has been proposed. But, for all this, there was no movement on FFmpeg or Mplayer; the first being the most widely used codec library around and the later, one of the most widely used media players (and obviously a consumer of FFmpeg). I bought myself a 70012 and later a 70015 with the intention of playing around with them, but when I got some free time last month, I started working on FFmpeg and Mplayer support.
After some experimentation, I did the initial implementation as a native Mplayer decoder, which helped remove FFmpeg as a variable while I tried to get things working correctly, and after some effort, I came up with something that worked pretty well for progressive content. and partially worked for some interlaced content. In my initial discussion on the mplayer mailing list, it became clear that it needed to be an FFmpeg decoder to be maintainable for the long term. So I went back and converted it, which was relatively straight-forward as the APIs are very similar. I’ve now started getting review feedback on the FFmpeg list, and I expect it will be quite a while before it gets in, assuming it ever does, but the code is definitely usable enough to publicise more widely.
What Works
- MPlayer playback
- 70015 Hardware: This is the newest part, with extra codec support
- All the officially supported content types except DivX 3.11
- Progressive Content
- Interlaced MPEG2 and H.264 MBAFF Content
You’ll note that I said MPlayer playback works but nothing about FFmpeg even though it’s an FFmpeg decoder. The issue here is that the hardware is pipelined, so it is normal for many frames to be in flight at one time – perhaps as many as 20 under normal conditions, and over a hundred if things start going wrong… This means that the application has to have a concept of lag in the decoding process. Now, while Mplayer uses FFmpeg’s codecs, it handles frame timing and av sync in a completely different way from the actual FFmpeg transcoding application, and it happens to do it in a way that can cope with the hardware behaviour (although I had to increase the number of frames in flight that Mplayer can handle). FFmpeg on the other hand assumes that when it submits a frame for decoding, the frame it gets back is the same one. From the discussion, it sounds like I’ll need to add the same mechanism that Mplayer uses to FFmpeg. So, for now, it’s an FFmpeg decoder that doesn’t work with FFmpeg 🙂
The 70012 is the previous generation of hardware and it has some significant differences from the 70015. Beyond the reduced codec support, it has much tighter requirements with respect to keeping the pipeline happily fed, and I haven’t had a chance to investigate what this really means yet. For now, it will kind-of work, but expect something to go wrong with the pipeline and either get input overflow or output underflow pretty quickly.
Interlaced content is tricky because it can appear in many different forms, and if you look at all the other applications out there with CrystalHD support, none of them really even try to handle it. This inherent challenge is compounded by the fact that the frames don’t seem to get marked correctly when returned from the hardware, so it’s hard to tell the cases apart. I have been able to verify that MPEG2 style interlacing (where the hardware returns each field separately) and H.264 MBAFF (where the hardware returns a field pair as one frame, but with dubious flags) work correctly. H.264 PAFF should work the same as MPEG2 but I haven’t found a sample that isn’t a scary DVB broadcast stream, which introduces all sorts of other complications. There’s also a concept of interlaced content that’s marked as progressive (so you just get a field pair frame) and this should just work but I haven’t found a sample yet.
Other things of note
If you’re trying to play very high bandwidth files, make sure your I/O path is actually fast enough to move the data (so don’t expect Bluray content to work over an 802.11g link). And if your file is encoded with features that aren’t supported by the hardware, then all bets are off; the most common example of this would be an H.264 file where the encoder decided to use the highest possible settings – such as 16 b-frames on 1080p content. The CrystalHD appears to try its best to play these files but you’ll see glitches (eg: In the 16 b-frame case, it will just silently fail to resolve references to the additional b-frames)
Performance
As all codec work is done in hardware, the CPU utilization is purely based on the video resolution – almost all the time is spent copying frames back and forth. In my very unscientific tests, my old 2.2GHz Core 2 Duo laptop can play 1080p content at 25% of a core compared to 70-100% for software decoding. Also note that the X server (and window manager if you use a composited desktop) will burn measurable amounts of CPU time to display the frames. It’s supposed to be possible to do 1080p playback on a single-core Atom, but I’m not in a position the test that. Nevertheless, the benefits are clear.
Getting the code
First off, you’ll need the latest driver and userspace library from Jarod’s git tree.
Then you should grab my patched Mplayer and FFmpeg trees from github, and then construct a full Mplayer tree on disk. That means:
- mplayer/: My mplayer tree
- mplayer/ffmpeg/: My ffmpeg tree
- mplayer/ffmpeg/libswcale/: From mplayerhq
- mplayer/libdvdread4/: From svn at svn://svn.mplayerhq.hu/dvdnav/trunk/libdvdread/src
- mplayer/libdvdnav/: From svn at //svn.mplayerhq.hu/dvdnav/trunk/libdvdnav/src
Then you should be able to build Mplayer as normal. CrystalHD support should be auto-detected and will be preferred at playback to the software decoder. In theory, mencoder should also work correctly but I haven’t tried it.
Enjoy!