21 $info = &$this->getid3->info;
23 if ($this->
fread(4) ==
'ADIF') {
34 $info = &$this->getid3->info;
35 $info[
'fileformat'] =
'aac';
36 $info[
'audio'][
'dataformat'] =
'aac';
37 $info[
'audio'][
'lossless'] =
false;
40 $AACheader = $this->
fread(1024);
43 if (substr($AACheader, 0, 4) ==
'ADIF') {
68 $info[
'aac'][
'header_type'] =
'ADIF';
70 $info[
'aac'][
'header'][
'mpeg_version'] = 4;
72 $info[
'aac'][
'header'][
'copyright'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) ==
'1');
74 if (
$info[
'aac'][
'header'][
'copyright']) {
78 $info[
'aac'][
'header'][
'original_copy'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) ==
'1');
80 $info[
'aac'][
'header'][
'home'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) ==
'1');
82 $info[
'aac'][
'header'][
'is_vbr'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) ==
'1');
84 if (
$info[
'aac'][
'header'][
'is_vbr']) {
85 $info[
'audio'][
'bitrate_mode'] =
'vbr';
89 $info[
'audio'][
'bitrate_mode'] =
'cbr';
92 $info[
'audio'][
'bitrate'] =
$info[
'aac'][
'header'][
'bitrate'];
94 if (
$info[
'audio'][
'bitrate'] == 0) {
95 $this->
error(
'Corrupt AAC file: bitrate_audio == zero');
101 for (
$i = 0;
$i <
$info[
'aac'][
'header'][
'num_program_configs'];
$i++) {
150 if (!$info[
'aac'][
'header'][
'is_vbr']) {
151 $info[
'aac'][
'program_configs'][
$i][
'buffer_fullness'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 20));
154 $info[
'aac'][
'program_configs'][
$i][
'element_instance_tag'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
156 $info[
'aac'][
'program_configs'][
$i][
'object_type'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
158 $info[
'aac'][
'program_configs'][
$i][
'sampling_frequency_index'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
160 $info[
'aac'][
'program_configs'][
$i][
'num_front_channel_elements'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
162 $info[
'aac'][
'program_configs'][
$i][
'num_side_channel_elements'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
164 $info[
'aac'][
'program_configs'][
$i][
'num_back_channel_elements'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
166 $info[
'aac'][
'program_configs'][
$i][
'num_lfe_channel_elements'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
168 $info[
'aac'][
'program_configs'][
$i][
'num_assoc_data_elements'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3));
170 $info[
'aac'][
'program_configs'][
$i][
'num_valid_cc_elements'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
172 $info[
'aac'][
'program_configs'][
$i][
'mono_mixdown_present'] = (bool)
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
174 if ($info[
'aac'][
'program_configs'][
$i][
'mono_mixdown_present']) {
175 $info[
'aac'][
'program_configs'][
$i][
'mono_mixdown_element_number'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
178 $info[
'aac'][
'program_configs'][
$i][
'stereo_mixdown_present'] = (bool)
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
180 if ($info[
'aac'][
'program_configs'][$i][
'stereo_mixdown_present']) {
181 $info[
'aac'][
'program_configs'][
$i][
'stereo_mixdown_element_number'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
184 $info[
'aac'][
'program_configs'][
$i][
'matrix_mixdown_idx_present'] = (bool)
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
186 if ($info[
'aac'][
'program_configs'][$i][
'matrix_mixdown_idx_present']) {
187 $info[
'aac'][
'program_configs'][
$i][
'matrix_mixdown_idx'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
189 $info[
'aac'][
'program_configs'][
$i][
'pseudo_surround_enable'] = (bool)
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
192 for ($j = 0; $j < $info[
'aac'][
'program_configs'][
$i][
'num_front_channel_elements']; $j++) {
193 $info[
'aac'][
'program_configs'][
$i][
'front_element_is_cpe'][$j] = (bool)
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
195 $info[
'aac'][
'program_configs'][
$i][
'front_element_tag_select'][$j] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
198 for ($j = 0; $j < $info[
'aac'][
'program_configs'][
$i][
'num_side_channel_elements']; $j++) {
199 $info[
'aac'][
'program_configs'][
$i][
'side_element_is_cpe'][$j] = (bool)
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
201 $info[
'aac'][
'program_configs'][
$i][
'side_element_tag_select'][$j] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
204 for ($j = 0; $j < $info[
'aac'][
'program_configs'][
$i][
'num_back_channel_elements']; $j++) {
205 $info[
'aac'][
'program_configs'][
$i][
'back_element_is_cpe'][$j] = (bool)
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
207 $info[
'aac'][
'program_configs'][
$i][
'back_element_tag_select'][$j] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
210 for ($j = 0; $j < $info[
'aac'][
'program_configs'][
$i][
'num_lfe_channel_elements']; $j++) {
211 $info[
'aac'][
'program_configs'][
$i][
'lfe_element_tag_select'][$j] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
214 for ($j = 0; $j < $info[
'aac'][
'program_configs'][
$i][
'num_assoc_data_elements']; $j++) {
215 $info[
'aac'][
'program_configs'][
$i][
'assoc_data_element_tag_select'][$j] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
218 for ($j = 0; $j < $info[
'aac'][
'program_configs'][
$i][
'num_valid_cc_elements']; $j++) {
219 $info[
'aac'][
'program_configs'][
$i][
'cc_element_is_ind_sw'][$j] = (bool)
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
221 $info[
'aac'][
'program_configs'][
$i][
'valid_cc_element_tag_select'][$j] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
225 $bitoffset = ceil($bitoffset / 8) * 8;
227 $info[
'aac'][
'program_configs'][
$i][
'comment_field_bytes'] =
getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 8));
229 $info[
'aac'][
'program_configs'][
$i][
'comment_field'] =
getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 8 * $info[
'aac'][
'program_configs'][$i][
'comment_field_bytes']));
230 $bitoffset += 8 * $info[
'aac'][
'program_configs'][
$i][
'comment_field_bytes'];
233 $info[
'aac'][
'header'][
'profile'] = self::AACprofileLookup($info[
'aac'][
'program_configs'][$i][
'object_type'], $info[
'aac'][
'header'][
'mpeg_version']);
234 $info[
'aac'][
'program_configs'][
$i][
'sampling_frequency'] = self::AACsampleRateLookup($info[
'aac'][
'program_configs'][$i][
'sampling_frequency_index']);
235 $info[
'audio'][
'sample_rate'] = $info[
'aac'][
'program_configs'][
$i][
'sampling_frequency'];
236 $info[
'audio'][
'channels'] = self::AACchannelCountCalculate($info[
'aac'][
'program_configs'][$i]);
237 if ($info[
'aac'][
'program_configs'][$i][
'comment_field']) {
238 $info[
'aac'][
'comments'][] = $info[
'aac'][
'program_configs'][
$i][
'comment_field'];
241 $info[
'playtime_seconds'] = (($info[
'avdataend'] - $info[
'avdataoffset']) * 8) / $info[
'audio'][
'bitrate'];
243 $info[
'audio'][
'encoder_options'] = $info[
'aac'][
'header_type'].
' '.$info[
'aac'][
'header'][
'profile'];
251 unset(
$info[
'fileformat']);
253 $this->
error(
'AAC-ADIF synch not found at offset '.
$info[
'avdataoffset'].
' (expected "ADIF", found "'.substr($AACheader, 0, 4).
'" instead)');
262 $info = &$this->getid3->info;
294 $byteoffset =
$info[
'avdataoffset'];
298 static $decbin = array();
301 for (
$i = 0;
$i < 256;
$i++) {
302 $decbin[chr(
$i)] = str_pad(decbin(
$i), 8,
'0', STR_PAD_LEFT);
306 $BitrateCache = array();
314 $this->
warning(
'Unable to parse AAC file beyond '.$this->
ftell().
' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).
'GB)');
317 $this->
fseek($byteoffset);
320 $substring = $this->
fread(9);
321 $substringlength = strlen($substring);
322 if ($substringlength != 9) {
323 $this->
error(
'Failed to read 7 bytes at offset '.($this->
ftell() - $substringlength).
' (only read '.$substringlength.
' bytes)');
331 $info[
'aac'][
'header'][
'raw'][
'syncword'] = ($header1 & 0xFFF0) >> 4;
332 if (
$info[
'aac'][
'header'][
'raw'][
'syncword'] != 0x0FFF) {
333 $this->
error(
'Synch pattern (0x0FFF) not found at offset '.($this->
ftell() - $substringlength).
' (found 0x0'.strtoupper(dechex(
$info[
'aac'][
'header'][
'raw'][
'syncword'])).
' instead)');
342 if ($framenumber == 0) {
343 $info[
'aac'][
'header_type'] =
'ADTS';
344 $info[
'fileformat'] =
'aac';
345 $info[
'audio'][
'dataformat'] =
'aac';
347 $info[
'aac'][
'header'][
'raw'][
'mpeg_version'] = ($header1 & 0x0008) >> 3;
348 $info[
'aac'][
'header'][
'raw'][
'mpeg_layer'] = ($header1 & 0x0006) >> 1;
349 $info[
'aac'][
'header'][
'raw'][
'protection_absent'] = ($header1 & 0x0001) >> 0;
351 $info[
'aac'][
'header'][
'raw'][
'profile_code'] = ($header2 & 0xC0000000) >> 30;
352 $info[
'aac'][
'header'][
'raw'][
'sample_rate_code'] = ($header2 & 0x3C000000) >> 26;
353 $info[
'aac'][
'header'][
'raw'][
'private_stream'] = ($header2 & 0x02000000) >> 25;
354 $info[
'aac'][
'header'][
'raw'][
'channels_code'] = ($header2 & 0x01C00000) >> 22;
355 $info[
'aac'][
'header'][
'raw'][
'original'] = ($header2 & 0x00200000) >> 21;
356 $info[
'aac'][
'header'][
'raw'][
'home'] = ($header2 & 0x00100000) >> 20;
357 $info[
'aac'][
'header'][
'raw'][
'copyright_stream'] = ($header2 & 0x00080000) >> 19;
358 $info[
'aac'][
'header'][
'raw'][
'copyright_start'] = ($header2 & 0x00040000) >> 18;
359 $info[
'aac'][
'header'][
'raw'][
'frame_length'] = ($header2 & 0x0003FFE0) >> 5;
361 $info[
'aac'][
'header'][
'mpeg_version'] = (
$info[
'aac'][
'header'][
'raw'][
'mpeg_version'] ? 2 : 4);
362 $info[
'aac'][
'header'][
'crc_present'] = (
$info[
'aac'][
'header'][
'raw'][
'protection_absent'] ?
false:
true);
363 $info[
'aac'][
'header'][
'profile'] = self::AACprofileLookup(
$info[
'aac'][
'header'][
'raw'][
'profile_code'],
$info[
'aac'][
'header'][
'mpeg_version']);
364 $info[
'aac'][
'header'][
'sample_frequency'] = self::AACsampleRateLookup(
$info[
'aac'][
'header'][
'raw'][
'sample_rate_code']);
365 $info[
'aac'][
'header'][
'private'] = (bool)
$info[
'aac'][
'header'][
'raw'][
'private_stream'];
366 $info[
'aac'][
'header'][
'original'] = (bool)
$info[
'aac'][
'header'][
'raw'][
'original'];
367 $info[
'aac'][
'header'][
'home'] = (bool)
$info[
'aac'][
'header'][
'raw'][
'home'];
368 $info[
'aac'][
'header'][
'channels'] = ((
$info[
'aac'][
'header'][
'raw'][
'channels_code'] == 7) ? 8 :
$info[
'aac'][
'header'][
'raw'][
'channels_code']);
369 if ($ReturnExtendedInfo) {
370 $info[
'aac'][$framenumber][
'copyright_id_bit'] = (bool)
$info[
'aac'][
'header'][
'raw'][
'copyright_stream'];
371 $info[
'aac'][$framenumber][
'copyright_id_start'] = (bool)
$info[
'aac'][
'header'][
'raw'][
'copyright_start'];
374 if (
$info[
'aac'][
'header'][
'raw'][
'mpeg_layer'] != 0) {
375 $this->
warning(
'Layer error - expected "0", found "'.
$info[
'aac'][
'header'][
'raw'][
'mpeg_layer'].
'" instead');
377 if (
$info[
'aac'][
'header'][
'sample_frequency'] == 0) {
378 $this->
error(
'Corrupt AAC file: sample_frequency == zero');
382 $info[
'audio'][
'sample_rate'] =
$info[
'aac'][
'header'][
'sample_frequency'];
383 $info[
'audio'][
'channels'] =
$info[
'aac'][
'header'][
'channels'];
386 $FrameLength = ($header2 & 0x0003FFE0) >> 5;
388 if (!isset($BitrateCache[$FrameLength])) {
389 $BitrateCache[$FrameLength] = (
$info[
'aac'][
'header'][
'sample_frequency'] / 1024) * $FrameLength * 8;
393 $info[
'aac'][$framenumber][
'aac_frame_length'] = $FrameLength;
395 $info[
'aac'][$framenumber][
'adts_buffer_fullness'] = (($header2 & 0x0000001F) << 6) & (($header3 & 0xFC) >> 2);
396 if (
$info[
'aac'][$framenumber][
'adts_buffer_fullness'] == 0x07FF) {
397 $info[
'audio'][
'bitrate_mode'] =
'vbr';
399 $info[
'audio'][
'bitrate_mode'] =
'cbr';
401 $info[
'aac'][$framenumber][
'num_raw_data_blocks'] = (($header3 & 0x03) >> 0);
403 if (
$info[
'aac'][
'header'][
'crc_present']) {
407 if (!$ReturnExtendedInfo) {
408 unset(
$info[
'aac'][$framenumber]);
421 $byteoffset += $FrameLength;
422 if ((++$framenumber < $MaxFramesToScan) && (($byteoffset + 10) <
$info[
'avdataend'])) {
428 $info[
'aac'][
'frames'] = $framenumber;
429 $info[
'playtime_seconds'] = (
$info[
'avdataend'] / $byteoffset) * (($framenumber * 1024) /
$info[
'aac'][
'header'][
'sample_frequency']);
430 if (
$info[
'playtime_seconds'] == 0) {
431 $this->
error(
'Corrupt AAC file: playtime_seconds == zero');
434 $info[
'audio'][
'bitrate'] = ((
$info[
'avdataend'] -
$info[
'avdataoffset']) * 8) /
$info[
'playtime_seconds'];
435 ksort(
$info[
'aac'][
'bitrate_distribution']);
437 $info[
'audio'][
'encoder_options'] =
$info[
'aac'][
'header_type'].
' '.
$info[
'aac'][
'header'][
'profile'];
447 static $AACsampleRateLookup = array();
448 if (empty($AACsampleRateLookup)) {
449 $AACsampleRateLookup[0] = 96000;
450 $AACsampleRateLookup[1] = 88200;
451 $AACsampleRateLookup[2] = 64000;
452 $AACsampleRateLookup[3] = 48000;
453 $AACsampleRateLookup[4] = 44100;
454 $AACsampleRateLookup[5] = 32000;
455 $AACsampleRateLookup[6] = 24000;
456 $AACsampleRateLookup[7] = 22050;
457 $AACsampleRateLookup[8] = 16000;
458 $AACsampleRateLookup[9] = 12000;
459 $AACsampleRateLookup[10] = 11025;
460 $AACsampleRateLookup[11] = 8000;
461 $AACsampleRateLookup[12] = 0;
462 $AACsampleRateLookup[13] = 0;
463 $AACsampleRateLookup[14] = 0;
464 $AACsampleRateLookup[15] = 0;
466 return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] :
'invalid');
470 static $AACprofileLookup = array();
471 if (empty($AACprofileLookup)) {
472 $AACprofileLookup[2][0] =
'Main profile';
473 $AACprofileLookup[2][1] =
'Low Complexity profile (LC)';
474 $AACprofileLookup[2][2] =
'Scalable Sample Rate profile (SSR)';
475 $AACprofileLookup[2][3] =
'(reserved)';
476 $AACprofileLookup[4][0] =
'AAC_MAIN';
477 $AACprofileLookup[4][1] =
'AAC_LC';
478 $AACprofileLookup[4][2] =
'AAC_SSR';
479 $AACprofileLookup[4][3] =
'AAC_LTP';
481 return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] :
'invalid');
486 for (
$i = 0;
$i < $program_configs[
'num_front_channel_elements'];
$i++) {
488 if ($program_configs[
'front_element_is_cpe'][
$i]) {
493 for (
$i = 0;
$i < $program_configs[
'num_side_channel_elements'];
$i++) {
495 if ($program_configs[
'side_element_is_cpe'][
$i]) {
500 for (
$i = 0;
$i < $program_configs[
'num_back_channel_elements'];
$i++) {
502 if ($program_configs[
'back_element_is_cpe'][
$i]) {
507 for (
$i = 0;
$i < $program_configs[
'num_lfe_channel_elements'];
$i++) {
static safe_inc(&$variable, $increment=1)
static AACchannelCountCalculate($program_configs)
static AACprofileLookup($profileid, $mpegversion)
getAACADIFheaderFilepointer()
static intValueSupported($num)
static Bin2Dec($binstring, $signed=false)
static BigEndian2Bin($byteword)
getID3() by James Heinrich info@getid3.org //
getAACADTSheaderFilepointer($MaxFramesToScan=1000000, $ReturnExtendedInfo=false)
static Bin2String($binstring)
static AACsampleRateLookup($samplerateid)
fseek($bytes, $whence=SEEK_SET)
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)