Skip to content

Instantly share code, notes, and snippets.

@NinoSkopac
Created May 12, 2018 19:34
Show Gist options
  • Save NinoSkopac/fdf1c88da6d9d57c852eca3a688f3310 to your computer and use it in GitHub Desktop.
Save NinoSkopac/fdf1c88da6d9d57c852eca3a688f3310 to your computer and use it in GitHub Desktop.
Get correct OGG Vorbis metadata using ffprobe (requires getID3 library)
<?php
/**
* Created by PhpStorm.
* User: ninoskopac
* Date: 10/05/2018
* Time: 07:01
*/
declare(strict_types=1);
namespace Read2Me\Synthesis;
use Symfony\Component\Process\Process;
final class AudioMeta implements AudioMetaInterface
{
/** @var \SplFileObject */
private $file;
/** @var array */
private $data;
public function __construct(\SplFileObject $file)
{
$getId3 = new \getID3();
$this->file = $file;
$this->data = $getId3->analyze($this->file->getRealPath());
// getID3 returns invalid data for Ogg_vorbis, so have to do it
// manually using FFMpeg//ffprobe. yayness
if ($this->file->getExtension() == 'ogg')
$this->ffprobe();
}
/**
* Override the following properties:
* - duration in seconds
* - duration in human readable
* - sample rate
* - bitrate (ffprobe returns this in kb/s, R2M stores it in b/s)
*/
private function ffprobe(): void {
$cmd = sprintf('ffprobe -i %s -show_format', escapeshellarg($this->file->getRealPath()));
$process = new Process($cmd);
$process->mustRun();
// fprobe returns a lot of useful data as info into stderr
// https://trac.ffmpeg.org/ticket/2226
// https://trac.ffmpeg.org/ticket/5020
$info = $process->getErrorOutput();
$format = $process->getOutput();
preg_match('/duration\=(.+)/', $format, $duration);
preg_match('/Duration\: ((\d{2})\:(\d{2})\:(\d{2}))/', $info, $durationHuman);
preg_match('/\, (.+) Hz/', $info, $sampleRate);
preg_match('/bitrate\: (.+) kb\/s/', $info, $bitrate);
$duration = (int) ceil($duration[1]);
[, $durationHumanHms, $durationHours, $durationMinutes, $durationSeconds] = $durationHuman;
if ($durationHours == '00')
$durationHuman = sprintf('%d:%d', $durationMinutes, $durationSeconds);
else
$durationHuman = $durationHumanHms;
$sampleRate = $sampleRate[1];
$bitrate = ((int) $bitrate[1]) * 1000;
$this->data['playtime_seconds'] = $duration;
$this->data['playtime_string'] = $durationHuman;
$this->data['audio']['sample_rate'] = (int) $sampleRate;
$this->data['audio']['bitrate'] = $bitrate;
}
public function getLength(): int
{
return (int) ceil($this->data['playtime_seconds']);
}
public function getPlaytime(): string
{
return $this->data['playtime_string'];
}
public function getFilesize(): int
{
return $this->data['filesize'];
}
public function getFormat(): string
{
return $this->data['fileformat'];
}
public function getSampleRate(): int
{
return $this->data['audio']['sample_rate'];
}
public function getBitrate(): int
{
return (int) $this->data['audio']['bitrate'];
}
public function getMime(): string
{
return strpos($this->data['mime_type'], ';') !== false ?
strstr($this->data['mime_type'], ';', true)
:
$this->data['mime_type'];
}
public function toArray(): array {
return [
'length' => $this->getLength(),
'playtime' => $this->getPlaytime(),
'filesize' => $this->getFilesize(),
'format' => $this->getFormat(),
'sample_rate' => $this->getSampleRate(),
'bitrate' => $this->getBitrate(),
'mime' => $this->getMime()
];
}
}
@NinoSkopac
Copy link
Author

here's the interface

interface AudioMetaInterface
{
    public function __construct(\SplFileObject $file);
    public function getLength(): int;
    public function getPlaytime(): string;
    public function getFilesize(): int;
    public function getFormat(): string;
    public function getSampleRate(): int;
    public function getBitrate(): int;
    public function getMime(): string;
    public function toArray(): array;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment