Mac下创建有声书

2014-03-03 14:18

本文介绍最近的折腾, 主要是如何高效地在Mac下创建有声书, 这包括:

软件准备

首先安装写必须的软件包, 首先需要安装Homebrew, 然后安装ffmpeg和mplayer.

brew install ffmpeg mplayer

关于mp3的合并, 本有另一个软件名为mp3wrap, 不过这个软件我不喜欢它命令行参数指定的方式, 而且生成出的文件也不一定靠谱(在音频纠错上有些问题, 导致iTunes卡死或提前中断), 于是没有安装它. 反正ffmpeg也能用来合并mp3文件.

音频提取

我们首先把视频中的音频提取出来, 这个我之前就做过. 这一次只是整理了一下代码, 加入了音频质量判断的逻辑:

DEFAULT_SAMPLE_RATE=32000
DEFAULT_BIT_RATE=80

fullpath="$1"
filename=`basename "$fullpath"`
suffix=`echo "$filename" | awk -F '.' '{print $NF}'`
basename=`basename "$filename" $suffix`
temp_name="${basename}mp3"
output_name="${basename}m4b"

mediainfo=`mplayer -endpos 0 -vo null -ao null "$fullpath" 2>/dev/null | grep "^AUDIO"`
bit_rate=`python -c "br = '${mediainfo}'.split(',')[3].strip().split()[0]; print min(br, ${DEFAULT_BIT_RATE})"`

ffmpeg -i "$fullpath" ${temp_name}

这样就能创建出一个临时的mp3文件, 里面是电影的音频, 我们后面会将这个文件转换成m4b的有声书格式.

mp3合并

前面说了, 用mp3wrap合并mp3并不算好的方法. 用ffmpeg合并音频的办法是:

ffmpeg -f concat -i files.list -c copy output.mp3

这儿的files.list应该是一个固定格式的文件. 里面包含需要合并的文件的信息. 为了生成这个列表, 需要一些简单的编码工作:

TEMPFILE=mp3join.list
OUTPUT="./output.mp3"
rm -f $TEMPFILE

python -c "import os; open('${TEMPFILE}', 'w').writelines(['file \'%s\'\n' % file.replace("'", "\\'") for file in os.listdir('.') if file.endswith('.mp3')])"

if [ -f $OUTPUT ]
then
    echo "file exist, quit"
    exit 1
fi

ffmpeg -f concat -i "$TEMPFILE" -c copy output.mp3

rm $TEMPFILE

这个脚本没啥复杂的, 就不解释了. 顺便想吐槽下, 我合并的时候有个文件的文件名里有一个英文单引号, 运行时导致ffmpeg抛了一个segmentation fault, 真是让人觉得堪忧. 我手工加了一个处理逻辑, replace了文件名中可能的单引号, 强行加了一个转义字符进去. 上面这个脚本我保存到自己放自己编写的命令的目录下, 使用的时候cd进到需要合并的mp3所在的文件夹, 然后执行一下这个脚本就行了.

mp3转换成m4b文件

之前我拿到mp3后都是导入到iTunes里面, 用iTunes自带的转换功能转换成aac编码的m4a文件, 然后再去目录里重命名成m4b文件. 这次找到了一个苹果自带的命令来进行格式的转换: afconvert. 执行转换的参数类似:

afconvert "${fullpath}" -v -s 3 -o "${output_name}" -q 127 -b "${bit_rate}000" -f m4bf -d aach

这个命令输出的m4b文件就可以直接导入到iTunes里了.

脚本

上面说了三个部分, 一个是视频提取, 一个是mp3合并, 一个是mp3转成m4b文件. 这儿分成了两个脚本, 一个是2m4b, 负责将输出的文件转换成m4b文件; 另一个是mp3join, 只负责合并. mp3join已经贴在前面了, 这儿只需要2m4b:

#!/usr/bin/env bash
#
# Author:         Xia Kai <xiaket@corp.netease.com/xiaket@gmail.com>
# Filename:       2m4b
# Date created:   2014-02-27 16:52
# Last modified:  2014-02-27 16:52
# Modified by:    Xia Kai <xiaket@corp.netease.com/xiaket@gmail.com>
#
# Description:
# create an m4b audiobook file from a movie or an mp3 file.
# Changelog:
# 2014-02-28 11:28: added mp3 support.

DEFAULT_SAMPLE_RATE=32000
DEFAULT_BIT_RATE=80

fullpath="$1"
filename=`basename "$fullpath"`
suffix=`echo "$filename" | awk -F '.' '{print $NF}'`
basename=`basename "$filename" $suffix`
temp_name="${basename}mp3"
output_name="${basename}m4b"

mediainfo=`mplayer -endpos 0 -vo null -ao null "$fullpath" 2>/dev/null | grep "^AUDIO"`
bit_rate=`python -c "br = '${mediainfo}'.split(',')[3].strip().split()[0]; print min(br, ${DEFAULT_BIT_RATE})"`

if [ $suffix = "mp3" ]
then
    afconvert "${fullpath}" -v -s 3 -o "${output_name}" -q 127 -b "${bit_rate}000" -f m4bf -d aach
else

    ffmpeg -i "$fullpath" "${temp_name}" && afconvert "${temp_name}" -v -s 3 -o "${output_name}" -q 127 -b "${bit_rate}000" -f m4bf -d aach && rm "${temp_name}"
fi