Skip to content

Commit

Permalink
add: Option adjust for ipod recalculates the bitrate according to the…
Browse files Browse the repository at this point in the history
… max. sampling rate on ipod devices

add: Option for tagging album (used as title in iTunes)
  • Loading branch information
Andreas committed Feb 11, 2018
1 parent 819f02e commit b8c4832
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 3 deletions.
19 changes: 18 additions & 1 deletion src/library/M4bTool/Command/AbstractConversionCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ class AbstractConversionCommand extends AbstractCommand
const OPTION_AUDIO_BIT_RATE = "audio-bitrate";
const OPTION_AUDIO_SAMPLE_RATE = "audio-samplerate";
const OPTION_AUDIO_CODEC = "audio-codec";
const OPTION_ADJUST_FOR_IPOD = "adjust-for-ipod";

protected $optAudioFormat;
protected $optAudioExtension;
protected $optAudioChannels;
protected $optAudioBitRate;
protected $optAudioSampleRate;
protected $optAudioCodec;
protected $optAdjustBitrateForIpod;


protected function configure()
Expand All @@ -32,9 +34,10 @@ protected function configure()
$this->addOption(static::OPTION_AUDIO_BIT_RATE, null, InputOption::VALUE_OPTIONAL, "audio bitrate, e.g. 64k, 128k, ...", ""); // -ab 128k
$this->addOption(static::OPTION_AUDIO_SAMPLE_RATE, null, InputOption::VALUE_OPTIONAL, "audio samplerate, e.g. 22050, 44100, ...", ""); // -ar 44100
$this->addOption(static::OPTION_AUDIO_CODEC, null, InputOption::VALUE_OPTIONAL, "audio codec, e.g. libmp3lame, aac, ...", ""); // -ar 44100

$this->addOption(static::OPTION_ADJUST_FOR_IPOD, null, InputOption::VALUE_NONE, "auto adjust bitrate and sampling rate for ipod, if track is to long (may lead to poor quality)");

$this->addOption("name", null, InputOption::VALUE_OPTIONAL, "provide a custom audiobook name, otherwise the existing metadata will be used", "");
$this->addOption("album", null, InputOption::VALUE_OPTIONAL, "provide a custom audiobook album, otherwise the existing metadata for name will be used", "");
$this->addOption("artist", null, InputOption::VALUE_OPTIONAL, "provide a custom audiobook artist, otherwise the existing metadata will be used", "");
$this->addOption("genre", null, InputOption::VALUE_OPTIONAL, "provide a custom audiobook genre, otherwise the existing metadata will be used", "");
$this->addOption("writer", null, InputOption::VALUE_OPTIONAL, "provide a custom audiobook writer, otherwise the existing metadata will be used", "");
Expand All @@ -55,6 +58,7 @@ protected function loadArguments()
"mp3" => "libmp3lame"
];

$this->optAdjustBitrateForIpod = $this->input->getOption(static::OPTION_ADJUST_FOR_IPOD);
$this->optAudioCodec = $this->input->getOption(static::OPTION_AUDIO_CODEC);
$this->optAudioFormat = $this->input->getOption(static::OPTION_AUDIO_FORMAT);
$this->optAudioExtension = $this->optAudioFormat;
Expand Down Expand Up @@ -141,6 +145,7 @@ protected function tagFile(SplFileInfo $file, Tag $tag)

if ($this->optAudioFormat === "mp4") {
$command = [];

$this->appendParameterToCommand($command, "-track", $tag->track);
$this->appendParameterToCommand($command, "-tracks", $tag->tracks);
$this->appendParameterToCommand($command, "-song", $tag->title);
Expand All @@ -149,6 +154,7 @@ protected function tagFile(SplFileInfo $file, Tag $tag)
$this->appendParameterToCommand($command, "-writer", $tag->writer);
$this->appendParameterToCommand($command, "-albumartist", $tag->albumArtist);
$this->appendParameterToCommand($command, "-year", $tag->year);
$this->appendParameterToCommand($command, "-album", $tag->album);
if (count($command) > 1) {
$command[] = $file;
$this->mp4tags($command, "tagging file " . $file);
Expand All @@ -173,6 +179,13 @@ public function inputOptionsToTag()
{
$tag = new Tag;
$tag->title = $this->input->getOption("name");
$tag->album = $this->input->getOption("album");

// on ipods / itunes, album is for title of the audio book
if($this->optAdjustBitrateForIpod && $tag->title && !$tag->album) {
$tag->album = $tag->title;
}

$tag->artist = $this->input->getOption("artist");
$tag->genre = $this->input->getOption("genre");
$tag->writer = $this->input->getOption("writer");
Expand Down Expand Up @@ -201,6 +214,10 @@ protected function bitrateStringToInt() {
return $value * $multiplier;
}

protected function samplingRateToInt() {
return (int)str_ireplace("hz", "", $this->optAudioSampleRate);
}

protected function appendFfmpegTagParametersToCommand(&$command, Tag $tag)
{
if ($tag->title) {
Expand Down
71 changes: 69 additions & 2 deletions src/library/M4bTool/Command/MergeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,62 @@ private function convertInputFiles()
if (!is_dir($dir) && !mkdir($dir, 0700, true)) {
throw new Exception("Could not create temp directory " . $dir);
}

if($this->optAdjustBitrateForIpod) {
$this->output->writeln("ipod auto adjust active, getting track durations");
$this->totalDuration = new TimeUnit();
foreach ($this->filesToConvert as $index => $file) {
$duration = $this->readDuration($file);
if (!$duration) {
throw new Exception("could not get duration for file ".$file." - needed for ". static::OPTION_ADJUST_FOR_IPOD);
}
$this->totalDuration->add($duration->milliseconds());
}

$samplingRateToBitrateMapping = [
8000 => "24k",
11025 => "32k",
12000 => "32k",
16000 => "48k",
22050 => "64k",
32000 => "96k",
44100 => "128k",
];

$durationSeconds = $this->totalDuration->milliseconds() / 1000;
$maxSamplingRate = 2147483647 / $durationSeconds;
$this->output->writeln("total duration: ".$this->totalDuration->format("%H:%I:%S.%V")." (".$durationSeconds."s)");
$this->output->writeln("max possible sampling rate: ".$maxSamplingRate."Hz");
$this->output->writeln("desired sampling rate: ".$this->optAudioSampleRate."Hz");

if($this->samplingRateToInt() > $maxSamplingRate) {
$this->output->writeln("desired sampling rate ".$this->optAudioSampleRate." is greater than max sampling rate ".$maxSamplingRate."Hz, trying to adjust");
$resultSamplingRate = 0;
$resultBitrate = "";
foreach($samplingRateToBitrateMapping as $samplingRate => $bitrate) {
if($samplingRate <= $maxSamplingRate) {
$resultSamplingRate = $samplingRate;
$resultBitrate = $bitrate;
} else {
break;
}
}

if($resultSamplingRate === 0) {
throw new Exception("Could not find an according setting for ".static::OPTION_AUDIO_BIT_RATE." / ".static::OPTION_AUDIO_SAMPLE_RATE. " for option ".static::OPTION_ADJUST_FOR_IPOD);
}

$this->optAudioSampleRate = $resultSamplingRate;
$this->optAudioBitRate = $resultBitrate;
$this->output->writeln("adjusted to ".$resultBitrate."/".$resultSamplingRate);
} else {
$this->output->writeln("desired sampling rate is ok, nothing to change");
}

}



foreach ($this->filesToConvert as $index => $file) {

$pad = str_pad($index + 1, $padLen, "0", STR_PAD_LEFT);
Expand All @@ -204,22 +260,33 @@ private function convertInputFiles()
"-map_metadata", "0",
];


// backwards compatibility: ffmpeg needed experimental flag in earlier versions
if ($this->optAudioCodec == "aac") {
$command[] = "-strict";
$command[] = "experimental";
}

if ($this->optAudioCodec == "libfdk_aac" && $this->bitrateStringToInt() <= 64000) {
/*
// If you require a low audio bitrate, such as ≤ 32kbs/channel, then HE-AAC would be worth considering
// if your player or device can support HE-AAC decoding. Anything higher may benefit more from AAC-LC due
// to less processing. If in doubt use AAC-LC. All players supporting HE-AAC also support AAC-LC.
// These HE-AAC-Files are not iTunes compatible, although iTunes should support it
if ($this->optAudioCodec == "libfdk_aac" && $this->bitrateStringToInt() <= 32000) {
$command[] = "-profile:a";
$command[] = "aac_he";
}
*/


// workaround incompatible files (only for windows systems)
if ($this->isWindows()) {
$command[] = "-vf";
$command[] = "scale=800:800";
}

// Relocating moov atom to the beginning of the file can facilitate playback before the file is completely downloaded by the client.
$command[] = "-movflags";
$command[] = "+faststart";

$this->appendParameterToCommand($command, "-y", $this->optForce);
$this->appendParameterToCommand($command, "-ab", $this->optAudioBitRate);
Expand Down

0 comments on commit b8c4832

Please sign in to comment.