mpg123 - Fast console MPEG Audio Player and decoder library

The mpg123 distribution contains a real time MPEG 1.0/2.0/2.5 audio player/decoder for layers 1,2 and 3 (most commonly MPEG 1.0 layer 3 aka MP3), as well as re-usable decoding and output libraries. Among others, it works on GNU/Linux, MacOSX, the BSDs, Solaris, AIX, HPUX, SGI Irix, OS/2 and Cygwin or plain MS Windows (not all more exotic platforms tested regularily, but patches welcome). You may jump to the non-exhaustive list of features.

It is free software licensed under LGPL 2.1 .

Note that nowadays, the mpg123 decoder core can work with floating point or integer math and with some tuning between accuracy and performance at build-time, using assembly optimizations for several platforms, depending on your build configuration. There is detection and selection of assembly optimisations on x86, x86-64, and ARM at program runtime. It's fast, it's high-quality. Just use it;-)

Top News

Some code analysis came in, with lots of minor and some major issues that force a bugfix release ahead of the planned 1.34.0. Most severe is the fix for unicode path handling on Windows platforms, and that is why I took the pain to also update the binaries via cross build. This release is highly recommened hygiene for anyone shipping mpg123, I'd even say it is mandatory nowadays. If you are stuck on something pre-1.33, you probably can prioritize some commits or might be lucky with the diff. Lots of the bugs are in older code.

  • mpg123:
    • Fix heap buffer overflows in unicode path conversion on Windows (bug 388, thanks to Alejandro Ramos).
    • Fix information disclosure of uninitialied memory for --auth-file without line endings. (bug 390, thanks to Alejandro Ramos)
    • Fix out-of-bounds read/write when combining --continue --random --listentry where n is larger than the playlist size. (bug 391, thanks to Alejandro Ramos)
    • Fix a harmless valgrind memory leak report by not nulling playlist name.
    • Fix error handling of win32_net_writestring() (Windows only) by actually using a signed type, also preventing a OOB read on failure. (bug 392 by Alejandro Ramos)
    • Fix a mostly harmless OOB read of 1 byte when printing USLT lyrics. (bug 392)
    • Fix leaking file descriptor on read error from --equalizer file. (bug 392)
    • Hardening of loading HTTP(S) via curl or wget against funky URLs by including the -- separator. No actual vulnerability, tough, just extra care. (bug 392)
  • out123:
    • Fix heap overrun on --endian conversion with differing input and output channel counts. (bug 391)
    • Fix parsing of filter specs with whitespace before commas, which resulted in out-of-bounds writes before. (bug 391)
  • libmpg123, mpg123: Harden memory realloc calls against multiplication overflow of size_t in arguments. Specifically, this addresses part of bug 389 with possible application abuse of mpg123_set_index64(). (bug 389 by Alejandro Ramos)
  • libmpg123:
    • Fix possible use of uninitialized values in layer III dequantization. III_dequantize_sample() for consistent output also for strange input. The new code seems to be slightly faster after some rearrangements. (thanks to He Huang, Swinburne University of Technology (discovered using NexusSan))
    • Fix a double free when deleting a handle after failed mpg123_decoder() call (possibly among others). (bug 389)
    • More strong wording in API that ID3 text convenience links are short-lived, but safeguard against ignorant use by nulling them early. (bug 389)
    • Prevent double free in mpg123_set_index() 32 bit wrapper being called with index size 0. (bug 392)
    • Harden against an application wielding a foot gun by handing in an undersized decoding buffer betwee seek and read (return error before trying to decode and discard frames in that case). (bug 392)
    • Do properly terminate ID3v2 texts coming in UTF16 encoding when they overwrite previous frames, like with other encodings. The symptom was a shorter second frame resulting in a combined text with the earlier longer frame. (bug 392)
    • Check and properly handle null source buffer and zero size in mpg123_store_utf8() instead of reading past (before) buffers. (bug 392)
    • Ensure clients get ID3v1 data with (unmotivated) mpg123_id3_raw() only if the parser decided that it is there, not possibly the last 128 bytes of a seekable stream without ID3v1 tag. (bug 392)
    • Prevent impossible NtoM resampling with too low target rate (like 1 Hz) which would trgger endless looping. (bug 392)
  • libout123:
    • Fix deadlock in buffer mode when combined with (stereo) 24 bit output. Now also mpg123 --buffer 4096 -e s24 shall actuallly work. Sorry. (bug 392)
    • Abort early on zero/negative rate and channel count in out123_start(). (bug 392)
    • Fix divide by zero in WAV writing by catching channel counts that go zero in the 16 bit WAV header field. (bug 392)
  • libsyn123:
    • Explictly reject mismatched format for appending filters with syn123_setup_filter(), preventing memory errors from that API-violating use. (bug 392)
    • Harden the dirty resampling interpolator against extreme rates (around 1e18 Hz) by fixing a sample offset check to not do the exact overflowing addition that it is supposed to guard against. The fine resampler was … fine. (bug 392)
    • Error out on trying to create a filter of order 0 instead of dividing by zero later. (bug 392)

Head over to the download section for getting your hands on the release.

  • mpg123
    • Prepare for const-returning strchr().
    • Hide seq_len debugging counter in non-debug mode (handle github PR 20).
    • Fix memory leak with --network internal due to inverted NULL check in net123_close_internal() (handle never NULL in practice, though; bug 386).
  • mpg123, out123: Fix strrchr() usage to be more const and correct under C99 as well as C23 (handles PR 19 on the github mirror).
  • mpg123-strip: Also use largefile API properly using mpg123config.h, but without actual effect at least on Linux/x86. It is cleaner that way, though.
  • ports/cmake: Yasm is not neeeded for Clang on MSVC (github PR 23, thanks to Alexander Lobakin).
  • libmpg123: Remove unused loop variable in layer2 left over from runtime table elimination (32 bit mmx/sse code, prompted by github PR 22).

Head over to the download section for getting your hands on the release.

Yet again, largefile support burns the hands that touch it. The changes in 1.32.0 introduced inconsistent largefile setup in the generic remote control mode, resulting in 64 bit offset functions being called with 32 bit offset arguments. This breaks position info for one, but also caused segfault on 32 bit ARM Linux. Disabling largefile support in the build

The normal playback mode of mpg123 including terminal control is not affected.

  • mpg123: Fix generic control mode for largefile-sensitive builds, where 32 bit off_t was used with mpg123 API calls expecting 64 bit off_t. I am appalled that it took a user on 32 bit ARM and a specific https stream to notice this (bug 385, regression since 1.32.0). The security impact of this could be serious, with memory corruption including segfault being observed.
  • mpg123-id3dump, out123: Enable 64 bit offset usage on largefile-sensitive platforms (regression since 1.32.0).
  • libmpg123:
    • Announce support for shadow stack / IBT in x86-64 assembly.
    • Also announce PAC/BTI for non-accurate neon64 (aarch64) synth.
  • libout123: Add a safeguard to ensure variable-length records from buffer communication are always zero-terminated.
  • libsyn123: Use union work buffer to avoid casts that may look like breaking strict aliasing.

Head over to the download section for getting your hands on the release.

For older news see the news archive

ISO MPEG compliance

This is a rough log of an automated compliance test on the mpg123 webserver (Xeon E3, GNU/Linux), using the test bitstreams from the ISO MPEG reference set. At least the floating point output should really be close enough to the reference.

Regarding the method: This is comparing mpg123's output (with gapless code deactivated) from reference bitstreams to the reference output. A simple RMS error measure is employed, relative to full scale, just summing over mono or stereo data indiscriminently. This is my interpretation of the rules... maximum allowed RMS=8.80967e-06, maximum signal difference 6.10352e-05.

compliance test for mpg123-1.34.0-dev+20260802022201 on Linux x86_64
First decoder in this list will be tested first, then generic: 
Supported decoders: AVX x86-64 generic generic_dither

Testing default decoder...

==== Layer 1 ====
--> 16 bit signed integer output
fl1.bit:	RMS=4.364373e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl2.bit:	RMS=4.353138e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl3.bit:	RMS=4.348759e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl4.bit:	RMS=4.403421e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl5.bit:	RMS=4.323446e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl6.bit:	RMS=4.389602e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl7.bit:	RMS=3.826083e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl8.bit:	RMS=4.362205e-06 (PASS) maxdiff=7.629395e-06 (PASS)
--> 32 bit integer output
fl1.bit:	RMS=1.967634e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl2.bit:	RMS=1.971686e-08 (PASS) maxdiff=1.117587e-07 (PASS)
fl3.bit:	RMS=2.002386e-08 (PASS) maxdiff=1.341105e-07 (PASS)
fl4.bit:	RMS=1.902169e-08 (PASS) maxdiff=1.266599e-07 (PASS)
fl5.bit:	RMS=3.655859e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl6.bit:	RMS=3.069318e-08 (PASS) maxdiff=1.629815e-07 (PASS)
fl7.bit:	RMS=1.768833e-08 (PASS) maxdiff=8.940697e-08 (PASS)
fl8.bit:	RMS=1.857219e-08 (PASS) maxdiff=8.428469e-08 (PASS)
--> 24 bit integer output
fl1.bit:	RMS=4.096055e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl2.bit:	RMS=4.156199e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl3.bit:	RMS=4.126996e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl4.bit:	RMS=4.100406e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl5.bit:	RMS=4.574976e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl6.bit:	RMS=3.920292e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl7.bit:	RMS=4.186568e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl8.bit:	RMS=4.104751e-08 (PASS) maxdiff=1.192093e-07 (PASS)
--> 32 bit floating point output
fl1.bit:	RMS=1.967635e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl2.bit:	RMS=1.971679e-08 (PASS) maxdiff=1.117587e-07 (PASS)
fl3.bit:	RMS=2.002391e-08 (PASS) maxdiff=1.341105e-07 (PASS)
fl4.bit:	RMS=1.902160e-08 (PASS) maxdiff=1.266599e-07 (PASS)
fl5.bit:	RMS=3.655860e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl6.bit:	RMS=3.069316e-08 (PASS) maxdiff=1.629815e-07 (PASS)
fl7.bit:	RMS=1.768828e-08 (PASS) maxdiff=8.940697e-08 (PASS)
fl8.bit:	RMS=1.857223e-08 (PASS) maxdiff=8.428469e-08 (PASS)

==== Layer 2 ====
--> 16 bit signed integer output
fl10.bit:	RMS=3.512100e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl11.bit:	RMS=3.837267e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl12.bit:	RMS=3.901071e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl13.bit:	RMS=4.379583e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl14.bit:	RMS=4.112578e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl15.bit:	RMS=4.388568e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl16.bit:	RMS=4.147495e-06 (PASS) maxdiff=7.688999e-06 (PASS)
--> 32 bit integer output
fl10.bit:	RMS=1.777418e-08 (PASS) maxdiff=8.475035e-08 (PASS)
fl11.bit:	RMS=1.789150e-08 (PASS) maxdiff=9.685755e-08 (PASS)
fl12.bit:	RMS=1.780872e-08 (PASS) maxdiff=8.940697e-08 (PASS)
fl13.bit:	RMS=1.760690e-08 (PASS) maxdiff=4.470348e-08 (PASS)
fl14.bit:	RMS=3.361258e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl15.bit:	RMS=2.414684e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl16.bit:	RMS=1.924891e-08 (PASS) maxdiff=1.192093e-07 (PASS)
--> 24 bit integer output
fl10.bit:	RMS=4.086103e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl11.bit:	RMS=4.098320e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl12.bit:	RMS=4.095125e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl13.bit:	RMS=4.108581e-08 (PASS) maxdiff=5.960464e-08 (PASS)
fl14.bit:	RMS=4.444728e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl15.bit:	RMS=4.098525e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl16.bit:	RMS=4.146825e-08 (PASS) maxdiff=1.192093e-07 (PASS)
--> 32 bit floating point output
fl10.bit:	RMS=1.777416e-08 (PASS) maxdiff=8.475035e-08 (PASS)
fl11.bit:	RMS=1.789151e-08 (PASS) maxdiff=9.685755e-08 (PASS)
fl12.bit:	RMS=1.780868e-08 (PASS) maxdiff=8.940697e-08 (PASS)
fl13.bit:	RMS=1.760693e-08 (PASS) maxdiff=4.470348e-08 (PASS)
fl14.bit:	RMS=3.361258e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl15.bit:	RMS=2.414676e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl16.bit:	RMS=1.924847e-08 (PASS) maxdiff=1.192093e-07 (PASS)

==== Layer 3 ====
--> 16 bit signed integer output
compl.bit:	RMS=4.300912e-06 (PASS) maxdiff=7.688999e-06 (PASS)
--> 32 bit integer output
compl.bit:	RMS=2.104434e-08 (PASS) maxdiff=1.881272e-07 (PASS)
--> 24 bit integer output
compl.bit:	RMS=4.170551e-08 (PASS) maxdiff=2.384186e-07 (PASS)
--> 32 bit floating point output
compl.bit:	RMS=2.104434e-08 (PASS) maxdiff=1.881272e-07 (PASS)

==== Layer 3 intensity stereo ====
   (no official reference, comparing to mpg123 generic 24 bit)
--> 16 bit signed integer output
drumshort08kHz.bit:	RMS=4.348691e-06 (PASS) maxdiff=7.629395e-06 (PASS)
drumshort24kHz.bit:	RMS=4.365981e-06 (PASS) maxdiff=7.688999e-06 (PASS)
drumshort48kHz.bit:	RMS=4.375106e-06 (PASS) maxdiff=8.106232e-06 (PASS)
mono-is-ms.bit:	RMS=4.389831e-06 (PASS) maxdiff=7.688999e-06 (PASS)
--> 32 bit integer output
drumshort08kHz.bit:	RMS=3.281180e-08 (PASS) maxdiff=1.043081e-07 (PASS)
drumshort24kHz.bit:	RMS=3.282391e-08 (PASS) maxdiff=1.192093e-07 (PASS)
drumshort48kHz.bit:	RMS=4.068793e-08 (PASS) maxdiff=6.854534e-07 (PASS)
mono-is-ms.bit:	RMS=3.511104e-08 (PASS) maxdiff=2.197921e-07 (PASS)
--> 24 bit integer output
drumshort08kHz.bit:	RMS=3.600636e-09 (PASS) maxdiff=5.960464e-08 (PASS)
drumshort24kHz.bit:	RMS=2.518008e-09 (PASS) maxdiff=1.192093e-07 (PASS)
drumshort48kHz.bit:	RMS=2.917921e-08 (PASS) maxdiff=7.152557e-07 (PASS)
mono-is-ms.bit:	RMS=1.635551e-08 (PASS) maxdiff=1.788139e-07 (PASS)
--> 32 bit floating point output
drumshort08kHz.bit:	RMS=3.281174e-08 (PASS) maxdiff=1.043081e-07 (PASS)
drumshort24kHz.bit:	RMS=3.282395e-08 (PASS) maxdiff=1.192093e-07 (PASS)
drumshort48kHz.bit:	RMS=4.068791e-08 (PASS) maxdiff=6.854534e-07 (PASS)
mono-is-ms.bit:	RMS=3.511108e-08 (PASS) maxdiff=2.197921e-07 (PASS)

==== Overall result ====
PASS (limited or full)

Now the generic decoder:

==== Layer 1 ====
--> 16 bit signed integer output
fl1.bit:	RMS=4.364373e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl2.bit:	RMS=4.353138e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl3.bit:	RMS=4.348759e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl4.bit:	RMS=4.403421e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl5.bit:	RMS=4.323446e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl6.bit:	RMS=4.389641e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl7.bit:	RMS=3.826083e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl8.bit:	RMS=4.362205e-06 (PASS) maxdiff=7.629395e-06 (PASS)
--> 32 bit integer output
fl1.bit:	RMS=1.977733e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl2.bit:	RMS=1.980311e-08 (PASS) maxdiff=1.117587e-07 (PASS)
fl3.bit:	RMS=2.006633e-08 (PASS) maxdiff=1.341105e-07 (PASS)
fl4.bit:	RMS=1.911986e-08 (PASS) maxdiff=1.266599e-07 (PASS)
fl5.bit:	RMS=4.047884e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl6.bit:	RMS=3.178246e-08 (PASS) maxdiff=1.639128e-07 (PASS)
fl7.bit:	RMS=1.775744e-08 (PASS) maxdiff=1.043081e-07 (PASS)
fl8.bit:	RMS=1.866297e-08 (PASS) maxdiff=8.195639e-08 (PASS)
--> 24 bit integer output
fl1.bit:	RMS=4.119282e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl2.bit:	RMS=4.184623e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl3.bit:	RMS=4.153068e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl4.bit:	RMS=4.118697e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl5.bit:	RMS=4.816338e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl6.bit:	RMS=4.047773e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl7.bit:	RMS=4.191854e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl8.bit:	RMS=4.106042e-08 (PASS) maxdiff=1.192093e-07 (PASS)
--> 32 bit floating point output
fl1.bit:	RMS=1.977741e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl2.bit:	RMS=1.980280e-08 (PASS) maxdiff=1.117587e-07 (PASS)
fl3.bit:	RMS=2.006633e-08 (PASS) maxdiff=1.341105e-07 (PASS)
fl4.bit:	RMS=1.911983e-08 (PASS) maxdiff=1.266599e-07 (PASS)
fl5.bit:	RMS=4.047868e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl6.bit:	RMS=3.178251e-08 (PASS) maxdiff=1.639128e-07 (PASS)
fl7.bit:	RMS=1.775792e-08 (PASS) maxdiff=1.043081e-07 (PASS)
fl8.bit:	RMS=1.866297e-08 (PASS) maxdiff=8.195639e-08 (PASS)

==== Layer 2 ====
--> 16 bit signed integer output
fl10.bit:	RMS=3.512100e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl11.bit:	RMS=3.837267e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl12.bit:	RMS=3.901071e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl13.bit:	RMS=4.379583e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl14.bit:	RMS=4.112596e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl15.bit:	RMS=4.388557e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl16.bit:	RMS=4.147495e-06 (PASS) maxdiff=7.688999e-06 (PASS)
--> 32 bit integer output
fl10.bit:	RMS=1.788206e-08 (PASS) maxdiff=8.195639e-08 (PASS)
fl11.bit:	RMS=1.798147e-08 (PASS) maxdiff=1.005828e-07 (PASS)
fl12.bit:	RMS=1.791770e-08 (PASS) maxdiff=8.568168e-08 (PASS)
fl13.bit:	RMS=1.770191e-08 (PASS) maxdiff=4.470348e-08 (PASS)
fl14.bit:	RMS=4.111211e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl15.bit:	RMS=2.477557e-08 (PASS) maxdiff=1.639128e-07 (PASS)
fl16.bit:	RMS=1.970979e-08 (PASS) maxdiff=1.490116e-07 (PASS)
--> 24 bit integer output
fl10.bit:	RMS=4.102704e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl11.bit:	RMS=4.113184e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl12.bit:	RMS=4.107583e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl13.bit:	RMS=4.127499e-08 (PASS) maxdiff=5.960464e-08 (PASS)
fl14.bit:	RMS=4.977907e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl15.bit:	RMS=4.145519e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl16.bit:	RMS=4.171672e-08 (PASS) maxdiff=1.788139e-07 (PASS)
--> 32 bit floating point output
fl10.bit:	RMS=1.788201e-08 (PASS) maxdiff=8.195639e-08 (PASS)
fl11.bit:	RMS=1.798150e-08 (PASS) maxdiff=1.005828e-07 (PASS)
fl12.bit:	RMS=1.791763e-08 (PASS) maxdiff=8.568168e-08 (PASS)
fl13.bit:	RMS=1.770194e-08 (PASS) maxdiff=4.470348e-08 (PASS)
fl14.bit:	RMS=4.111203e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl15.bit:	RMS=2.477554e-08 (PASS) maxdiff=1.639128e-07 (PASS)
fl16.bit:	RMS=1.970946e-08 (PASS) maxdiff=1.490116e-07 (PASS)

==== Layer 3 ====
--> 16 bit signed integer output
compl.bit:	RMS=4.300914e-06 (PASS) maxdiff=7.688999e-06 (PASS)
--> 32 bit integer output
compl.bit:	RMS=2.147540e-08 (PASS) maxdiff=1.750886e-07 (PASS)
--> 24 bit integer output
compl.bit:	RMS=4.202659e-08 (PASS) maxdiff=1.788139e-07 (PASS)
--> 32 bit floating point output
compl.bit:	RMS=2.147539e-08 (PASS) maxdiff=1.750886e-07 (PASS)

==== Layer 3 intensity stereo ====
   (no official reference, comparing to mpg123 generic 24 bit)
--> 16 bit signed integer output
drumshort08kHz.bit:	RMS=4.348733e-06 (PASS) maxdiff=7.748604e-06 (PASS)
drumshort24kHz.bit:	RMS=4.366053e-06 (PASS) maxdiff=7.808208e-06 (PASS)
drumshort48kHz.bit:	RMS=4.375036e-06 (PASS) maxdiff=7.748604e-06 (PASS)
mono-is-ms.bit:	RMS=4.389819e-06 (PASS) maxdiff=7.629395e-06 (PASS)
--> 32 bit integer output
drumshort08kHz.bit:	RMS=3.685351e-08 (PASS) maxdiff=4.172325e-07 (PASS)
drumshort24kHz.bit:	RMS=3.893594e-08 (PASS) maxdiff=7.450581e-07 (PASS)
drumshort48kHz.bit:	RMS=3.389556e-08 (PASS) maxdiff=2.607703e-07 (PASS)
mono-is-ms.bit:	RMS=3.372314e-08 (PASS) maxdiff=8.940697e-08 (PASS)
--> 24 bit integer output
drumshort08kHz.bit:	RMS=2.297661e-08 (PASS) maxdiff=4.172325e-07 (PASS)
drumshort24kHz.bit:	RMS=2.677607e-08 (PASS) maxdiff=7.748604e-07 (PASS)
drumshort48kHz.bit:	RMS=1.460054e-08 (PASS) maxdiff=2.384186e-07 (PASS)
mono-is-ms.bit:	RMS=9.138218e-09 (PASS) maxdiff=5.960464e-08 (PASS)
--> 32 bit floating point output
drumshort08kHz.bit:	RMS=3.685353e-08 (PASS) maxdiff=4.172325e-07 (PASS)
drumshort24kHz.bit:	RMS=3.893599e-08 (PASS) maxdiff=7.450581e-07 (PASS)
drumshort48kHz.bit:	RMS=3.389551e-08 (PASS) maxdiff=2.607703e-07 (PASS)
mono-is-ms.bit:	RMS=3.372002e-08 (PASS) maxdiff=8.940697e-08 (PASS)

==== Overall result ====
PASS (limited or full)

Depending on what integer quality mode you choose at compile time (and the decoder in use), the 16bit output can vary between PASS and LIMITED for fully or limited accuracy compliance. But keep in mind: For the integer output, you have to give +-1 for rounding... that's what I append to any integer number read from some measurement device anyway, by default. That minimum possible deviation already brings the output close (or over) the border of full compliance... that really does not mean that the output sounds bad! It shall be noted that a measure to improve subjective quality, namely the dithering before rounding to integers, can also increase the theoretical decoding error.

In the end, RMS values in the order of 10 to the power of -5 should sound just fine. To get 16bit output to PASS, you usually need to enable proper rounding using the --enable-int-quality configure flag, which is on by default since some time now. On a specific (older) system, you might consider turning that off for possibly a slight performance gain.

For comparisong with other decoders (as well as older incarnations of the mpg123 engine), have a read of the Underbit compliance tests. Actually, my testing method follows that example, including their quoting of ISO MPEG rules.

Regression tests

This is output from the rudimentary regression test suite (which should eventually merge several approaches we had on testing in the past), working on the periodic snapshot:

cc -Os  -I/tmp/mpg123-svn.3bBqd/prefix/include  -c -o helpers.o helpers.c
CC 2859531_id3_tag_not_skipped_when_NO_ID3V2_is_defined.bin
CC 2950218_extra_samples_seek_last_frame.bin
CC basic_resync.bin
CC bug201_another_one.bin
CC bug201_wrong_frame_buffer.bin
CC chomp_strings.bin
CC custom_io.bin
CC frame_seek_weirdness.bin
CC freeformat.bin
CC less_bytes_after_seek2.bin
CC less_bytes_after_seek.bin
CC more_bytes_on_second_decode.bin
CC out123_errorlist.bin
CC out123_passthrough.bin
CC premature_decoder_change.bin
CC seek_accuracy.bin
CC string_alloc.bin
Running tests.
Starting tests, look into test.log for messages.
PASS|SKIP is good, FAIL is bad.

2859531_id3_tag_not_skipped_when_NO_ID3V2_is_defined:     PASS
2950218_extra_samples_seek_last_frame:                    PASS
basic_resync:                                             PASS
bug201_another_one:                                       PASS
bug201_wrong_frame_buffer:                                PASS
chomp_strings:                                            PASS
custom_io:                                                PASS
frame_seek_weirdness:                                     PASS
freeformat:                                               PASS
less_bytes_after_seek2:                                   PASS
less_bytes_after_seek:                                    PASS
more_bytes_on_second_decode:                              PASS
out123_errorlist:                                         PASS
out123_passthrough:                                       PASS
premature_decoder_change:                                 PASS
seek_accuracy:                                            PASS
string_alloc:                                             PASS

PASS

Build tests

Testing some build setups and looking at libmpg123 size.

Testing builds ...
config:
build default: PASS
   libmpg123.so=264K libsyn123.so=74K libout123.so=54K mpg123=139K out123=62K
config: --disable-shared
build static: PASS
   libmpg123.a=382K libsyn123.a=93K libout123.a=86K mpg123=456K out123=150K
config: --enable-portable
build portable: PASS
   libmpg123.so=256K libsyn123.so=74K libout123.so=54K out123=62K
config: --disable-8bit
build just no 8 bit: PASS
   libmpg123.so=256K libsyn123.so=74K libout123.so=54K mpg123=139K out123=62K
config: --disable-buffer --disable-feeder
config: --disable-messages --disable-moreinfo
config: --disable-feature_report --disable-network
config: --disable-icy --disable-id3v2 --disable-ntom
config: --disable-8bit --disable-16bit --disable-32bit
config: --disable-layer1 --disable-layer2
config: --enable-runtime-tables --disable-downsample
config: --disable-equalizer --disable-ieeefloat
build minimal mpg123: PASS
   libmpg123.so=124K libsyn123.so=74K libout123.so=34K mpg123=115K out123=54K
config: --disable-buffer --disable-feeder
config: --disable-messages --disable-moreinfo
config: --disable-feature_report --disable-network
config: --disable-icy --disable-id3v2 --disable-ntom
config: --disable-8bit --disable-16bit --disable-32bit
config: --disable-layer1 --disable-layer2
config: --enable-runtime-tables --disable-downsample
config: --disable-equalizer --disable-ieeefloat
config: --enable-portable --disable-string
build minimal libmpg123: PASS
   libmpg123.so=111K
config: --disable-buffer --disable-feeder
config: --disable-messages --disable-moreinfo
config: --disable-feature_report --disable-network
config: --disable-icy --disable-id3v2 --disable-ntom
config: --disable-8bit --disable-16bit --disable-32bit
config: --disable-layer1 --disable-layer2
config: --enable-runtime-tables --disable-downsample
config: --disable-equalizer --disable-ieeefloat
config: --enable-portable --disable-string
config: --with-cpu=generic
build minimal generic libmpg123: PASS
   libmpg123.so=99K
config: --with-audio=dummy
build cross arm-linux-gnueabihf default: PASS
   libmpg123.so=264K libsyn123.so=74K libout123.so=54K mpg123=139K out123=62K
config: --with-audio=dummy --disable-buffer
config: --disable-feeder --disable-messages
config: --disable-moreinfo --disable-feature_report
config: --disable-network --disable-icy --disable-id3v2
config: --disable-ntom --disable-8bit --disable-16bit
config: --disable-32bit --disable-layer1 --disable-layer2
config: --enable-runtime-tables --disable-downsample
config: --disable-equalizer --disable-ieeefloat
build cross arm-linux-gnueabihf minimal mpg123: PASS
   libmpg123.so=124K libsyn123.so=74K libout123.so=34K mpg123=115K out123=54K
config: --with-audio=dummy --disable-buffer
config: --disable-feeder --disable-messages
config: --disable-moreinfo --disable-feature_report
config: --disable-network --disable-icy --disable-id3v2
config: --disable-ntom --disable-8bit --disable-16bit
config: --disable-32bit --disable-layer1 --disable-layer2
config: --enable-runtime-tables --disable-downsample
config: --disable-equalizer --disable-ieeefloat
config: --enable-portable --disable-string
build cross arm-linux-gnueabihf minimal libmpg123: PASS
   libmpg123.so=111K
config: --with-audio=dummy
build cross aarch64-linux-gnu default: PASS
   libmpg123.so=264K libsyn123.so=74K libout123.so=54K mpg123=139K out123=62K
config: --with-audio=dummy --disable-buffer
config: --disable-feeder --disable-messages
config: --disable-moreinfo --disable-feature_report
config: --disable-network --disable-icy --disable-id3v2
config: --disable-ntom --disable-8bit --disable-16bit
config: --disable-32bit --disable-layer1 --disable-layer2
config: --enable-runtime-tables --disable-downsample
config: --disable-equalizer --disable-ieeefloat
build cross aarch64-linux-gnu minimal mpg123: PASS
   libmpg123.so=124K libsyn123.so=74K libout123.so=34K mpg123=115K out123=54K
config: --with-audio=dummy --disable-buffer
config: --disable-feeder --disable-messages
config: --disable-moreinfo --disable-feature_report
config: --disable-network --disable-icy --disable-id3v2
config: --disable-ntom --disable-8bit --disable-16bit
config: --disable-32bit --disable-layer1 --disable-layer2
config: --enable-runtime-tables --disable-downsample
config: --disable-equalizer --disable-ieeefloat
config: --enable-portable --disable-string
build cross aarch64-linux-gnu minimal libmpg123: PASS
   libmpg123.so=111K

Needed computing power

A test (GNU/Linux OS) with 0.60-beta2 showed 3 % to 4 % CPU usage on decoding high quality VBR MP3 with a pentiumII laptop with 366MHz, while a pentium 100MHz can easily handle two mpg123 instances in realtime (plus the mixing daemon that works on decoded data). Well, and more recently, A Core2Duo P8600 core can do 500 times realtime decoding (a track nearly five minutes long decoded in half a second).

Also, we have reports from such devices as nintendo DS or Sony PSP, or various embedded systems...

Michael said once upon a time

Plays Layer 3 in stereo on an AMD-486-120Mhz or (of course) a faster machine.

Just for info: mpg123 plays an average 128bps stream, with about 66% in full quality on an AMD 486-133MHz machine.

Hopefully valid HTML! Valid CSS!