wp/wp-includes/ID3/module.audio.mp3.php
changeset 19 3d72ae0968f4
parent 16 a86126ab1dd4
child 21 48c4eec2b7e6
equal deleted inserted replaced
18:be944660c56a 19:3d72ae0968f4
    16 
    16 
    17 if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
    17 if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
    18 	exit;
    18 	exit;
    19 }
    19 }
    20 
    20 
    21 // number of frames to scan to determine if MPEG-audio sequence is valid
       
    22 // Lower this number to 5-20 for faster scanning
       
    23 // Increase this number to 50+ for most accurate detection of valid VBR/CBR
       
    24 // mpeg-audio streams
       
    25 define('GETID3_MP3_VALID_CHECK_FRAMES', 35);
       
    26 
       
    27 
    21 
    28 class getid3_mp3 extends getid3_handler
    22 class getid3_mp3 extends getid3_handler
    29 {
    23 {
    30 	/**
    24 	/**
    31 	 * Forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow,
    25 	 * Forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow,
    34 	 * @var bool
    28 	 * @var bool
    35 	 */
    29 	 */
    36 	public $allow_bruteforce = false;
    30 	public $allow_bruteforce = false;
    37 
    31 
    38 	/**
    32 	/**
       
    33 	 * number of frames to scan to determine if MPEG-audio sequence is valid
       
    34 	 * Lower this number to 5-20 for faster scanning
       
    35 	 * Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams
       
    36 	 *
       
    37 	 * @var int
       
    38 	 */
       
    39 	public $mp3_valid_check_frames = 50;
       
    40 
       
    41 	/**
    39 	 * @return bool
    42 	 * @return bool
    40 	 */
    43 	 */
    41 	public function Analyze() {
    44 	public function Analyze() {
    42 		$info = &$this->getid3->info;
    45 		$info = &$this->getid3->info;
    43 
    46 
    53 
    56 
    54 		if (isset($info['mpeg']['audio']['bitrate_mode'])) {
    57 		if (isset($info['mpeg']['audio']['bitrate_mode'])) {
    55 			$info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
    58 			$info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
    56 		}
    59 		}
    57 
    60 
       
    61 		$CurrentDataLAMEversionString = null;
    58 		if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) {
    62 		if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) {
    59 
    63 
    60 			$synchoffsetwarning = 'Unknown data before synch ';
    64 			$synchoffsetwarning = 'Unknown data before synch ';
    61 			if (isset($info['id3v2']['headerlength'])) {
    65 			if (isset($info['id3v2']['headerlength'])) {
    62 				$synchoffsetwarning .= '(ID3v2 header ends at '.$info['id3v2']['headerlength'].', then '.($info['avdataoffset'] - $info['id3v2']['headerlength']).' bytes garbage, ';
    66 				$synchoffsetwarning .= '(ID3v2 header ends at '.$info['id3v2']['headerlength'].', then '.($info['avdataoffset'] - $info['id3v2']['headerlength']).' bytes garbage, ';
   119 			}
   123 			}
   120 			if (($PossiblyLongerLAMEversion_String = strstr($PossiblyLongerLAMEversion_Data, $CurrentDataLAMEversionString)) !== false) {
   124 			if (($PossiblyLongerLAMEversion_String = strstr($PossiblyLongerLAMEversion_Data, $CurrentDataLAMEversionString)) !== false) {
   121 				if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) {
   125 				if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) {
   122 					$PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3"  "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
   126 					$PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3"  "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
   123 					if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) {
   127 					if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) {
       
   128 						if (!empty($info['audio']['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version']) && ($info['audio']['encoder'] == $info['mpeg']['audio']['LAME']['short_version'])) {
       
   129 							if (preg_match('#^LAME[0-9\\.]+#', $PossiblyLongerLAMEversion_NewString, $matches)) {
       
   130 								// "LAME3.100" -> "LAME3.100.1", but avoid including "(alpha)" and similar
       
   131 								$info['mpeg']['audio']['LAME']['short_version'] = $matches[0];
       
   132 							}
       
   133 						}
   124 						$info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString;
   134 						$info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString;
   125 					}
   135 					}
   126 				}
   136 				}
   127 			}
   137 			}
   128 		}
   138 		}
   293 			$encoder_options = 'ABR'.$thisfile_mpeg_audio_lame['bitrate_abr'];
   303 			$encoder_options = 'ABR'.$thisfile_mpeg_audio_lame['bitrate_abr'];
   294 
   304 
   295 		} elseif (!empty($info['audio']['bitrate'])) {
   305 		} elseif (!empty($info['audio']['bitrate'])) {
   296 
   306 
   297 			if ($info['audio']['bitrate_mode'] == 'cbr') {
   307 			if ($info['audio']['bitrate_mode'] == 'cbr') {
   298 				$encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
   308 				$encoder_options = strtoupper($info['audio']['bitrate_mode']).round($info['audio']['bitrate'] / 1000);
   299 			} else {
   309 			} else {
   300 				$encoder_options = strtoupper($info['audio']['bitrate_mode']);
   310 				$encoder_options = strtoupper($info['audio']['bitrate_mode']);
   301 			}
   311 			}
   302 
   312 
   303 		}
   313 		}
   486 		$thisfile_mpeg_audio = &$info['mpeg']['audio'];
   496 		$thisfile_mpeg_audio = &$info['mpeg']['audio'];
   487 
   497 
   488 		if ($MPEGaudioHeaderValidCache[$head4_key]) {
   498 		if ($MPEGaudioHeaderValidCache[$head4_key]) {
   489 			$thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
   499 			$thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
   490 		} else {
   500 		} else {
   491 			$this->error('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset);
   501 			$this->warning('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset);
   492 			return false;
   502 			return false;
   493 		}
   503 		}
   494 
   504 
   495 		if (!$FastMPEGheaderScan) {
   505 		if (!$FastMPEGheaderScan) {
   496 			$thisfile_mpeg_audio['version']       = $MPEGaudioVersionLookup[$thisfile_mpeg_audio['raw']['version']];
   506 			$thisfile_mpeg_audio['version']       = $MPEGaudioVersionLookup[$thisfile_mpeg_audio['raw']['version']];
   720 					$thisfile_mpeg_audio_lame    = &$thisfile_mpeg_audio['LAME'];
   730 					$thisfile_mpeg_audio_lame    = &$thisfile_mpeg_audio['LAME'];
   721 
   731 
   722 
   732 
   723 					$thisfile_mpeg_audio_lame['long_version']  = substr($headerstring, $VBRidOffset + 120, 20);
   733 					$thisfile_mpeg_audio_lame['long_version']  = substr($headerstring, $VBRidOffset + 120, 20);
   724 					$thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
   734 					$thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
   725 					$thisfile_mpeg_audio_lame['numeric_version'] = str_replace('LAME', '', $thisfile_mpeg_audio_lame['short_version']);
   735 
   726 					if (preg_match('#^LAME([0-9\\.a-z]+)#', $thisfile_mpeg_audio_lame['long_version'], $matches)) {
   736 					//$thisfile_mpeg_audio_lame['numeric_version'] = str_replace('LAME', '', $thisfile_mpeg_audio_lame['short_version']);
       
   737 					$thisfile_mpeg_audio_lame['numeric_version'] = '';
       
   738 					if (preg_match('#^LAME([0-9\\.a-z]*)#', $thisfile_mpeg_audio_lame['long_version'], $matches)) {
   727 						$thisfile_mpeg_audio_lame['short_version']   = $matches[0];
   739 						$thisfile_mpeg_audio_lame['short_version']   = $matches[0];
   728 						$thisfile_mpeg_audio_lame['numeric_version'] = $matches[1];
   740 						$thisfile_mpeg_audio_lame['numeric_version'] = $matches[1];
   729 					}
   741 					}
   730 					foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) {
   742 					if (strlen($thisfile_mpeg_audio_lame['numeric_version']) > 0) {
   731 						$thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number);
   743 						foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) {
   732 					}
   744 							$thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number);
   733 
       
   734 					//if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
       
   735 					if ((($thisfile_mpeg_audio_lame['integer_version'][0] * 1000) + $thisfile_mpeg_audio_lame['integer_version'][1]) >= 3090) { // cannot use string version compare, may have "LAME3.90" or "LAME3.100" -- see https://github.com/JamesHeinrich/getID3/issues/207
       
   736 
       
   737 						// extra 11 chars are not part of version string when LAMEtag present
       
   738 						unset($thisfile_mpeg_audio_lame['long_version']);
       
   739 
       
   740 						// It the LAME tag was only introduced in LAME v3.90
       
   741 						// http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
       
   742 
       
   743 						// Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
       
   744 						// are assuming a 'Xing' identifier offset of 0x24, which is the case for
       
   745 						// MPEG-1 non-mono, but not for other combinations
       
   746 						$LAMEtagOffsetContant = $VBRidOffset - 0x24;
       
   747 
       
   748 						// shortcuts
       
   749 						$thisfile_mpeg_audio_lame['RGAD']    = array('track'=>array(), 'album'=>array());
       
   750 						$thisfile_mpeg_audio_lame_RGAD       = &$thisfile_mpeg_audio_lame['RGAD'];
       
   751 						$thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track'];
       
   752 						$thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album'];
       
   753 						$thisfile_mpeg_audio_lame['raw'] = array();
       
   754 						$thisfile_mpeg_audio_lame_raw    = &$thisfile_mpeg_audio_lame['raw'];
       
   755 
       
   756 						// byte $9B  VBR Quality
       
   757 						// This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
       
   758 						// Actually overwrites original Xing bytes
       
   759 						unset($thisfile_mpeg_audio['VBR_scale']);
       
   760 						$thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
       
   761 
       
   762 						// bytes $9C-$A4  Encoder short VersionString
       
   763 						$thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
       
   764 
       
   765 						// byte $A5  Info Tag revision + VBR method
       
   766 						$LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
       
   767 
       
   768 						$thisfile_mpeg_audio_lame['tag_revision']   = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
       
   769 						$thisfile_mpeg_audio_lame_raw['vbr_method'] =  $LAMEtagRevisionVBRmethod & 0x0F;
       
   770 						$thisfile_mpeg_audio_lame['vbr_method']     = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
       
   771 						$thisfile_mpeg_audio['bitrate_mode']        = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'
       
   772 
       
   773 						// byte $A6  Lowpass filter value
       
   774 						$thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
       
   775 
       
   776 						// bytes $A7-$AE  Replay Gain
       
   777 						// http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
       
   778 						// bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
       
   779 						if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
       
   780 							// LAME 3.94a16 and later - 9.23 fixed point
       
   781 							// ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
       
   782 							$thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608);
       
   783 						} else {
       
   784 							// LAME 3.94a15 and earlier - 32-bit floating point
       
   785 							// Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
       
   786 							$thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
       
   787 						}
   745 						}
   788 						if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
   746 						//if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
   789 							unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
   747 						if ((($thisfile_mpeg_audio_lame['integer_version'][0] * 1000) + $thisfile_mpeg_audio_lame['integer_version'][1]) >= 3090) { // cannot use string version compare, may have "LAME3.90" or "LAME3.100" -- see https://github.com/JamesHeinrich/getID3/issues/207
   790 						} else {
   748 
   791 							$thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
   749 							// extra 11 chars are not part of version string when LAMEtag present
       
   750 							unset($thisfile_mpeg_audio_lame['long_version']);
       
   751 
       
   752 							// It the LAME tag was only introduced in LAME v3.90
       
   753 							// http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
       
   754 
       
   755 							// Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
       
   756 							// are assuming a 'Xing' identifier offset of 0x24, which is the case for
       
   757 							// MPEG-1 non-mono, but not for other combinations
       
   758 							$LAMEtagOffsetContant = $VBRidOffset - 0x24;
       
   759 
       
   760 							// shortcuts
       
   761 							$thisfile_mpeg_audio_lame['RGAD']    = array('track'=>array(), 'album'=>array());
       
   762 							$thisfile_mpeg_audio_lame_RGAD       = &$thisfile_mpeg_audio_lame['RGAD'];
       
   763 							$thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track'];
       
   764 							$thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album'];
       
   765 							$thisfile_mpeg_audio_lame['raw'] = array();
       
   766 							$thisfile_mpeg_audio_lame_raw    = &$thisfile_mpeg_audio_lame['raw'];
       
   767 
       
   768 							// byte $9B  VBR Quality
       
   769 							// This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
       
   770 							// Actually overwrites original Xing bytes
       
   771 							unset($thisfile_mpeg_audio['VBR_scale']);
       
   772 							$thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
       
   773 
       
   774 							// bytes $9C-$A4  Encoder short VersionString
       
   775 							$thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
       
   776 
       
   777 							// byte $A5  Info Tag revision + VBR method
       
   778 							$LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
       
   779 
       
   780 							$thisfile_mpeg_audio_lame['tag_revision']   = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
       
   781 							$thisfile_mpeg_audio_lame_raw['vbr_method'] =  $LAMEtagRevisionVBRmethod & 0x0F;
       
   782 							$thisfile_mpeg_audio_lame['vbr_method']     = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
       
   783 							$thisfile_mpeg_audio['bitrate_mode']        = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'
       
   784 
       
   785 							// byte $A6  Lowpass filter value
       
   786 							$thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
       
   787 
       
   788 							// bytes $A7-$AE  Replay Gain
       
   789 							// http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
       
   790 							// bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
       
   791 							if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
       
   792 								// LAME 3.94a16 and later - 9.23 fixed point
       
   793 								// ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
       
   794 								$thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608);
       
   795 							} else {
       
   796 								// LAME 3.94a15 and earlier - 32-bit floating point
       
   797 								// Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
       
   798 								$thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
       
   799 							}
       
   800 							if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
       
   801 								unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
       
   802 							} else {
       
   803 								$thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
       
   804 							}
       
   805 
       
   806 							$thisfile_mpeg_audio_lame_raw['RGAD_track']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));
       
   807 							$thisfile_mpeg_audio_lame_raw['RGAD_album']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));
       
   808 
       
   809 
       
   810 							if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
       
   811 
       
   812 								$thisfile_mpeg_audio_lame_RGAD_track['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
       
   813 								$thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
       
   814 								$thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
       
   815 								$thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] =  $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
       
   816 								$thisfile_mpeg_audio_lame_RGAD_track['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']);
       
   817 								$thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']);
       
   818 								$thisfile_mpeg_audio_lame_RGAD_track['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);
       
   819 
       
   820 								if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
       
   821 									$info['replay_gain']['track']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
       
   822 								}
       
   823 								$info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator'];
       
   824 								$info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db'];
       
   825 							} else {
       
   826 								unset($thisfile_mpeg_audio_lame_RGAD['track']);
       
   827 							}
       
   828 							if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
       
   829 
       
   830 								$thisfile_mpeg_audio_lame_RGAD_album['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
       
   831 								$thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
       
   832 								$thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
       
   833 								$thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
       
   834 								$thisfile_mpeg_audio_lame_RGAD_album['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);
       
   835 								$thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);
       
   836 								$thisfile_mpeg_audio_lame_RGAD_album['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);
       
   837 
       
   838 								if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
       
   839 									$info['replay_gain']['album']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
       
   840 								}
       
   841 								$info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator'];
       
   842 								$info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db'];
       
   843 							} else {
       
   844 								unset($thisfile_mpeg_audio_lame_RGAD['album']);
       
   845 							}
       
   846 							if (empty($thisfile_mpeg_audio_lame_RGAD)) {
       
   847 								unset($thisfile_mpeg_audio_lame['RGAD']);
       
   848 							}
       
   849 
       
   850 
       
   851 							// byte $AF  Encoding flags + ATH Type
       
   852 							$EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1));
       
   853 							$thisfile_mpeg_audio_lame['encoding_flags']['nspsytune']   = (bool) ($EncodingFlagsATHtype & 0x10);
       
   854 							$thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
       
   855 							$thisfile_mpeg_audio_lame['encoding_flags']['nogap_next']  = (bool) ($EncodingFlagsATHtype & 0x40);
       
   856 							$thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']  = (bool) ($EncodingFlagsATHtype & 0x80);
       
   857 							$thisfile_mpeg_audio_lame['ath_type']                      =         $EncodingFlagsATHtype & 0x0F;
       
   858 
       
   859 							// byte $B0  if ABR {specified bitrate} else {minimal bitrate}
       
   860 							$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1));
       
   861 							if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)
       
   862 								$thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
       
   863 							} elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)
       
   864 								// ignore
       
   865 							} elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
       
   866 								$thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
       
   867 							}
       
   868 
       
   869 							// bytes $B1-$B3  Encoder delays
       
   870 							$EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3));
       
   871 							$thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12;
       
   872 							$thisfile_mpeg_audio_lame['end_padding']   =  $EncoderDelays & 0x000FFF;
       
   873 
       
   874 							// byte $B4  Misc
       
   875 							$MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1));
       
   876 							$thisfile_mpeg_audio_lame_raw['noise_shaping']       = ($MiscByte & 0x03);
       
   877 							$thisfile_mpeg_audio_lame_raw['stereo_mode']         = ($MiscByte & 0x1C) >> 2;
       
   878 							$thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
       
   879 							$thisfile_mpeg_audio_lame_raw['source_sample_freq']  = ($MiscByte & 0xC0) >> 6;
       
   880 							$thisfile_mpeg_audio_lame['noise_shaping']       = $thisfile_mpeg_audio_lame_raw['noise_shaping'];
       
   881 							$thisfile_mpeg_audio_lame['stereo_mode']         = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']);
       
   882 							$thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality'];
       
   883 							$thisfile_mpeg_audio_lame['source_sample_freq']  = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']);
       
   884 
       
   885 							// byte $B5  MP3 Gain
       
   886 							$thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true);
       
   887 							$thisfile_mpeg_audio_lame['mp3_gain_db']     = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain'];
       
   888 							$thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6));
       
   889 
       
   890 							// bytes $B6-$B7  Preset and surround info
       
   891 							$PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2));
       
   892 							// Reserved                                                    = ($PresetSurroundBytes & 0xC000);
       
   893 							$thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800);
       
   894 							$thisfile_mpeg_audio_lame['surround_info']     = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']);
       
   895 							$thisfile_mpeg_audio_lame['preset_used_id']    = ($PresetSurroundBytes & 0x07FF);
       
   896 							$thisfile_mpeg_audio_lame['preset_used']       = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
       
   897 							if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
       
   898 								$this->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org');
       
   899 							}
       
   900 							if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
       
   901 								// this may change if 3.90.4 ever comes out
       
   902 								$thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
       
   903 							}
       
   904 
       
   905 							// bytes $B8-$BB  MusicLength
       
   906 							$thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4));
       
   907 							$ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']);
       
   908 
       
   909 							// bytes $BC-$BD  MusicCRC
       
   910 							$thisfile_mpeg_audio_lame['music_crc']    = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
       
   911 
       
   912 							// bytes $BE-$BF  CRC-16 of Info Tag
       
   913 							$thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));
       
   914 
       
   915 
       
   916 							// LAME CBR
       
   917 							if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
       
   918 
       
   919 								$thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
       
   920 								$thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
       
   921 								$info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
       
   922 								//if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {
       
   923 								//	$thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];
       
   924 								//}
       
   925 
       
   926 							}
       
   927 
   792 						}
   928 						}
   793 
       
   794 						$thisfile_mpeg_audio_lame_raw['RGAD_track']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));
       
   795 						$thisfile_mpeg_audio_lame_raw['RGAD_album']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));
       
   796 
       
   797 
       
   798 						if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
       
   799 
       
   800 							$thisfile_mpeg_audio_lame_RGAD_track['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
       
   801 							$thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
       
   802 							$thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
       
   803 							$thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] =  $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
       
   804 							$thisfile_mpeg_audio_lame_RGAD_track['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']);
       
   805 							$thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']);
       
   806 							$thisfile_mpeg_audio_lame_RGAD_track['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);
       
   807 
       
   808 							if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
       
   809 								$info['replay_gain']['track']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
       
   810 							}
       
   811 							$info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator'];
       
   812 							$info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db'];
       
   813 						} else {
       
   814 							unset($thisfile_mpeg_audio_lame_RGAD['track']);
       
   815 						}
       
   816 						if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
       
   817 
       
   818 							$thisfile_mpeg_audio_lame_RGAD_album['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
       
   819 							$thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
       
   820 							$thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
       
   821 							$thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
       
   822 							$thisfile_mpeg_audio_lame_RGAD_album['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);
       
   823 							$thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);
       
   824 							$thisfile_mpeg_audio_lame_RGAD_album['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);
       
   825 
       
   826 							if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
       
   827 								$info['replay_gain']['album']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
       
   828 							}
       
   829 							$info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator'];
       
   830 							$info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db'];
       
   831 						} else {
       
   832 							unset($thisfile_mpeg_audio_lame_RGAD['album']);
       
   833 						}
       
   834 						if (empty($thisfile_mpeg_audio_lame_RGAD)) {
       
   835 							unset($thisfile_mpeg_audio_lame['RGAD']);
       
   836 						}
       
   837 
       
   838 
       
   839 						// byte $AF  Encoding flags + ATH Type
       
   840 						$EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1));
       
   841 						$thisfile_mpeg_audio_lame['encoding_flags']['nspsytune']   = (bool) ($EncodingFlagsATHtype & 0x10);
       
   842 						$thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
       
   843 						$thisfile_mpeg_audio_lame['encoding_flags']['nogap_next']  = (bool) ($EncodingFlagsATHtype & 0x40);
       
   844 						$thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']  = (bool) ($EncodingFlagsATHtype & 0x80);
       
   845 						$thisfile_mpeg_audio_lame['ath_type']                      =         $EncodingFlagsATHtype & 0x0F;
       
   846 
       
   847 						// byte $B0  if ABR {specified bitrate} else {minimal bitrate}
       
   848 						$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1));
       
   849 						if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)
       
   850 							$thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
       
   851 						} elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)
       
   852 							// ignore
       
   853 						} elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
       
   854 							$thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
       
   855 						}
       
   856 
       
   857 						// bytes $B1-$B3  Encoder delays
       
   858 						$EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3));
       
   859 						$thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12;
       
   860 						$thisfile_mpeg_audio_lame['end_padding']   =  $EncoderDelays & 0x000FFF;
       
   861 
       
   862 						// byte $B4  Misc
       
   863 						$MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1));
       
   864 						$thisfile_mpeg_audio_lame_raw['noise_shaping']       = ($MiscByte & 0x03);
       
   865 						$thisfile_mpeg_audio_lame_raw['stereo_mode']         = ($MiscByte & 0x1C) >> 2;
       
   866 						$thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
       
   867 						$thisfile_mpeg_audio_lame_raw['source_sample_freq']  = ($MiscByte & 0xC0) >> 6;
       
   868 						$thisfile_mpeg_audio_lame['noise_shaping']       = $thisfile_mpeg_audio_lame_raw['noise_shaping'];
       
   869 						$thisfile_mpeg_audio_lame['stereo_mode']         = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']);
       
   870 						$thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality'];
       
   871 						$thisfile_mpeg_audio_lame['source_sample_freq']  = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']);
       
   872 
       
   873 						// byte $B5  MP3 Gain
       
   874 						$thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true);
       
   875 						$thisfile_mpeg_audio_lame['mp3_gain_db']     = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain'];
       
   876 						$thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6));
       
   877 
       
   878 						// bytes $B6-$B7  Preset and surround info
       
   879 						$PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2));
       
   880 						// Reserved                                                    = ($PresetSurroundBytes & 0xC000);
       
   881 						$thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800);
       
   882 						$thisfile_mpeg_audio_lame['surround_info']     = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']);
       
   883 						$thisfile_mpeg_audio_lame['preset_used_id']    = ($PresetSurroundBytes & 0x07FF);
       
   884 						$thisfile_mpeg_audio_lame['preset_used']       = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
       
   885 						if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
       
   886 							$this->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org');
       
   887 						}
       
   888 						if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
       
   889 							// this may change if 3.90.4 ever comes out
       
   890 							$thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
       
   891 						}
       
   892 
       
   893 						// bytes $B8-$BB  MusicLength
       
   894 						$thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4));
       
   895 						$ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']);
       
   896 
       
   897 						// bytes $BC-$BD  MusicCRC
       
   898 						$thisfile_mpeg_audio_lame['music_crc']    = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
       
   899 
       
   900 						// bytes $BE-$BF  CRC-16 of Info Tag
       
   901 						$thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));
       
   902 
       
   903 
       
   904 						// LAME CBR
       
   905 						if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
       
   906 
       
   907 							$thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
       
   908 							$thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
       
   909 							$info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
       
   910 							//if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {
       
   911 							//	$thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];
       
   912 							//}
       
   913 
       
   914 						}
       
   915 
       
   916 					}
   929 					}
   917 				}
   930 				}
   918 
   931 
   919 			} else {
   932 			} else {
   920 
   933 
  1006 
  1019 
  1007 		if ($recursivesearch) {
  1020 		if ($recursivesearch) {
  1008 
  1021 
  1009 			if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
  1022 			if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
  1010 				return false;
  1023 				return false;
       
  1024 			}
       
  1025 			if (!empty($this->getid3->info['mp3_validity_check_bitrates']) && !empty($thisfile_mpeg_audio['bitrate_mode']) && ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') && !empty($thisfile_mpeg_audio['VBR_bitrate'])) {
       
  1026 				// https://github.com/JamesHeinrich/getID3/issues/287
       
  1027 				if (count(array_keys($this->getid3->info['mp3_validity_check_bitrates'])) == 1) {
       
  1028 					list($cbr_bitrate_in_short_scan) = array_keys($this->getid3->info['mp3_validity_check_bitrates']);
       
  1029 					$deviation_cbr_from_header_bitrate = abs($thisfile_mpeg_audio['VBR_bitrate'] - $cbr_bitrate_in_short_scan) / $cbr_bitrate_in_short_scan;
       
  1030 					if ($deviation_cbr_from_header_bitrate < 0.01) {
       
  1031 						// VBR header bitrate may differ slightly from true bitrate of frames, perhaps accounting for overhead of VBR header frame itself?
       
  1032 						// If measured CBR bitrate is within 1% of specified bitrate in VBR header then assume that file is truly CBR
       
  1033 						$thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
       
  1034 						//$this->warning('VBR header ignored, assuming CBR '.round($cbr_bitrate_in_short_scan / 1000).'kbps based on scan of '.$this->mp3_valid_check_frames.' frames');
       
  1035 					}
       
  1036 				}
       
  1037 			}
       
  1038 			if (isset($this->getid3->info['mp3_validity_check_bitrates'])) {
       
  1039 				unset($this->getid3->info['mp3_validity_check_bitrates']);
  1011 			}
  1040 			}
  1012 
  1041 
  1013 		}
  1042 		}
  1014 
  1043 
  1015 
  1044 
  1128 	public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) {
  1157 	public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) {
  1129 		$info = &$this->getid3->info;
  1158 		$info = &$this->getid3->info;
  1130 		$firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']);
  1159 		$firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']);
  1131 		$this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
  1160 		$this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
  1132 
  1161 
  1133 		for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) {
  1162 		$info['mp3_validity_check_bitrates'] = array();
  1134 			// check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch
  1163 		for ($i = 0; $i < $this->mp3_valid_check_frames; $i++) {
       
  1164 			// check next (default: 50) frames for validity, to make sure we haven't run across a false synch
  1135 			if (($nextframetestoffset + 4) >= $info['avdataend']) {
  1165 			if (($nextframetestoffset + 4) >= $info['avdataend']) {
  1136 				// end of file
  1166 				// end of file
  1137 				return true;
  1167 				return true;
  1138 			}
  1168 			}
  1139 
  1169 
  1140 			$nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
  1170 			$nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
  1141 			if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
  1171 			if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
       
  1172 				getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][$nextframetestarray['mpeg']['audio']['bitrate']]);
  1142 				if ($ScanAsCBR) {
  1173 				if ($ScanAsCBR) {
  1143 					// force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
  1174 					// force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
  1144 					if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) {
  1175 					if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) {
  1145 						return false;
  1176 						return false;
  1146 					}
  1177 					}
  1271 		$LongMPEGversionLookup        = array();
  1302 		$LongMPEGversionLookup        = array();
  1272 		$LongMPEGlayerLookup          = array();
  1303 		$LongMPEGlayerLookup          = array();
  1273 		$LongMPEGbitrateLookup        = array();
  1304 		$LongMPEGbitrateLookup        = array();
  1274 		$LongMPEGpaddingLookup        = array();
  1305 		$LongMPEGpaddingLookup        = array();
  1275 		$LongMPEGfrequencyLookup      = array();
  1306 		$LongMPEGfrequencyLookup      = array();
       
  1307 		$Distribution                 = array();
  1276 		$Distribution['bitrate']      = array();
  1308 		$Distribution['bitrate']      = array();
  1277 		$Distribution['frequency']    = array();
  1309 		$Distribution['frequency']    = array();
  1278 		$Distribution['layer']        = array();
  1310 		$Distribution['layer']        = array();
  1279 		$Distribution['version']      = array();
  1311 		$Distribution['version']      = array();
  1280 		$Distribution['padding']      = array();
  1312 		$Distribution['padding']      = array();
  1431 			return false;
  1463 			return false;
  1432 		}
  1464 		}
  1433 		$header = $this->fread($sync_seek_buffer_size);
  1465 		$header = $this->fread($sync_seek_buffer_size);
  1434 		$sync_seek_buffer_size = strlen($header);
  1466 		$sync_seek_buffer_size = strlen($header);
  1435 		$SynchSeekOffset = 0;
  1467 		$SynchSeekOffset = 0;
       
  1468 		$SyncSeekAttempts = 0;
       
  1469 		$SyncSeekAttemptsMax = 1000;
       
  1470 		$FirstFrameThisfileInfo = null;
  1436 		while ($SynchSeekOffset < $sync_seek_buffer_size) {
  1471 		while ($SynchSeekOffset < $sync_seek_buffer_size) {
  1437 			if ((($avdataoffset + $SynchSeekOffset)  < $info['avdataend']) && !feof($this->getid3->fp)) {
  1472 			if ((($avdataoffset + $SynchSeekOffset)  < $info['avdataend']) && !feof($this->getid3->fp)) {
  1438 
  1473 
  1439 				if ($SynchSeekOffset > $sync_seek_buffer_size) {
  1474 				if ($SynchSeekOffset > $sync_seek_buffer_size) {
  1440 					// if a synch's not found within the first 128k bytes, then give up
  1475 					// if a synch's not found within the first 128k bytes, then give up
  1469 			if (($SynchSeekOffset + 1) >= strlen($header)) {
  1504 			if (($SynchSeekOffset + 1) >= strlen($header)) {
  1470 				$this->error('Could not find valid MPEG synch before end of file');
  1505 				$this->error('Could not find valid MPEG synch before end of file');
  1471 				return false;
  1506 				return false;
  1472 			}
  1507 			}
  1473 
  1508 
  1474 			if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // synch detected
  1509 			if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // possible synch detected
       
  1510 				if (++$SyncSeekAttempts >= $SyncSeekAttemptsMax) {
       
  1511 					// https://github.com/JamesHeinrich/getID3/issues/286
       
  1512 					// corrupt files claiming to be MP3, with a large number of 0xFF bytes near the beginning, can cause this loop to take a very long time
       
  1513 					// should have escape condition to avoid spending too much time scanning a corrupt file
       
  1514 					// if a synch's not found within the first 128k bytes, then give up
       
  1515 					$this->error('Could not find valid MPEG audio synch after scanning '.$SyncSeekAttempts.' candidate offsets');
       
  1516 					if (isset($info['audio']['bitrate'])) {
       
  1517 						unset($info['audio']['bitrate']);
       
  1518 					}
       
  1519 					if (isset($info['mpeg']['audio'])) {
       
  1520 						unset($info['mpeg']['audio']);
       
  1521 					}
       
  1522 					if (empty($info['mpeg'])) {
       
  1523 						unset($info['mpeg']);
       
  1524 					}
       
  1525 					return false;
       
  1526 				}
  1475 				$FirstFrameAVDataOffset = null;
  1527 				$FirstFrameAVDataOffset = null;
  1476 				if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
  1528 				if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
  1477 					$FirstFrameThisfileInfo = $info;
  1529 					$FirstFrameThisfileInfo = $info;
  1478 					$FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
  1530 					$FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
  1479 					if (!$this->decodeMPEGaudioHeader($FirstFrameAVDataOffset, $FirstFrameThisfileInfo, false)) {
  1531 					if (!$this->decodeMPEGaudioHeader($FirstFrameAVDataOffset, $FirstFrameThisfileInfo, false)) {
  1509 							$GarbageOffsetStart = $FirstFrameAVDataOffset + $FirstFrameThisfileInfo['mpeg']['audio']['framelength'];
  1561 							$GarbageOffsetStart = $FirstFrameAVDataOffset + $FirstFrameThisfileInfo['mpeg']['audio']['framelength'];
  1510 							$GarbageOffsetEnd   = $avdataoffset + $SynchSeekOffset;
  1562 							$GarbageOffsetEnd   = $avdataoffset + $SynchSeekOffset;
  1511 							if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
  1563 							if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
  1512 								$info = $dummy;
  1564 								$info = $dummy;
  1513 								$info['avdataoffset'] = $GarbageOffsetEnd;
  1565 								$info['avdataoffset'] = $GarbageOffsetEnd;
  1514 								$this->warning('apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd);
  1566 								$this->warning('apparently-valid VBR header not used because could not find '.$this->mp3_valid_check_frames.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd);
  1515 							} else {
  1567 							} else {
  1516 								$this->warning('using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')');
  1568 								$this->warning('using data from VBR header even though could not find '.$this->mp3_valid_check_frames.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')');
  1517 							}
  1569 							}
  1518 						}
  1570 						}
  1519 					}
  1571 					}
  1520 					if (isset($info['mpeg']['audio']['bitrate_mode']) && ($info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($info['mpeg']['audio']['VBR_method'])) {
  1572 					if (isset($info['mpeg']['audio']['bitrate_mode']) && ($info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($info['mpeg']['audio']['VBR_method'])) {
  1521 						// VBR file with no VBR header
  1573 						// VBR file with no VBR header
  1556 						$this_scan_segment = 0;
  1608 						$this_scan_segment = 0;
  1557 						$frames_scan_per_segment = ceil($max_frames_scan / $max_scan_segments);
  1609 						$frames_scan_per_segment = ceil($max_frames_scan / $max_scan_segments);
  1558 						$pct_data_scanned = 0;
  1610 						$pct_data_scanned = 0;
  1559 						for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
  1611 						for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
  1560 							$frames_scanned_this_segment = 0;
  1612 							$frames_scanned_this_segment = 0;
       
  1613 							$scan_start_offset = array();
  1561 							if ($this->ftell() >= $info['avdataend']) {
  1614 							if ($this->ftell() >= $info['avdataend']) {
  1562 								break;
  1615 								break;
  1563 							}
  1616 							}
  1564 							$scan_start_offset[$current_segment] = max($this->ftell(), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments)));
  1617 							$scan_start_offset[$current_segment] = max($this->ftell(), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments)));
  1565 							if ($current_segment > 0) {
  1618 							if ($current_segment > 0) {
  1885 
  1938 
  1886 		if (strlen($Header4Bytes) != 4) {
  1939 		if (strlen($Header4Bytes) != 4) {
  1887 			return false;
  1940 			return false;
  1888 		}
  1941 		}
  1889 
  1942 
       
  1943 		$MPEGrawHeader = array();
  1890 		$MPEGrawHeader['synch']         = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
  1944 		$MPEGrawHeader['synch']         = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
  1891 		$MPEGrawHeader['version']       = (ord($Header4Bytes[1]) & 0x18) >> 3; //    BB
  1945 		$MPEGrawHeader['version']       = (ord($Header4Bytes[1]) & 0x18) >> 3; //    BB
  1892 		$MPEGrawHeader['layer']         = (ord($Header4Bytes[1]) & 0x06) >> 1; //      CC
  1946 		$MPEGrawHeader['layer']         = (ord($Header4Bytes[1]) & 0x06) >> 1; //      CC
  1893 		$MPEGrawHeader['protection']    = (ord($Header4Bytes[1]) & 0x01);      //        D
  1947 		$MPEGrawHeader['protection']    = (ord($Header4Bytes[1]) & 0x01);      //        D
  1894 		$MPEGrawHeader['bitrate']       = (ord($Header4Bytes[2]) & 0xF0) >> 4; // EEEE
  1948 		$MPEGrawHeader['bitrate']       = (ord($Header4Bytes[2]) & 0xF0) >> 4; // EEEE