MP3

From Segfault
Jump to navigation Jump to search

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:[1][2]

ffmpeg -i "concat:file-01.mp3|file-02.mp3" -codec:a 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')" -codec:a copy output.mp3

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

ffmpeg -i "concat:$(ls file*.mp3 | xargs | sed 's/mp3 /mp3|/g')" -codec:a libopus 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, with opusenc:

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

Again, with 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 - -o output.ogg

Apparently ffmpeg can add metadata as well,[4] w/o the need for an extra program:

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

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 -b:a 192k -f mp3 foo_192.mp3
$ ls -lgo foo.mp3 foo_192.mp3
-rw------- 1 4239196 May 28 20:45 foo.mp3
-rw------- 1 5274149 May 28 20:49 foo_128.mp3

A second example[5][6]:

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

With lame:

lame --strictly-enforce-ISO -p --mp3input --bitwidth 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[7]

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[8] called fpMP3Enc[9], but the project appears to be dead. Their development kit can still be downloaded[10] 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[11] 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

Fixing

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

mp3val

mp3val will analyze (and fix) corrupted MP3 files:

svn checkout https://svn.code.sf.net/p/mp3val/subversion/trunk mp3val-svn
cd mp3val-svn
make -C sources/ -f Makefile.linux 
sudo install -o root -g root -m 0755 sources/mp3val /usr/local/bin/mp3val

Usage:

$ 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.

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[12] the cover art, that was somehow mangled:

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

Links

References