rlm@3: | rlm@3: // | Allan Hansen | rlm@3: // +----------------------------------------------------------------------+ rlm@3: // | module.audio.shorten.php | rlm@3: // | Module for analyzing Shorten Audio files | rlm@3: // | dependencies: module.audio-video.riff.php | rlm@3: // +----------------------------------------------------------------------+ rlm@3: // rlm@3: // $Id: module.audio.shorten.php,v 1.5 2006/12/03 19:28:18 ah Exp $ rlm@3: rlm@3: rlm@3: rlm@3: class getid3_shorten extends getid3_handler rlm@3: { rlm@3: rlm@3: public function __construct(getID3 $getid3) { rlm@3: rlm@3: parent::__construct($getid3); rlm@3: rlm@3: if ((bool)ini_get('safe_mode')) { rlm@3: throw new getid3_exception('PHP running in Safe Mode - backtick operator not available, cannot analyze Shorten files.'); rlm@3: } rlm@3: rlm@3: if (!`head --version`) { rlm@3: throw new getid3_exception('head[.exe] binary not found in path. UNIX: typically /usr/bin. Windows: typically c:\windows\system32.'); rlm@3: } rlm@3: rlm@3: if (!`shorten -l`) { rlm@3: throw new getid3_exception('shorten[.exe] binary not found in path. UNIX: typically /usr/bin. Windows: typically c:\windows\system32.'); rlm@3: } rlm@3: } rlm@3: rlm@3: rlm@3: public function Analyze() { rlm@3: rlm@3: $getid3 = $this->getid3; rlm@3: rlm@3: $getid3->include_module('audio-video.riff'); rlm@3: rlm@3: fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); rlm@3: rlm@3: $shn_header = fread($getid3->fp, 8); rlm@3: rlm@3: // Magic bytes: "ajkg" rlm@3: rlm@3: $getid3->info['fileformat'] = 'shn'; rlm@3: $getid3->info['audio']['dataformat'] = 'shn'; rlm@3: $getid3->info['audio']['lossless'] = true; rlm@3: $getid3->info['audio']['bitrate_mode'] = 'vbr'; rlm@3: rlm@3: $getid3->info['shn']['version'] = getid3_lib::LittleEndian2Int($shn_header{4}); rlm@3: rlm@3: fseek($getid3->fp, $getid3->info['avdataend'] - 12, SEEK_SET); rlm@3: rlm@3: $seek_table_signature_test = fread($getid3->fp, 12); rlm@3: rlm@3: $getid3->info['shn']['seektable']['present'] = (bool)(substr($seek_table_signature_test, 4, 8) == 'SHNAMPSK'); rlm@3: if ($getid3->info['shn']['seektable']['present']) { rlm@3: rlm@3: $getid3->info['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($seek_table_signature_test, 0, 4)); rlm@3: $getid3->info['shn']['seektable']['offset'] = $getid3->info['avdataend'] - $getid3->info['shn']['seektable']['length']; rlm@3: fseek($getid3->fp, $getid3->info['shn']['seektable']['offset'], SEEK_SET); rlm@3: $seek_table_magic = fread($getid3->fp, 4); rlm@3: rlm@3: if ($seek_table_magic != 'SEEK') { rlm@3: rlm@3: throw new getid3_exception('Expecting "SEEK" at offset '.$getid3->info['shn']['seektable']['offset'].', found "'.$seek_table_magic.'"'); rlm@3: } rlm@3: rlm@3: $seek_table_data = fread($getid3->fp, $getid3->info['shn']['seektable']['length'] - 16); rlm@3: $getid3->info['shn']['seektable']['entry_count'] = floor(strlen($seek_table_data) / 80); rlm@3: } rlm@3: rlm@3: $commandline = 'shorten -x '.escapeshellarg(realpath($getid3->filename)).' - | head -c 64'; rlm@3: $output = `$commandline`; rlm@3: rlm@3: if (@$output && substr($output, 12, 4) == 'fmt ') { rlm@3: rlm@3: $fmt_size = getid3_lib::LittleEndian2Int(substr($output, 16, 4)); rlm@3: $decoded_wav_format_ex = getid3_riff::RIFFparseWAVEFORMATex(substr($output, 20, $fmt_size)); rlm@3: rlm@3: $getid3->info['audio']['channels'] = $decoded_wav_format_ex['channels']; rlm@3: $getid3->info['audio']['bits_per_sample'] = $decoded_wav_format_ex['bits_per_sample']; rlm@3: $getid3->info['audio']['sample_rate'] = $decoded_wav_format_ex['sample_rate']; rlm@3: rlm@3: if (substr($output, 20 + $fmt_size, 4) == 'data') { rlm@3: rlm@3: $getid3->info['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $decoded_wav_format_ex['raw']['nAvgBytesPerSec']; rlm@3: rlm@3: } else { rlm@3: rlm@3: throw new getid3_exception('shorten failed to decode DATA chunk to expected location, cannot determine playtime'); rlm@3: } rlm@3: rlm@3: $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) / $getid3->info['playtime_seconds']) * 8; rlm@3: rlm@3: } else { rlm@3: rlm@3: throw new getid3_exception('shorten failed to decode file to WAV for parsing'); rlm@3: return false; rlm@3: } rlm@3: rlm@3: return true; rlm@3: } rlm@3: rlm@3: } rlm@3: rlm@3: ?>