Perl Script to Convert an Audiobook (m4b) to mp3 files splitting on the chapters

I have an Nissan Altima with a BOSE radio that allows me to hook up an USB thumbdrive containing mp3 files. The problem is most of my audiobooks are in m4b format. Previously I’ve used tools like mp3splt and tried to split on ‘silence’ or timed increments (say 15 min) but I was getting mp3 files that would be split in midsentence and sometimes midword. It became very annoying after awhile.

So, I came up with a really simple script to convert an audiobook (m4b) into mp3 files splitting on the chapters. We are dependent on FFmpeg::Command and a modified FFprobe Perl module.

In the following example, we are converting a Ben Bova audiobook but we are going to specify to start the track numbering at “10” because the 2nd file ended with track “9”.

jason@jason-Inspiron-1545 ~/bin $ ./ -i "/home/jason/Audiobooks/Ben Bova/Mars/Mars 3.m4b" -o mp3 -a "Mars" -t 10
Converting "Mars 3.m4b" to "mp3/010 Mars.mp3"...
	album: Mars
	artist: Ben Bova
	title: 010 - Mars
	genre: Audiobook
	track: 10
Converting "Mars 3.m4b" to "mp3/011 Mars.mp3"...
	album: Mars
	artist: Ben Bova
	title: 011 - Mars
	genre: Audiobook
	track: 11
Converting "Mars 3.m4b" to "mp3/012 Mars.mp3"...
	album: Mars
	artist: Ben Bova
	title: 012 - Mars
	genre: Audiobook
	track: 12
Converting "Mars 3.m4b" to "mp3/013 Mars.mp3"...
	album: Mars
	artist: Ben Bova
	title: 013 - Mars
	genre: Audiobook
	track: 13
Converting "Mars 3.m4b" to "mp3/014 Mars.mp3"...
	album: Mars
	artist: Ben Bova
	title: 014 - Mars
	genre: Audiobook
	track: 14

Source code:


use strict;
use warnings;

use lib qw(/home/jason/bin);

use Getopt::Std;
use File::Basename;
use FFmpeg::Command;
use FFprobe;


sub _encode_mp3 {
  my ($input_file, $output_dir, $album, $starting_track) = @_;

  my %tags = ();
  my $track_number;
  my $mp4 = FFprobe->probe_file($input_file);
  my $base_output_file = basename($input_file);
  $base_output_file =~ s/\.\w+$//;

  if (exists $mp4->{format}->{'TAG:comment'}) {
    $tags{genre} = $mp4->{format}->{'TAG:comment'};
    $tags{genre} =~ s/("')//g;

  if (exists $mp4->{format}->{'TAG:genre'}) {
    $tags{genre} = $mp4->{format}->{'TAG:genre'};
    $tags{genre} =~ s/("')//g;

  if (exists $mp4->{format}->{'TAG:artist'}) {
    $tags{artist} = $mp4->{format}->{'TAG:artist'};
    $tags{artist} =~ s/("')//g;

  if ($album) {
    $tags{album} = $album;
  } elsif (exists $mp4->{format}->{'TAG:album'}) {
    $tags{album} = $mp4->{format}->{'TAG:album'};

  $tags{album} =~ s/("')//g;
  $track_number = $starting_track if $starting_track;

  foreach my $chapter (sort keys %{$mp4->{chapters}}) {
    unless ($starting_track) {
      $track_number = $chapter;

    my $output_file = sprintf "%s/%03d %s.mp3", $output_dir, $track_number, $tags{album};
    my $start = $mp4->{chapters}->{$chapter}->{start};
    my $duration = $mp4->{chapters}->{$chapter}->{end} - $start;
    my @options = ();

    if ($album) {
      $tags{title} = sprintf "%03d - %s", $track_number, $album;
    } else {
      if (exists $mp4->{format}->{'TAG:title'}) {
        $tags{title} = sprintf "%03d - %s", $track_number, $mp4->{format}->{'TAG:title'};
      } else {
        $tags{title} = sprintf "%03d - %s", $track_number, $base_output_file;

    $tags{title} =~ s/("')//g;

    my $ffmpeg = FFmpeg::Command->new;

        file => $input_file,

     'file' => $output_file,
     'audio_codec' => 'libmp3lame',
     'audio_bit_rate' => 64,

    printf "Converting \"%s\" to \"%s\"...\n", basename($input_file), $output_file;

Share Button

How to create an iTunes/iPod compatible audiobook (MPEG4 m4b) on Linux using MP4Box and mp4v2 v1.9.1 – it can be done!

I’ve been wracking my brains over this for the past few weeks and it finally struck me how to create an m4b audiobook with chapters that is compatible with your iPod, iTunes, VLC, etc.  It was very simple once I figured it out:

Step 1:

encode the mp3 files to “aac” (mpeg4) using your favorite converter (I use ffmpeg):

ffmpeg -i "track1.mp3" -y -vn -acodec libfaac -ab 128k -ar 44100 -threads 3 -f mp4 track1.aac

Step 2:

Create a chapters file so that MP4Box can understand it:

* Common syntax : CHAPTERX=h:m:s[:ms or .ms] on one line and CHAPTERXNAME=name on the other – the order is not important but chapter lines MUST be declared sequencially (same X value expected for 2 consecutive lines).


CHAPTER1NAME=Chapter 001
CHAPTER2NAME=Chapter 002
CHAPTER3NAME=Chapter 003
CHAPTER4NAME=Chapter 004
CHAPTER5NAME=Chapter 005
CHAPTER6NAME=Chapter 006
CHAPTER7NAME=Chapter 007
CHAPTER8NAME=Chapter 008
CHAPTER9NAME=Chapter 009
CHAPTER10NAME=Chapter 010
CHAPTER11NAME=Chapter 011
CHAPTER12NAME=Chapter 012
CHAPTER13NAME=Chapter 013
CHAPTER14NAME=Chapter 014
CHAPTER15NAME=Chapter 015
CHAPTER16NAME=Chapter 016
CHAPTER17NAME=Chapter 017
CHAPTER18NAME=Chapter 018
CHAPTER19NAME=Chapter 019
CHAPTER20NAME=Chapter 020
CHAPTER21NAME=Chapter 021
CHAPTER22NAME=Chapter 022

Step 3:

Add the chapters to the audio file (creates Nero format chapter markers):

MP4Box -add track1.aac -chap track1.chapters test.mp4

Step 4:

Convert the Nero chapter markers to Quicktime chapter markers using mp4chaps from the mp4v2 project (you will want v1.9.1 or higher):

mp4chaps --convert --chapter-qt test.mp4
converting chapters in file "test.mp4" from Nero to QuickTime

Step 5:

Rename the file from .mp4 to .m4b extension so iTunes will see it as an audiobook:

mv test.mp4 test.m4b

Proof that it works:

and VLC showing the chapters:

Of course, we aren’t putting in any tags such as “author” or “genre” in this example. Use your favorite tags editor to do so.

Share Button