Pull to refresh

Создание m4b из mp3 аудиокниг для ipod

Reading time 3 min
Views 17K
Захотелось давеча прослушать аудиокнижку одну, проблема в том, что прослушать ее захотелось на ipod, а в m4b формате нигде найти не смог, только mp3.

После продолжительного гугления, был найден пост с идеями как это сделать, но без нормальной реализации. Своими идеями и решениями я успел поделиться с автором этого поста, но он их, спустя какое-то время, зачем-то потер.

Суть в том, что .m4b это файл AAC в контейнере mp4, но с закладками и переименованный. Следовательно, необходимо все mp3 перегнать в aac и сгенерировать файл закладок (chapters), в quicktime формате, после чего запихнуть все это дело в mp4 контейнер.

Под linux есть только 1 нормальный AAC encoder — NeroAacEncoder. Код закрыт, но он бесплатен и работает.
Альтернатива есть в ffmpeg, но она очень сырая.
Еще есть alac encoder\decoder, тоже в ffmpeg, но он вообще не контролирует битрейт — 10 метровый mp3 превращается в 100Мб монстра.

Изначально, запихивать в контейнер планировалось с помощью MP4Box, которая входит в пакет gpac. А libmp4v2 использовать для разметки тэгов и обработки chapters-файла (только надо обязательно использовать trunk-r355 snapshot, там много багфиксов, да и стабильная версия все равно не работает правильно).

Тут-то и выяснилось что MP4Box имеет ограничение на запихивание в один контейнер — 20 файлов (почему и зачем не понятно). Да и chapters-файл, с таким подходом, надо генерировать самому. Результатом стал этот скрипт на 140 строк и несколькими проблемами.

Чуть позже было найдено гораздо более оптимальное решение — mp3 перегонять в wav, а потом их перегонять всем скопом через NeroAacEnc, который умет сам генерировать chapters и не имеет ограничений на кол-во входящих файлов. Тэги можно расставить NeroAacTag (они в комплекте идут) одной строкой, и, есть мнение, что это будет более правильно и аккуратно. Правда это не избавляет от использования mp4chaps (из libmp4v2) для конвертации nero-закладок в quicktime-закладки.

UPD: Это довольно очевидно, но все же — файлы должны иметь правильные названия\нумерацию, что бы `ls -1` их выводил в правильном порядке. Не 1..12, а 01..12, к примеру.
Или, как совершенно справедливо заметил xn__p2a, использовать «ls -1v» (для вывода 1..12).

# FIELD SEPARATOR
IFS=$'\n'
# ALL MP3 TO WAV
for i in `ls -1 *.mp3`; do mplayer -nocorrect-pts -vo null -vc null -ao pcm:fast:file="${i%%mp3}wav" "$i"; done
# CONCATE ALL WAV TO MP4 WITH AUTOMATIC CREATION OF CHAPTER MARKS
for i in `ls -1 *.wav`; do printf %s "-if \"$i\" ";done | xargs ../neroAacEnc -of OUT.mp4
# SET CORRECT TAGS
../neroAacTag -meta:title="MY_TITLE" -meta:artist="MY_AUTHOR" -add-cover:front:BOOK_COVER.jpg OUT.mp4
# CONVERT CHAPTERS FOR IPOD
mp4chaps -convert --chapter-qt OUT.mp4


Конечно, теперь на винте лежат не aac, а огромные wav, которые надо будет потом убить, да и через fifo (так было в первом скрипте) как-то элегантнее, но все стало намного проще.

UPD: есть мнение, что использовать mplayer для получения wav из mp3 это оверкилл.
Некоторые альтернативы:
ffmpeg -i input.mp3 output.wav
mpg123 -w output.wav input.mp3
lame -decode input.mp3 output.wav 


В новоиспеченном m4b файле, названия глав будут типа 'Chapter 01', но это можно легко исправить, отредактировав файл закладок:

# EXPORT CHAPTERS TO MP4FILE.CHAPTERS.TXT
mp4chaps -x test.mp4
# NOW YOU CAN MODIFY THEM AND IMPORT BACK
mp4chaps -i test.mp4


Как и чем редактировать — на ваш выбор.

gtkpod-1.0.0 и libgpod-0.8.0 научились поддерживать ipod nano 5-го поколения, так что я пользую их.

UPD: после продолжительно переписки с xn__p2a, появился третий вариант скрипта:
#!/bin/bash
# INPUT FIELD SEPARATOR
IFS=$'\n'
# JUST MORE CONVINIENT
function mpfifo {
  mplayer -nocorrect-pts -vo null -vc null -ao pcm:fast:file="${1%%mp3}wav" "$1" &>"/dev/null" &
}
# NEED MORE FIFO!!111
for i in `ls -1v *.mp3`; do mkfifo "${i%%mp3}wav"; done
# RUN NEROAACENC
for i in `ls -1v *.mp3`; do printf %s " -if \""${i%%mp3}wav"\"";done | xargs ../../neroAacEnc -of test.mp4 &
# RUN ALL MP3
for i in `ls -1v *.mp3`; do mpfifo "$i"; done
# CONVERT CHAPTERS
mp4chaps -convert --chapter-qt test.mp4

Этот вариант признан более элегантным, т.к. чистить надо только 0B fifo: `find -maxdepth 1 -type p -exec rm {} +`

PS: Жаль не получается завернуть выхлопы mplayer'а в инпут neroAacEnc, так что бы он их принимал за отдельные файлы (иначе авторазметки не будет).
PPS: НЕ ставить systemwide libmp4v2 trunk 335 — слетит 1\2 вещей зависящих от этой либы, а gtkpod разучится понимать m4a\m4b файлы.
PPPS: Можно заворачивать отдельные aac в отдельные mp4 и переименовывать в m4a, если хочется loseless музыки на ipod.
Tags:
Hubs:
+23
Comments 17
Comments Comments 17

Articles