MP3

From Segfault
Jump to: navigation, search

Fixing

There are several programs out there that might be able to fix a broken MP3 file.

vbrfix

vbrfix reads the MP3 structure and rebuilds the file including a new VBR header. This helps with files reporting an incorrect length, e.g. VBR files not properly marked as being VBR.

$ mkdir fixed
$ ls *mp3 | while read a; do vbrfix -always -makevbr -log "$a" fixed/"$a"; done
Fixing foo.mp3->vbrfix.tmp
FileLength = 8147337
Found Xing tag at 1 with size 208
10%...
20%...
30%...
40%...
Id3v1 tag found
DONE, ABR=151,Frames=16439
CHAN=2
Written new vbr tag
50%...
60%...
70%...
80%...
Copied vbrfix.tmp->fixed/foo.mp3
100%...

For some reason, vbrfix doesn't delete its temporary files afterwards:

$ ls -go vbrfix.*
-rw------- 1 2366360 Mar 24 15:08 vbrfix.log
-rw------- 1 8147546 Mar 24 15:08 vbrfix.tmp
$ rm -f vbrfix.*

mp3val

mp3val will analyze (and fix) corrupted MP3 files:

$ mp3val -f file.mp3
Analyzing file "file.mp3"...
WARNING: "file.mp3": Wrong number of MPEG frames specified in Xing header (1817 instead of 144584)
WARNING: "file.mp3": Wrong number of MPEG data bytes specified in Xing header (759848 instead of 60430192)
INFO: "file.mp3": 144584 MPEG frames (MPEG 1 Layer III), +ID3v1+ID3v2, CBR, CRC
Rebuilding file "file.mp3"...
FIXED: "file.mp3": File was rebuilt
Done!

When no corruptions are found, the file will be left alone.

mp3check

mp3check tries to check (and fix) MP3 files, but appears to be kinda buggy[1][2], as it reports various things as an "error" while ignoring real errors:

$ mp3check --error-check corrupt.mp3 
corrupt.mp3:
49535 bytes of junk before first frame header
valid id3 tag trailer v1.1 found

Even known-good files appear to contain "junk" before the first frame header. And I wouldn't consider ID3 tags as an error. So, let's ignore both of them:

$ mp3check --error-check --ign-junk-start --ign-tag128 --anomaly-check --fix-headers corrupt.mp3
$ echo $?
0

Yet, mp3val begs to differ, see above.

Note: there's another tool called mp3check. It's a Perl script from 2005 relying on id3tool (also from 2005, used to check the ID3 tags) and mp3_check (last release from 2000-09-15, used to check the internal consistency of the MP3 files).

mp3diags

mp3diags, in its own words:

> MP3 Diags is a GUI-based application that allows end-users to identify
> issues with their MP3 files, fix some of the issues and make other changes,
> like adding track information.

Removing cover art

Transcoding an MP3 file failed with:

[mp3 @ 0x7f8419010600] Skipping 0 bytes of junk at 73436.
[png @ 0x7f8419812600] Invalid PNG signature 0xFFD8FFE000104A46.
[mp3 @ 0x7f8419010600] decoding for stream 1 failed

The trick was to discard[3] the cover art, that was somehow mangled:

ffmpeg -y -i foobar.mp3 -map 0:a -vn -acodec libopus -map_metadata -1 foobar.opus

Merging

To merge multiple MP3 files into one without losing filename and ID3 information, mp3wrap can be used:

$ mp3wrap -v output.mp3 file-01.mp3 file-02.mp3
  50 %  --> Wrapping file-01.mp3 ... OK
 100 %  --> Wrapping file-02.mp3 ... OK

 Calculating CRC, please wait... OK
output_MP3WRAP.mp3 has been created successfully!

The output file is suffixed with _MP3WRAP. The ID3 information is wrapped into the file and can only be read after the file has been unwrapped again:

$ id3v2 -l output_MP3WRAP.mp3 | grep ^COMM
COMM (Comments): ()[]: This file is wrapped with Mp3Wrap. Get mp3splt, the free tool to split original files at
http://mp3splt.sourceforge.net. Please do not remove this comment.

We can also use FFmpeg to concatenate files:[4][5]

ffmpeg -i "concat:file-01.mp3|file-02.mp3" -acodec copy output.mp3

The resulting file size should be the sum of both source files:

$ ls -lgo file-01.mp3 file-02.mp3 output.mp3
-rw-r--r-- 1 13375616 Oct  9 11:57 file-01.mp3
-rw-r--r-- 1 13863040 Oct  9 11:57 file-02.mp3
-rw-r--r-- 1 27237729 Nov 22 21:07 output.mp3

Concatenating many files with FFmpeg can be done too, although it's a bit awkward to construct a valid command line:

ffmpeg -i "concat:$(ls file*.mp3 | xargs | sed 's/mp3 /mp3|/g')" -acodec copy output.mp3

While we're at it, let's convert the result into a different format[6] too:

ffmpeg -i "concat:$(ls file*.mp3 | xargs | sed 's/mp3 /mp3|/g')" -c:a libopus -vbr on output.opus

Using libopus makes quite a difference on the file size:

$ ls -hlgo file-01.mp3 file-02.mp3 output.opus
-rw-r--r-- 1 13M Oct  9 11:57 file-01.mp3
-rw-r--r-- 1 14M Oct  9 11:57 file-02.mp3
-rw-r--r-- 1 14M Nov 23 00:48 output.opus

Let's try that again but add metadata information to our output file:

ffmpeg -i "concat:$(ls file*.mp3 | xargs | sed 's/mp3 /mp3|/g')" -f wav - | opusenc --artist "Foobar" --album "Baz" --date "2015" --title "Song" --vbr - output.opus

Again, for vorbis-tools:

ffmpeg -i "concat:$(ls file*.mp3 | xargs | sed 's/mp3 /mp3|/g')" -f wav - | oggenc --artist "Foobar" --album "Baz" --date "2015" --title "Song" --tracknum 1 -q 3 - -o output.ogg

Re-encoding

Re-encoding might be the easiest way, if no other programs (see above) were able to help. With FFmpeg:

$ file foo.mp3
foo.mp3: Audio file with ID3 version 2.3.0, contains: MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, JntStereo

$ ffmpeg -i foo.mp3 -vn -ar 44100 -ac 2 -ab 128k -f mp3 foo_128.mp3
$ ls -lgo foo.mp3 foo_128.mp3
-rw------- 1 5963904 May 28 20:45 foo.mp3
-rw------- 1 5964340 May 28 20:49 foo_128.mp3

A second example[7][8]:

ffmpeg -i foo.mp3 -c:a libmp3lame -b:a 192k -vn foo_192.mp3               # CBR,  192 kbps
ffmpeg -i foo.mp3 -c:a libmp3lame -q:a 2    -vn foo_vbr.mp3               # VBR, ~170-210 kbps

With lame:

lame --strictly-enforce-ISO -p --mp3input -b 192 foo.mp3 foo_192.mp3      # CBR,  192 kbps
lame --strictly-enforce-ISO -p --mp3input -V 2 foo.mp3 foo_192.mp3        # VBR, ~190 kbps[9]

Note: the -p option adds a 16 bit checksum to every frame, for error protection.

On performance: LAME is not multi-core aware and thus will only use one CPU. There is a multithreaded version[10] called fpMP3Enc[11], but the project appears to be dead. Their development kit can still be downloaded[12] though.

Splitting

With mp3splt it's easy to split big files into smaller ones.

To split a 300 MB file into two smaller ones:

$ mp3splt -S 2 /mnt/media/big.mp3 -d . -o small-@n.mp3
Processing file '/mnt/media/big.mp3' ...
info: file matches the plugin 'mp3 (libmad)'
info: found Xing or Info header. Switching to frame mode...
info: MPEG 1 Layer 3 - 44100 Hz - Joint Stereo - FRAME MODE - Total time: 209m.00s
info: starting 'split in equal tracks' mode
  File "./small-01.mp3" created
  File "./small-02.mp3" created
Processed 480054 frames - Sync errors: 0
split in equal tracks ok

$ ls -hgo /mnt/media/big.mp3 small*.mp3
-rw------- 1 152M Mar 26 23:31 small-01.mp3
-rw------- 1 150M Mar 26 23:31 small-02.mp3
-rw-r--r-- 1 302M Feb 20  2013 /mnt/media/big.mp3

We can also do splitting tricks[13] with FFmpeg. When -acodec copy is used, the file is not re-encoded.

pull out a half hour chunk from the start of an audio file:

Extract the first 30 minutes from an audio file:

ffmpeg -i file.mp3 -acodec copy -ss 00:00:00 -t 00:30:00 file_30min.mp3

Split a 5 hour audio file into 30min tracks:

$ ffmpeg -i big-file.mp3 2>&1 | grep Duration
  Duration: 04:52:00.69, start: 0.025056, bitrate: 325 kb/s                       # That'd be ten 30min tracks

To do this, we create two files per hour:

mkdir split
i=0
while [ $i -lt 5 ]; do
    echo "Hour: $i"
    ffmpeg -i big-file.mp3 -acodec copy -ss 0${i}:00:00 -t 00:30:00 split/${i}a.mp3
    ffmpeg -i big-file.mp3 -acodec copy -ss 0${i}:30:00 -t 00:30:00 split/${i}b.mp3
    i=$((i+1))
done

Packages

Debian ships almost all mentioned programs by default:

apt-get install mp3wrap mp3splt lame twolame ffmpeg vorbis-tools opus-tools

Links

References