A reversing journey... (January 2008)

 

mp3PRO?

From my local copy of Wikipedia:

mp3PRO is an audio compression algorithm (or codec) that combines the MP3 audio format with spectral band replication compression methods. It claims to achieve transparency at lower bitrates than MP3, resulting in a file nearly half the size of standard MP3.

A different way of describing it:

It was a time long ago and Ogg Vorbis had not yet entered the picture. I was young. I was naive. I believed that even closed formats would stay forever.

I was out of hard disk space.

And this format was promising to halve my MP3 files in half!

In my tests I found out that it sounded pretty good, too, so I decided to go ahead and use mp3PRO for my audio collection...

And halved it, it did. And I got some much needed disk space. And I installed Linux...

Time passed...

And, as expected, Linux (and the BSDs) shook my world... I became an addict; I learned to worship Stallman and Raymond, I coded in C and C++ and Perl and Python... I read manuals and infopages... I became a hermit...

...and after 10 years of working in silence, it dawned on me... now that I was using open-source OSes, how would I listen to my music?

Closed formats: A Royal Pain In The...

To add insult to injury, in the years that passed, not only had Ogg Vorbis emerged, it had also surpassed mp3PRO in terms of quality/bitrate. So not only did my music collection suffer silence at the hands of a closed format, it was also sounding inferior...

I contemplated re-coding all my CDs in Vorbis... But I am lazy... I am also a somewhat-adept coder, so I started investigating...

Option 0: In-Duh-vidual

Well, mp3PRO files are in fact valid MP3 files. You can listen to them with any MP3 decoder - but you are only listening to the first 22KHz of the spectrum... To hear the rest, you need an mp3PRO-aware decoder... So the quality of the sound is rather flat, similar to that of a radio station...

Option 1: Wine

WINE is a great piece of software. Does it run Winamp, with its mp3PRO plugin?
Winamp under WINE
Of course it does!

In the snapshot above, you can see the nice IceWM window decorations (I love spartan window managers). You can also see that the file being played is, in fact, an mp3PRO file - which sounds every bit as delicious as it does under Windows, at a smooth 44KHz.

Option 2: Mass conversion

Then again, WINE is a beast. Perhaps it is better to "bite the bullet" and transcode the files from mp3PRO to Vorbis... Harddisk space is now cheaper than air (almost), so I can use this nice "dBpowerAMP Music Converter" thingie that I downloaded from the Web, to convert my files to WAVs, and re-encode them in Vorbis. This tool supports mp3PRO through the Winamp plugin, so there, I am out of excuses...

Music Converter
Or am I?

Do I have to Cick/Click/Click for all the music files I have? Hundreds of them...?

Option 3: XMMS

Then again, why transcode? The frequency information is there, why re-encode it in another format?

All I want is to be able to listen to my files using a native Linux solution... Let's Google...

What do you know!... THOMSON released an mp3PRO plugin for XMMS, back in 2005!... Now there's something I did not expect.

Then again, people all over the web are complaining about it ("it doesn't work" - "it borks my XMMS") ... let's try it anyway...

bash$ rpm -qip libmp3PRO-1.0.1-1.i386.rpm 
Name        : libmp3PRO                    Relocations: (not relocateable)
Version     : 1.0.1   Vendor: Coding Technologies GmbH <mp3PRO@CodingTechnologies.com>
Release     : 1                             Build Date: Wed 14 Sep 2005 03:41:15 PM EEST
Install Date: (not installed)               Build Host: linux.local
Group       : Applications/Multimedia       Source RPM: libmp3PRO-1.0.1-1.src.rpm
Size        : 391408                           License: distributable
Signature   : (none)
URL         : http://www.mp3PROzone.com
Summary     : XMMS input plugin to play mp3PRO files and streams.
Description :
The Coding Technologies mp3PRO Decoder plugin is a complete
ISO/IEC 11172-3 ("MPEG-1") and ISO/IEC 13818-3 ("MPEG-2") implementation
of the MPEG Layer-3 decoding algorithm with the additional ability to
handle the mp3PRO enhancement. The proprietary Fraunhofer IIS extension for
sampling frequencies of 8, 11.025 and 12 kHz ("MPEG-2.5") is also supported.

Install this plugin if you want to play mp3PRO files or streams. To ensure
using this plugin for mp3PRO files it is recommended to disable the built-in
MPEG Layer 1/2/3 Player.
Hmm, looks nice enough. Extracting the contents with alien (I use Debian), copying libmp3PRO.so into /usr/lib/xmms/Input/...

Hooray, it worked! (If it didn't work for you, keep reading...)

Option 4: MPlayer

Well then, why did these people complain? It works fine, in both my Gentoo and my Debian Etch... And now that I have an XMMS plugin, I can even use MPlayer's xmms demuxer, and do ANYTHING I want with my mp3PRO files... filter them, transcode them, flip them sideways...

Let me show you - oh wait!

Here's something weird... I compiled my MPlayer with --enable-xmms and fed it (using -demuxer xmms) with an mp3PRO file...

I only get 22KHz!

bash$ mplayer -demuxer xmms "SlaveChildrenCrusade.mp3"
MPlayer 1.0rc2-4.2.2 (C) 2000-2007 MPlayer Team
CPU: Intel(R) Core(TM)2 Duo CPU     E4500  @ 2.20GHz
CPUflags:  MMX: 1 MMX2: 1 3DNow: 0 3DNow2: 0 SSE: 1 SSE2: 1
Compiled for x86 CPU with extensions: MMX MMX2 SSE SSE2
115 audio & 237 video codecs

Playing SlaveChildrenCrusade.mp3.
Found plugin: libmp3PRO.so ().
Found plugin: libmp4.so (MP4 & MPEG2/4-AAC audio player - 1.2.x).
Found plugin: libwav.so (Wave Player 1.2.10).
Found plugin: libmikmod.so (MikMod Player 1.2.10).
Found plugin: libmodplugxmms.so (ModPlug Player).
Found plugin: libcdaudio.so (CD Audio Player 1.2.10).
Found plugin: libtonegen.so (Tone Generator 1.2.10).
Waiting for the XMMS plugin to start playback of 'SlaveChildrenCrusade.mp3'...
XMMS file format detected.
==========================================================================
Opening audio decoder: [pcm] Uncompressed PCM audio decoder
AUDIO: 22050 Hz, 2 ch, s16le, 705.6 kbit/100.00% (ratio: 88200->88200)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
==========================================================================
AO: [oss] 22050Hz 2ch s16le (2 bytes per sample)
Video: no video
Starting playback...
Closing plugin: /usr/lib/xmms/Input/libtonegen.so.
Closing plugin: /usr/lib/xmms/Input/libcdaudio.so.
Closing plugin: /usr/lib/xmms/Input/libmodplugxmms.so.
Closing plugin: /usr/lib/xmms/Input/libmikmod.so.
Closing plugin: /usr/lib/xmms/Input/libwav.so.
Closing plugin: /usr/lib/xmms/Input/libmp4.so.
Closing plugin: /usr/lib/xmms/Input/libmp3PRO.so.

Exiting... (Quit)
MPlayer DID use the XMMS plugin, but something went wrong... Why?

Hmm...

How can the same plugin - the same executable code - behave differently under MPlayer? Is it locked, maybe? To only run under XMMS? (Binary blobs... Sigh... You can never tell...)

Looking at the source code for libmpdemux/demux_xmms.c, I can see that a disk_open callback is called from code within the plugin, to provide the player with the "decoding details":

static int disk_open(AFormat fmt, int rate, int nch) {
    switch (fmt) {
        case FMT_U8:
            xmms_afmt=...
In other words, it is the plugin that decides the quality of the output (parameter "rate"). The function pointer to "disk_open" is passed to the plugin in a structure (of type OutputPlugin) during plugin initialization, and the plugin calls it when it knows enough about the input to decide what output it is going to generate.

The million dollar question, is why does the plugin call disk_open with 22KHz when used under MPlayer, but with 44KHz when used under XMMS?

Well... it took some work with GDB to figure this out...

The mp3PRO plugin contains a getbits function.

That's not so bad, in itself... unless the shared library in question (libmp3PRO.so) is NOT the ONLY library that uses such a function...

So what happens is this:

At this point, "ld" has a problem. Which getbits definition (of the two addresses now available in MPlayer's process space) should it use to "patch" the invocations to getbits inside the newly loaded code of libmp3PRO.so?

It turns out, that in my case, it used the getbits from libmp3lame.so!

What this means, in plain terms, is that "ld" tried to put the shoes of a midget on Andre the Giant.

The results, could have been ANYTHING. I was amazed to see that this didn't cause a crash; pure luck, as it turned out: a function inside the plugin (SbrCrcCheckMp3) tried to use getbits, and ended up calling the COMPLETELY different implementation of the function offered by the code inside libmp3lame. This foreign code, returned a completely unexpected value to SbrCrcCheckMp3, and so the poor function considered the Sbr information (spectral band replication) to be "bad" - and disabled the decoding of the upper frequencies (the ones above 22KHz!).

This of course explains all the poor people that complain about this plugin "borking" their XMMS... What happens is truly random... In my case, I was lucky - my XMMS and its plugins didn't offer an alternative getbits, so everything was fine under XMMS. Under MPlayer, however, I could have gotten any kind of behaviour. Crash, corruption...

Other people, apparently, were not so lucky.

Executive summary: Friggin' binary blobs! If only we could dispose of them...

So how do I fix this?

Easy. You just have to build an MPlayer that... That's not as hard as it sounds. Basically, after configuring MPlayer with configure --enable-xmms, I had to do 2 things: That was it. After make mplayer, I got my 44KHz decoding...
bash$ ./mplayer -demuxer xmms "SlaveChildrenCrusade.mp3"
...
XMMS file format detected.
==========================================================================
Opening audio decoder: [pcm] Uncompressed PCM audio decoder
AUDIO: 44100 Hz, 2 ch, s16le, 1411.2 kbit/100.00% (ratio: 176400->176400)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
==========================================================================
AO: [oss] 44100Hz 2ch s16le (2 bytes per sample)
Video: no video
Starting playback...
...
And now, the sky's the limit... If I choose to, I can transcode my files into vorbis using pipes (and avoid the Gigabytes of WAVs that "Option 2" would require)... or I can apply any kind of runtime filter (e.g. -af sub, -af extrastereo, -af karaoke, etc).

I am happy - I can listen to my collection again...


profile for ttsiodras at Stack Overflow, Q&A for professional and enthusiast programmers
GitHub member ttsiodras
 
Index
 
 
CV
 
 
Updated: Sat Oct 8 12:33:59 2022