wp/wp-includes/ID3/module.audio.mp3.php
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
4:346c88efed21 5:5e2f62d02dcd
     1 <?php
     1 <?php
     2 /////////////////////////////////////////////////////////////////
     2 /////////////////////////////////////////////////////////////////
     3 /// getID3() by James Heinrich <info@getid3.org>               //
     3 /// getID3() by James Heinrich <info@getid3.org>               //
     4 //  available at http://getid3.sourceforge.net                 //
     4 //  available at http://getid3.sourceforge.net                 //
     5 //            or http://www.getid3.org                         //
     5 //            or http://www.getid3.org                         //
       
     6 //          also https://github.com/JamesHeinrich/getID3       //
     6 /////////////////////////////////////////////////////////////////
     7 /////////////////////////////////////////////////////////////////
     7 // See readme.txt for more details                             //
     8 // See readme.txt for more details                             //
     8 /////////////////////////////////////////////////////////////////
     9 /////////////////////////////////////////////////////////////////
     9 //                                                             //
    10 //                                                             //
    10 // module.audio.mp3.php                                        //
    11 // module.audio.mp3.php                                        //
    93 			// not sure what the actual last frame length will be, but will be less than or equal to 1441
    94 			// not sure what the actual last frame length will be, but will be less than or equal to 1441
    94 			$PossiblyLongerLAMEversion_FrameLength = 1441;
    95 			$PossiblyLongerLAMEversion_FrameLength = 1441;
    95 
    96 
    96 			// Not sure what version of LAME this is - look in padding of last frame for longer version string
    97 			// Not sure what version of LAME this is - look in padding of last frame for longer version string
    97 			$PossibleLAMEversionStringOffset = $info['avdataend'] - $PossiblyLongerLAMEversion_FrameLength;
    98 			$PossibleLAMEversionStringOffset = $info['avdataend'] - $PossiblyLongerLAMEversion_FrameLength;
    98 			fseek($this->getid3->fp, $PossibleLAMEversionStringOffset);
    99 			$this->fseek($PossibleLAMEversionStringOffset);
    99 			$PossiblyLongerLAMEversion_Data = fread($this->getid3->fp, $PossiblyLongerLAMEversion_FrameLength);
   100 			$PossiblyLongerLAMEversion_Data = $this->fread($PossiblyLongerLAMEversion_FrameLength);
   100 			switch (substr($CurrentDataLAMEversionString, -1)) {
   101 			switch (substr($CurrentDataLAMEversionString, -1)) {
   101 				case 'a':
   102 				case 'a':
   102 				case 'b':
   103 				case 'b':
   103 					// "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example
   104 					// "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example
   104 					// need to trim off "a" to match longer string
   105 					// need to trim off "a" to match longer string
   420 			$MPEGaudioChannelModeLookup   = self::MPEGaudioChannelModeArray();
   421 			$MPEGaudioChannelModeLookup   = self::MPEGaudioChannelModeArray();
   421 			$MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
   422 			$MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
   422 			$MPEGaudioEmphasisLookup      = self::MPEGaudioEmphasisArray();
   423 			$MPEGaudioEmphasisLookup      = self::MPEGaudioEmphasisArray();
   423 		}
   424 		}
   424 
   425 
   425 		if (fseek($this->getid3->fp, $offset, SEEK_SET) != 0) {
   426 		if ($this->fseek($offset) != 0) {
   426 			$info['error'][] = 'decodeMPEGaudioHeader() failed to seek to next offset at '.$offset;
   427 			$info['error'][] = 'decodeMPEGaudioHeader() failed to seek to next offset at '.$offset;
   427 			return false;
   428 			return false;
   428 		}
   429 		}
   429 		//$headerstring = fread($this->getid3->fp, 1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
   430 		//$headerstring = $this->fread(1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
   430 		$headerstring = fread($this->getid3->fp, 226); // LAME header at offset 36 + 190 bytes of Xing/LAME data
   431 		$headerstring = $this->fread(226); // LAME header at offset 36 + 190 bytes of Xing/LAME data
   431 
   432 
   432 		// MP3 audio frame structure:
   433 		// MP3 audio frame structure:
   433 		// $aa $aa $aa $aa [$bb $bb] $cc...
   434 		// $aa $aa $aa $aa [$bb $bb] $cc...
   434 		// where $aa..$aa is the four-byte mpeg-audio header (below)
   435 		// where $aa..$aa is the four-byte mpeg-audio header (below)
   435 		// $bb $bb is the optional 2-byte CRC
   436 		// $bb $bb is the optional 2-byte CRC
   888 
   889 
   889 		}
   890 		}
   890 
   891 
   891 		if (($ExpectedNumberOfAudioBytes > 0) && ($ExpectedNumberOfAudioBytes != ($info['avdataend'] - $info['avdataoffset']))) {
   892 		if (($ExpectedNumberOfAudioBytes > 0) && ($ExpectedNumberOfAudioBytes != ($info['avdataend'] - $info['avdataoffset']))) {
   892 			if ($ExpectedNumberOfAudioBytes > ($info['avdataend'] - $info['avdataoffset'])) {
   893 			if ($ExpectedNumberOfAudioBytes > ($info['avdataend'] - $info['avdataoffset'])) {
   893 				if (isset($info['fileformat']) && ($info['fileformat'] == 'riff')) {
   894 				if ($this->isDependencyFor('matroska') || $this->isDependencyFor('riff')) {
   894 					// ignore, audio data is broken into chunks so will always be data "missing"
   895 					// ignore, audio data is broken into chunks so will always be data "missing"
   895 				} elseif (($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) {
   896 				}
   896 					$info['warning'][] = 'Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)';
   897 				elseif (($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) {
   897 				} else {
   898 					$this->warning('Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)');
   898 					$info['warning'][] = 'Probable truncated file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)';
   899 				}
       
   900 				else {
       
   901 					$this->warning('Probable truncated file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)');
   899 				}
   902 				}
   900 			} else {
   903 			} else {
   901 				if ((($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes) == 1) {
   904 				if ((($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes) == 1) {
   902 				//	$prenullbytefileoffset = ftell($this->getid3->fp);
   905 				//	$prenullbytefileoffset = $this->ftell();
   903 				//	fseek($this->getid3->fp, $info['avdataend'], SEEK_SET);
   906 				//	$this->fseek($info['avdataend']);
   904 				//	$PossibleNullByte = fread($this->getid3->fp, 1);
   907 				//	$PossibleNullByte = $this->fread(1);
   905 				//	fseek($this->getid3->fp, $prenullbytefileoffset, SEEK_SET);
   908 				//	$this->fseek($prenullbytefileoffset);
   906 				//	if ($PossibleNullByte === "\x00") {
   909 				//	if ($PossibleNullByte === "\x00") {
   907 						$info['avdataend']--;
   910 						$info['avdataend']--;
   908 				//		$info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
   911 				//		$info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
   909 				//	} else {
   912 				//	} else {
   910 				//		$info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';
   913 				//		$info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';
  1116 	}
  1119 	}
  1117 
  1120 
  1118 	public function FreeFormatFrameLength($offset, $deepscan=false) {
  1121 	public function FreeFormatFrameLength($offset, $deepscan=false) {
  1119 		$info = &$this->getid3->info;
  1122 		$info = &$this->getid3->info;
  1120 
  1123 
  1121 		fseek($this->getid3->fp, $offset, SEEK_SET);
  1124 		$this->fseek($offset);
  1122 		$MPEGaudioData = fread($this->getid3->fp, 32768);
  1125 		$MPEGaudioData = $this->fread(32768);
  1123 
  1126 
  1124 		$SyncPattern1 = substr($MPEGaudioData, 0, 4);
  1127 		$SyncPattern1 = substr($MPEGaudioData, 0, 4);
  1125 		// may be different pattern due to padding
  1128 		// may be different pattern due to padding
  1126 		$SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3};
  1129 		$SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3};
  1127 		if ($SyncPattern2 === $SyncPattern1) {
  1130 		if ($SyncPattern2 === $SyncPattern1) {
  1164 		if ($deepscan) {
  1167 		if ($deepscan) {
  1165 
  1168 
  1166 			$ActualFrameLengthValues = array();
  1169 			$ActualFrameLengthValues = array();
  1167 			$nextoffset = $offset + $framelength;
  1170 			$nextoffset = $offset + $framelength;
  1168 			while ($nextoffset < ($info['avdataend'] - 6)) {
  1171 			while ($nextoffset < ($info['avdataend'] - 6)) {
  1169 				fseek($this->getid3->fp, $nextoffset - 1, SEEK_SET);
  1172 				$this->fseek($nextoffset - 1);
  1170 				$NextSyncPattern = fread($this->getid3->fp, 6);
  1173 				$NextSyncPattern = $this->fread(6);
  1171 				if ((substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2)) {
  1174 				if ((substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2)) {
  1172 					// good - found where expected
  1175 					// good - found where expected
  1173 					$ActualFrameLengthValues[] = $framelength;
  1176 					$ActualFrameLengthValues[] = $framelength;
  1174 				} elseif ((substr($NextSyncPattern, 0, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 0, strlen($SyncPattern2)) == $SyncPattern2)) {
  1177 				} elseif ((substr($NextSyncPattern, 0, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 0, strlen($SyncPattern2)) == $SyncPattern2)) {
  1175 					// ok - found one byte earlier than expected (last frame wasn't padded, first frame was)
  1178 					// ok - found one byte earlier than expected (last frame wasn't padded, first frame was)
  1213 		$Distribution['layer']        = array();
  1216 		$Distribution['layer']        = array();
  1214 		$Distribution['version']      = array();
  1217 		$Distribution['version']      = array();
  1215 		$Distribution['padding']      = array();
  1218 		$Distribution['padding']      = array();
  1216 
  1219 
  1217 		$info = &$this->getid3->info;
  1220 		$info = &$this->getid3->info;
  1218 		fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
  1221 		$this->fseek($info['avdataoffset']);
  1219 
  1222 
  1220 		$max_frames_scan = 5000;
  1223 		$max_frames_scan = 5000;
  1221 		$frames_scanned  = 0;
  1224 		$frames_scanned  = 0;
  1222 
  1225 
  1223 		$previousvalidframe = $info['avdataoffset'];
  1226 		$previousvalidframe = $info['avdataoffset'];
  1224 		while (ftell($this->getid3->fp) < $info['avdataend']) {
  1227 		while ($this->ftell() < $info['avdataend']) {
  1225 			set_time_limit(30);
  1228 			set_time_limit(30);
  1226 			$head4 = fread($this->getid3->fp, 4);
  1229 			$head4 = $this->fread(4);
  1227 			if (strlen($head4) < 4) {
  1230 			if (strlen($head4) < 4) {
  1228 				break;
  1231 				break;
  1229 			}
  1232 			}
  1230 			if ($head4{0} != "\xFF") {
  1233 			if ($head4{0} != "\xFF") {
  1231 				for ($i = 1; $i < 4; $i++) {
  1234 				for ($i = 1; $i < 4; $i++) {
  1232 					if ($head4{$i} == "\xFF") {
  1235 					if ($head4{$i} == "\xFF") {
  1233 						fseek($this->getid3->fp, $i - 4, SEEK_CUR);
  1236 						$this->fseek($i - 4, SEEK_CUR);
  1234 						continue 2;
  1237 						continue 2;
  1235 					}
  1238 					}
  1236 				}
  1239 				}
  1237 				continue;
  1240 				continue;
  1238 			}
  1241 			}
  1256 						$LongMPEGlayerLookup[$head4],
  1259 						$LongMPEGlayerLookup[$head4],
  1257 						$LongMPEGpaddingLookup[$head4],
  1260 						$LongMPEGpaddingLookup[$head4],
  1258 						$LongMPEGfrequencyLookup[$head4]);
  1261 						$LongMPEGfrequencyLookup[$head4]);
  1259 				}
  1262 				}
  1260 				if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
  1263 				if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
  1261 					$WhereWeWere = ftell($this->getid3->fp);
  1264 					$WhereWeWere = $this->ftell();
  1262 					fseek($this->getid3->fp, $MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR);
  1265 					$this->fseek($MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR);
  1263 					$next4 = fread($this->getid3->fp, 4);
  1266 					$next4 = $this->fread(4);
  1264 					if ($next4{0} == "\xFF") {
  1267 					if ($next4{0} == "\xFF") {
  1265 						if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
  1268 						if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
  1266 							$MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4);
  1269 							$MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4);
  1267 						}
  1270 						}
  1268 						if (!isset($MPEGaudioHeaderValidCache[$next4])) {
  1271 						if (!isset($MPEGaudioHeaderValidCache[$next4])) {
  1269 							$MPEGaudioHeaderValidCache[$next4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false);
  1272 							$MPEGaudioHeaderValidCache[$next4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false);
  1270 						}
  1273 						}
  1271 						if ($MPEGaudioHeaderValidCache[$next4]) {
  1274 						if ($MPEGaudioHeaderValidCache[$next4]) {
  1272 							fseek($this->getid3->fp, -4, SEEK_CUR);
  1275 							$this->fseek(-4, SEEK_CUR);
  1273 
  1276 
  1274 							getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]);
  1277 							getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]);
  1275 							getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]);
  1278 							getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]);
  1276 							getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]);
  1279 							getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]);
  1277 							getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]);
  1280 							getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]);
  1278 							getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
  1281 							getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
  1279 							if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
  1282 							if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
  1280 								$pct_data_scanned = (ftell($this->getid3->fp) - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
  1283 								$pct_data_scanned = ($this->ftell() - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
  1281 								$info['warning'][] = 'too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
  1284 								$info['warning'][] = 'too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
  1282 								foreach ($Distribution as $key1 => $value1) {
  1285 								foreach ($Distribution as $key1 => $value1) {
  1283 									foreach ($value1 as $key2 => $value2) {
  1286 									foreach ($value1 as $key2 => $value2) {
  1284 										$Distribution[$key1][$key2] = round($value2 / $pct_data_scanned);
  1287 										$Distribution[$key1][$key2] = round($value2 / $pct_data_scanned);
  1285 									}
  1288 									}
  1288 							}
  1291 							}
  1289 							continue;
  1292 							continue;
  1290 						}
  1293 						}
  1291 					}
  1294 					}
  1292 					unset($next4);
  1295 					unset($next4);
  1293 					fseek($this->getid3->fp, $WhereWeWere - 3, SEEK_SET);
  1296 					$this->fseek($WhereWeWere - 3);
  1294 				}
  1297 				}
  1295 
  1298 
  1296 			}
  1299 			}
  1297 		}
  1300 		}
  1298 		foreach ($Distribution as $key => $value) {
  1301 		foreach ($Distribution as $key => $value) {
  1353 		   $MPEGaudioLayerLookup   = self::MPEGaudioLayerArray();
  1356 		   $MPEGaudioLayerLookup   = self::MPEGaudioLayerArray();
  1354 		   $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
  1357 		   $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
  1355 
  1358 
  1356 		}
  1359 		}
  1357 
  1360 
  1358 		fseek($this->getid3->fp, $avdataoffset, SEEK_SET);
  1361 		$this->fseek($avdataoffset);
  1359 		$sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset);
  1362 		$sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset);
  1360 		if ($sync_seek_buffer_size <= 0) {
  1363 		if ($sync_seek_buffer_size <= 0) {
  1361 			$info['error'][] = 'Invalid $sync_seek_buffer_size at offset '.$avdataoffset;
  1364 			$info['error'][] = 'Invalid $sync_seek_buffer_size at offset '.$avdataoffset;
  1362 			return false;
  1365 			return false;
  1363 		}
  1366 		}
  1364 		$header = fread($this->getid3->fp, $sync_seek_buffer_size);
  1367 		$header = $this->fread($sync_seek_buffer_size);
  1365 		$sync_seek_buffer_size = strlen($header);
  1368 		$sync_seek_buffer_size = strlen($header);
  1366 		$SynchSeekOffset = 0;
  1369 		$SynchSeekOffset = 0;
  1367 		while ($SynchSeekOffset < $sync_seek_buffer_size) {
  1370 		while ($SynchSeekOffset < $sync_seek_buffer_size) {
  1368 			if ((($avdataoffset + $SynchSeekOffset)  < $info['avdataend']) && !feof($this->getid3->fp)) {
  1371 			if ((($avdataoffset + $SynchSeekOffset)  < $info['avdataend']) && !feof($this->getid3->fp)) {
  1369 
  1372 
  1471 							$info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 8000=>0, 16000=>0, 24000=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0);
  1474 							$info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 8000=>0, 16000=>0, 24000=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0);
  1472 						}
  1475 						}
  1473 
  1476 
  1474 						$dummy = array('error'=>$info['error'], 'warning'=>$info['warning'], 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
  1477 						$dummy = array('error'=>$info['error'], 'warning'=>$info['warning'], 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
  1475 						$synchstartoffset = $info['avdataoffset'];
  1478 						$synchstartoffset = $info['avdataoffset'];
  1476 						fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
  1479 						$this->fseek($info['avdataoffset']);
  1477 
  1480 
  1478 						// you can play with these numbers:
  1481 						// you can play with these numbers:
  1479 						$max_frames_scan  = 50000;
  1482 						$max_frames_scan  = 50000;
  1480 						$max_scan_segments = 10;
  1483 						$max_scan_segments = 10;
  1481 
  1484 
  1486 						$this_scan_segment = 0;
  1489 						$this_scan_segment = 0;
  1487 						$frames_scan_per_segment = ceil($max_frames_scan / $max_scan_segments);
  1490 						$frames_scan_per_segment = ceil($max_frames_scan / $max_scan_segments);
  1488 						$pct_data_scanned = 0;
  1491 						$pct_data_scanned = 0;
  1489 						for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
  1492 						for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
  1490 							$frames_scanned_this_segment = 0;
  1493 							$frames_scanned_this_segment = 0;
  1491 							if (ftell($this->getid3->fp) >= $info['avdataend']) {
  1494 							if ($this->ftell() >= $info['avdataend']) {
  1492 								break;
  1495 								break;
  1493 							}
  1496 							}
  1494 							$scan_start_offset[$current_segment] = max(ftell($this->getid3->fp), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments)));
  1497 							$scan_start_offset[$current_segment] = max($this->ftell(), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments)));
  1495 							if ($current_segment > 0) {
  1498 							if ($current_segment > 0) {
  1496 								fseek($this->getid3->fp, $scan_start_offset[$current_segment], SEEK_SET);
  1499 								$this->fseek($scan_start_offset[$current_segment]);
  1497 								$buffer_4k = fread($this->getid3->fp, 4096);
  1500 								$buffer_4k = $this->fread(4096);
  1498 								for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) {
  1501 								for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) {
  1499 									if (($buffer_4k{$j} == "\xFF") && ($buffer_4k{($j + 1)} > "\xE0")) { // synch detected
  1502 									if (($buffer_4k{$j} == "\xFF") && ($buffer_4k{($j + 1)} > "\xE0")) { // synch detected
  1500 										if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) {
  1503 										if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) {
  1501 											$calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength'];
  1504 											$calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength'];
  1502 											if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) {
  1505 											if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) {
  1521 									getid3_lib::safe_inc($info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]);
  1524 									getid3_lib::safe_inc($info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]);
  1522 									$synchstartoffset += $dummy['mpeg']['audio']['framelength'];
  1525 									$synchstartoffset += $dummy['mpeg']['audio']['framelength'];
  1523 								}
  1526 								}
  1524 								$frames_scanned++;
  1527 								$frames_scanned++;
  1525 								if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) {
  1528 								if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) {
  1526 									$this_pct_scanned = (ftell($this->getid3->fp) - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']);
  1529 									$this_pct_scanned = ($this->ftell() - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']);
  1527 									if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) {
  1530 									if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) {
  1528 										// file likely contains < $max_frames_scan, just scan as one segment
  1531 										// file likely contains < $max_frames_scan, just scan as one segment
  1529 										$max_scan_segments = 1;
  1532 										$max_scan_segments = 1;
  1530 										$frames_scan_per_segment = $max_frames_scan;
  1533 										$frames_scan_per_segment = $max_frames_scan;
  1531 									} else {
  1534 									} else {