public function getAACADIFheaderFilepointer() { $info =& $this->getid3->info; $info['fileformat'] = 'aac'; $info['audio']['dataformat'] = 'aac'; $info['audio']['lossless'] = false; $this->fseek($info['avdataoffset']); $AACheader = $this->fread(1024); $offset = 0; if (substr($AACheader, 0, 4) == 'ADIF') { // http://faac.sourceforge.net/wiki/index.php?page=ADIF // http://libmpeg.org/mpeg4/doc/w2203tfs.pdf // adif_header() { // adif_id 32 // copyright_id_present 1 // if( copyright_id_present ) // copyright_id 72 // original_copy 1 // home 1 // bitstream_type 1 // bitrate 23 // num_program_config_elements 4 // for (i = 0; i < num_program_config_elements + 1; i++ ) { // if( bitstream_type == '0' ) // adif_buffer_fullness 20 // program_config_element() // } // } $AACheaderBitstream = Utils::BigEndian2Bin($AACheader); $bitoffset = 0; $info['aac']['header_type'] = 'ADIF'; $bitoffset += 32; $info['aac']['header']['mpeg_version'] = 4; $info['aac']['header']['copyright'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); $bitoffset += 1; if ($info['aac']['header']['copyright']) { $info['aac']['header']['copyright_id'] = Utils::Bin2String(substr($AACheaderBitstream, $bitoffset, 72)); $bitoffset += 72; } $info['aac']['header']['original_copy'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); $bitoffset += 1; $info['aac']['header']['home'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); $bitoffset += 1; $info['aac']['header']['is_vbr'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); $bitoffset += 1; if ($info['aac']['header']['is_vbr']) { $info['audio']['bitrate_mode'] = 'vbr'; $info['aac']['header']['bitrate_max'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23)); $bitoffset += 23; } else { $info['audio']['bitrate_mode'] = 'cbr'; $info['aac']['header']['bitrate'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23)); $bitoffset += 23; $info['audio']['bitrate'] = $info['aac']['header']['bitrate']; } if ($info['audio']['bitrate'] == 0) { $info['error'][] = 'Corrupt AAC file: bitrate_audio == zero'; return false; } $info['aac']['header']['num_program_configs'] = 1 + Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; for ($i = 0; $i < $info['aac']['header']['num_program_configs']; $i++) { // http://www.audiocoding.com/wiki/index.php?page=program_config_element // buffer_fullness 20 // element_instance_tag 4 // object_type 2 // sampling_frequency_index 4 // num_front_channel_elements 4 // num_side_channel_elements 4 // num_back_channel_elements 4 // num_lfe_channel_elements 2 // num_assoc_data_elements 3 // num_valid_cc_elements 4 // mono_mixdown_present 1 // mono_mixdown_element_number 4 if mono_mixdown_present == 1 // stereo_mixdown_present 1 // stereo_mixdown_element_number 4 if stereo_mixdown_present == 1 // matrix_mixdown_idx_present 1 // matrix_mixdown_idx 2 if matrix_mixdown_idx_present == 1 // pseudo_surround_enable 1 if matrix_mixdown_idx_present == 1 // for (i = 0; i < num_front_channel_elements; i++) { // front_element_is_cpe[i] 1 // front_element_tag_select[i] 4 // } // for (i = 0; i < num_side_channel_elements; i++) { // side_element_is_cpe[i] 1 // side_element_tag_select[i] 4 // } // for (i = 0; i < num_back_channel_elements; i++) { // back_element_is_cpe[i] 1 // back_element_tag_select[i] 4 // } // for (i = 0; i < num_lfe_channel_elements; i++) { // lfe_element_tag_select[i] 4 // } // for (i = 0; i < num_assoc_data_elements; i++) { // assoc_data_element_tag_select[i] 4 // } // for (i = 0; i < num_valid_cc_elements; i++) { // cc_element_is_ind_sw[i] 1 // valid_cc_element_tag_select[i] 4 // } // byte_alignment() VAR // comment_field_bytes 8 // for (i = 0; i < comment_field_bytes; i++) { // comment_field_data[i] 8 // } if (!$info['aac']['header']['is_vbr']) { $info['aac']['program_configs'][$i]['buffer_fullness'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 20)); $bitoffset += 20; } $info['aac']['program_configs'][$i]['element_instance_tag'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; $info['aac']['program_configs'][$i]['object_type'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); $bitoffset += 2; $info['aac']['program_configs'][$i]['sampling_frequency_index'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; $info['aac']['program_configs'][$i]['num_front_channel_elements'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; $info['aac']['program_configs'][$i]['num_side_channel_elements'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; $info['aac']['program_configs'][$i]['num_back_channel_elements'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; $info['aac']['program_configs'][$i]['num_lfe_channel_elements'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); $bitoffset += 2; $info['aac']['program_configs'][$i]['num_assoc_data_elements'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3)); $bitoffset += 3; $info['aac']['program_configs'][$i]['num_valid_cc_elements'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; $info['aac']['program_configs'][$i]['mono_mixdown_present'] = (bool) Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); $bitoffset += 1; if ($info['aac']['program_configs'][$i]['mono_mixdown_present']) { $info['aac']['program_configs'][$i]['mono_mixdown_element_number'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; } $info['aac']['program_configs'][$i]['stereo_mixdown_present'] = (bool) Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); $bitoffset += 1; if ($info['aac']['program_configs'][$i]['stereo_mixdown_present']) { $info['aac']['program_configs'][$i]['stereo_mixdown_element_number'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; } $info['aac']['program_configs'][$i]['matrix_mixdown_idx_present'] = (bool) Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); $bitoffset += 1; if ($info['aac']['program_configs'][$i]['matrix_mixdown_idx_present']) { $info['aac']['program_configs'][$i]['matrix_mixdown_idx'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); $bitoffset += 2; $info['aac']['program_configs'][$i]['pseudo_surround_enable'] = (bool) Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); $bitoffset += 1; } for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_front_channel_elements']; $j++) { $info['aac']['program_configs'][$i]['front_element_is_cpe'][$j] = (bool) Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); $bitoffset += 1; $info['aac']['program_configs'][$i]['front_element_tag_select'][$j] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; } for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_side_channel_elements']; $j++) { $info['aac']['program_configs'][$i]['side_element_is_cpe'][$j] = (bool) Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); $bitoffset += 1; $info['aac']['program_configs'][$i]['side_element_tag_select'][$j] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; } for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_back_channel_elements']; $j++) { $info['aac']['program_configs'][$i]['back_element_is_cpe'][$j] = (bool) Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); $bitoffset += 1; $info['aac']['program_configs'][$i]['back_element_tag_select'][$j] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; } for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_lfe_channel_elements']; $j++) { $info['aac']['program_configs'][$i]['lfe_element_tag_select'][$j] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; } for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_assoc_data_elements']; $j++) { $info['aac']['program_configs'][$i]['assoc_data_element_tag_select'][$j] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; } for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_valid_cc_elements']; $j++) { $info['aac']['program_configs'][$i]['cc_element_is_ind_sw'][$j] = (bool) Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); $bitoffset += 1; $info['aac']['program_configs'][$i]['valid_cc_element_tag_select'][$j] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); $bitoffset += 4; } $bitoffset = ceil($bitoffset / 8) * 8; $info['aac']['program_configs'][$i]['comment_field_bytes'] = Utils::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 8)); $bitoffset += 8; $info['aac']['program_configs'][$i]['comment_field'] = Utils::Bin2String(substr($AACheaderBitstream, $bitoffset, 8 * $info['aac']['program_configs'][$i]['comment_field_bytes'])); $bitoffset += 8 * $info['aac']['program_configs'][$i]['comment_field_bytes']; $info['aac']['header']['profile'] = self::AACprofileLookup($info['aac']['program_configs'][$i]['object_type'], $info['aac']['header']['mpeg_version']); $info['aac']['program_configs'][$i]['sampling_frequency'] = self::AACsampleRateLookup($info['aac']['program_configs'][$i]['sampling_frequency_index']); $info['audio']['sample_rate'] = $info['aac']['program_configs'][$i]['sampling_frequency']; $info['audio']['channels'] = self::AACchannelCountCalculate($info['aac']['program_configs'][$i]); if ($info['aac']['program_configs'][$i]['comment_field']) { $info['aac']['comments'][] = $info['aac']['program_configs'][$i]['comment_field']; } } $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate']; $info['audio']['encoder_options'] = $info['aac']['header_type'] . ' ' . $info['aac']['header']['profile']; return true; } else { unset($info['fileformat']); unset($info['aac']); $info['error'][] = 'AAC-ADIF synch not found at offset ' . $info['avdataoffset'] . ' (expected "ADIF", found "' . substr($AACheader, 0, 4) . '" instead)'; return false; } }
public function Analyze() { $info =& $this->getid3->info; ///AH $info['ac3']['raw']['bsi'] = array(); $thisfile_ac3 =& $info['ac3']; $thisfile_ac3_raw =& $thisfile_ac3['raw']; $thisfile_ac3_raw_bsi =& $thisfile_ac3_raw['bsi']; // http://www.atsc.org/standards/a_52a.pdf $info['fileformat'] = 'ac3'; // An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames // Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256 // new audio samples per channel. A synchronization information (SI) header at the beginning // of each frame contains information needed to acquire and maintain synchronization. A // bit stream information (BSI) header follows SI, and contains parameters describing the coded // audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the // end of each frame is an error check field that includes a CRC word for error detection. An // additional CRC word is located in the SI header, the use of which, by a decoder, is optional. // // syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC // syncinfo() { // syncword 16 // crc1 16 // fscod 2 // frmsizecod 6 // } /* end of syncinfo */ $this->fseek($info['avdataoffset']); $this->AC3header['syncinfo'] = $this->fread(5); if (strpos($this->AC3header['syncinfo'], self::syncword) === 0) { $thisfile_ac3_raw['synchinfo']['synchword'] = self::syncword; $offset = 2; } else { if (!$this->isDependencyFor('Matroska')) { unset($info['fileformat'], $info['ac3']); return $this->error('Expecting "' . Utils::PrintHexBytes(self::syncword) . '" at offset ' . $info['avdataoffset'] . ', found "' . Utils::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)) . '"'); } $offset = 0; $this->fseek(-2, SEEK_CUR); } $info['audio']['dataformat'] = 'ac3'; $info['audio']['bitrate_mode'] = 'cbr'; $info['audio']['lossless'] = false; $thisfile_ac3_raw['synchinfo']['crc1'] = Utils::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2)); $ac3_synchinfo_fscod_frmsizecod = Utils::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset + 2, 1)); $thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xc0) >> 6; $thisfile_ac3_raw['synchinfo']['frmsizecod'] = $ac3_synchinfo_fscod_frmsizecod & 0x3f; $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']); if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) { $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate']; } $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']); $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']); $info['audio']['bitrate'] = $thisfile_ac3['bitrate']; $this->AC3header['bsi'] = Utils::BigEndian2Bin($this->fread(15)); $ac3_bsi_offset = 0; $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); if ($thisfile_ac3_raw_bsi['bsid'] > 8) { // Decoders which can decode version 8 will thus be able to decode version numbers less than 8. // If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used. // Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8. $this->error('Bit stream identification is version ' . $thisfile_ac3_raw_bsi['bsid'] . ', but getID3() only understands up to version 8'); unset($info['ac3']); return false; } $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3); $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3); $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']); $ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']); foreach ($ac3_coding_mode as $key => $value) { $thisfile_ac3[$key] = $value; } switch ($thisfile_ac3_raw_bsi['acmod']) { case 0: case 1: $info['audio']['channelmode'] = 'mono'; break; case 3: case 4: $info['audio']['channelmode'] = 'stereo'; break; default: $info['audio']['channelmode'] = 'surround'; break; } $info['audio']['channels'] = $thisfile_ac3['num_channels']; if ($thisfile_ac3_raw_bsi['acmod'] & 0x1) { // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream. $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2); $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']); } if ($thisfile_ac3_raw_bsi['acmod'] & 0x4) { // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream. $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2); $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']); } if ($thisfile_ac3_raw_bsi['acmod'] == 0x2) { // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround. $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2); $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']); } $thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1); $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon']; if ($thisfile_ac3_raw_bsi['lfeon']) { //$info['audio']['channels']++; $info['audio']['channels'] .= '.1'; } $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']); // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5); $thisfile_ac3['dialogue_normalization'] = '-' . $thisfile_ac3_raw_bsi['dialnorm'] . 'dB'; $thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1); if ($thisfile_ac3_raw_bsi['compre_flag']) { $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8); $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']); } $thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1); if ($thisfile_ac3_raw_bsi['langcode_flag']) { $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8); } $thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1); if ($thisfile_ac3_raw_bsi['audprodie']) { $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5); $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2); $thisfile_ac3['mixing_level'] = 80 + $thisfile_ac3_raw_bsi['mixlevel'] . 'dB'; $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']); } if ($thisfile_ac3_raw_bsi['acmod'] == 0x0) { // If acmod is 0, then two completely independent program channels (dual mono) // are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case, // a number of additional items are present in BSI or audblk to fully describe Ch2. // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5); $thisfile_ac3['dialogue_normalization2'] = '-' . $thisfile_ac3_raw_bsi['dialnorm2'] . 'dB'; $thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1); if ($thisfile_ac3_raw_bsi['compre_flag2']) { $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8); $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']); } $thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1); if ($thisfile_ac3_raw_bsi['langcode_flag2']) { $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8); } $thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1); if ($thisfile_ac3_raw_bsi['audprodie2']) { $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5); $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2); $thisfile_ac3['mixing_level2'] = 80 + $thisfile_ac3_raw_bsi['mixlevel2'] . 'dB'; $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']); } } $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1); $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1); $thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1); if ($thisfile_ac3_raw_bsi['timecode1_flag']) { $thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14); } $thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1); if ($thisfile_ac3_raw_bsi['timecode2_flag']) { $thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14); } $thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1); if ($thisfile_ac3_raw_bsi['addbsi_flag']) { $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6); $this->AC3header['bsi'] .= Utils::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length'])); $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8); $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8; } return true; }