xine gets improved WavPack support

It’s 6:35Am, I’m still awake, and I worked the whole day and night on xine-lib, so let me try to show what changed there of nice, so that I can also drop some of the negativity going on.

First of all, I stated fixing the WavPack demuxer so that it shown the correct duration and playing time of the stream, this way also Amarok stops going crazy when WavPack tracks are present in the playlist. This was the easy part.

Then, I decided to try again writing a WavPack decoder that used directly the WavPack library rather than FFmpeg. Why this? Because FFmpeg has a few imitations at the moment when WavPack is concerned, for instance it does not handle at all the multichannel WavPacks. I started working on WavPack support in July, but I was never able to get anything working until FFmpeg got WavPack support, and then I limited myself to a demuxer plugin, so this was the time to restart my work.

I’ve decided to make a single plugin fo both demuxer and decoder, so that you don’t have two different plugins to load, both using libwavpack. To do that, though, I had to shuffle around the demux_wavpack.c file, so i lost a bit of history; luckily the demuxer was young enough not to have anything important in there.

I had to fiddle quite a bit to get the demuxer working, because I have to pass between the demuxer and the decode entire blocks of data, and I need two different sets of wrapper functions that mimic filesystem access (seek, tell, read, …), one that used xine’s input framework, the other using a simple buffer access (for the decoder). I had some trouble because I lost a bit of focus while I was working on it, so I made some stupid mistake that asked me to rebuild the code a lot of times before finding the cause, and I wasn’t really able at the end to get some PTS support working.

About at 6AM I was finally able to play Hikaru Utada’s Passion from my own WavPack rip of the single album (thanks again Ben for it 🙂 )… being my first xine decoder from scratch, I felt so excited that it finally worked, that I cannot even sleep now about an hour later.

Of course the work is not complete yet, I’ll have to spend a little more time on xine-lib to complete things like Seeking (currently totally unimplemented), and I plan to remove FFmpeg Wavpack decoding support today as soon as I wake up after taking a few hours of sleep. This is because FFmpeg requires the frames to be passed with the last 12 bytes of the WV header (which would be otherwise 24 bytes), which is incompatible with WavPack library requirement of having all of them; right now, the decoder is forging a WavPack header while reassembling the frame, and more or less works, but there are two cases where this method will not work.

The first case is when the WavPack version is updated; currently I’m setting the version to 0x0406 which is the generic version created by WavPack 4.40 utilities; it might not be the same version as the original WavPack file though, so it’s probably not always working as intended already; the second case is with multichannel WavPack files. WavPack files support multichannel data by interpolating stereo and mono frames that covers up to 6 channels easily. It’s not difficult to handle, as the streaming mode of the library will just convert the three blocks composing the 6 channels into one single decoded 6-channels frame, but to do so, I need to pass more than one actual frame in a single xine frame, and so I cannot use the 12-bytes trick anymore.

Considering that FFmpeg does not handle multichannel files, and that requiring half of a frame’s header is quite silly (either you require the header or you don’t requiring half of it is pointless, even if the upper half is not used), I’ll easily get rid of FFmpeg WavPack decoding if that brings me a working multichannel decoder using the official library. It’s not even an additional dependency at build or runtime, as the library was already needed for the demuxer alone (it’s quite complex to write a new demuxer, or better, it’s quite long and boring to do so, it’s probably simpler than writing a FLAC demuxer).

Another planned feature is support for basic tags reading so that it can actually appear in xine, but for that I’d rather think about writing a tag reading implementation in xine-lib itself, as WavPacks like MP3s and MusePack files would use APE tags, so it’s pointless to repeat the same implementation over and over. I considered for a moment TagLib, but I refuse that idea at the moment.