Changeset 46112 for trunk/src/wp-includes/ID3/module.audio.mp3.php
- Timestamp:
- 09/14/2019 07:06:09 PM (6 years ago)
- File:
-
- 1 edited
-
trunk/src/wp-includes/ID3/module.audio.mp3.php (modified) (40 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/ID3/module.audio.mp3.php
r41196 r46112 1 1 <?php 2 2 3 ///////////////////////////////////////////////////////////////// 3 4 /// getID3() by James Heinrich <info@getid3.org> // 4 // available at http://getid3.sourceforge.net // 5 // or http://www.getid3.org // 6 // also https://github.com/JamesHeinrich/getID3 // 7 ///////////////////////////////////////////////////////////////// 8 // See readme.txt for more details // 5 // available at https://github.com/JamesHeinrich/getID3 // 6 // or https://www.getid3.org // 7 // or http://getid3.sourceforge.net // 8 // see readme.txt for more details // 9 9 ///////////////////////////////////////////////////////////////// 10 10 // // … … 25 25 class getid3_mp3 extends getid3_handler 26 26 { 27 28 public $allow_bruteforce = false; // forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, unrecommended, but may provide data from otherwise-unusuable files 29 27 /** 28 * Forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, 29 * unrecommended, but may provide data from otherwise-unusable files. 30 * 31 * @var bool 32 */ 33 public $allow_bruteforce = false; 34 35 /** 36 * @return bool 37 */ 30 38 public function Analyze() { 31 39 $info = &$this->getid3->info; … … 36 44 if ($this->allow_bruteforce) { 37 45 $this->error('Rescanning file in BruteForce mode'); 38 $this->getOnlyMPEGaudioInfoBruteForce( $this->getid3->fp, $info);46 $this->getOnlyMPEGaudioInfoBruteForce(); 39 47 } 40 48 } … … 153 161 // Calculate playtime 154 162 if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) { 155 $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate']; 163 // https://github.com/JamesHeinrich/getID3/issues/161 164 // VBR header frame contains ~0.026s of silent audio data, but is not actually part of the original encoding and should be ignored 165 $xingVBRheaderFrameLength = ((isset($info['mpeg']['audio']['VBR_frames']) && isset($info['mpeg']['audio']['framelength'])) ? $info['mpeg']['audio']['framelength'] : 0); 166 167 $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset'] - $xingVBRheaderFrameLength) * 8 / $info['audio']['bitrate']; 156 168 } 157 169 … … 161 173 } 162 174 163 175 /** 176 * @return string 177 */ 164 178 public function GuessEncoderOptions() { 165 179 // shortcuts 166 180 $info = &$this->getid3->info; 181 $thisfile_mpeg_audio = array(); 182 $thisfile_mpeg_audio_lame = array(); 167 183 if (!empty($info['mpeg']['audio'])) { 168 184 $thisfile_mpeg_audio = &$info['mpeg']['audio']; … … 179 195 $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality']; 180 196 181 } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) {197 } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && isset($thisfile_mpeg_audio_lame['preset_used_id']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) { 182 198 183 199 $encoder_options = $thisfile_mpeg_audio_lame['preset_used']; … … 405 421 } 406 422 407 423 /** 424 * @param int $offset 425 * @param array $info 426 * @param bool $recursivesearch 427 * @param bool $ScanAsCBR 428 * @param bool $FastMPEGheaderScan 429 * 430 * @return bool 431 */ 408 432 public function decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) { 409 433 static $MPEGaudioVersionLookup; … … 459 483 $thisfile_mpeg_audio = &$info['mpeg']['audio']; 460 484 461 462 485 if ($MPEGaudioHeaderValidCache[$head4_key]) { 463 486 $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray; … … 563 586 $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; 564 587 $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer'; 565 $info['audio']['codec'] = 'Fraunhofer';588 $info['audio']['codec'] = 'Fraunhofer'; 566 589 567 590 $SideInfoData = substr($headerstring, 4 + 2, 32); … … 656 679 } elseif (!empty($info['filesize'])) { 657 680 $used_filesize = $info['filesize']; 658 $used_filesize -= intval(@$info['id3v2']['headerlength']);681 $used_filesize -= (isset($info['id3v2']['headerlength']) ? intval($info['id3v2']['headerlength']) : 0); 659 682 $used_filesize -= (isset($info['id3v1']) ? 128 : 0); 660 683 $used_filesize -= (isset($info['tag_offset_end']) ? $info['tag_offset_end'] - $info['tag_offset_start'] : 0); … … 679 702 $LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100); 680 703 for ($i = 0; $i < 100; $i++) { 681 $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData {$i});704 $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData[$i]); 682 705 } 683 706 } … … 1084 1107 } 1085 1108 1109 /** 1110 * @param int $offset 1111 * @param int $nextframetestoffset 1112 * @param bool $ScanAsCBR 1113 * 1114 * @return bool 1115 */ 1086 1116 public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) { 1087 1117 $info = &$this->getid3->info; … … 1130 1160 } 1131 1161 1162 /** 1163 * @param int $offset 1164 * @param bool $deepscan 1165 * 1166 * @return int|false 1167 */ 1132 1168 public function FreeFormatFrameLength($offset, $deepscan=false) { 1133 1169 $info = &$this->getid3->info; … … 1138 1174 $SyncPattern1 = substr($MPEGaudioData, 0, 4); 1139 1175 // may be different pattern due to padding 1140 $SyncPattern2 = $SyncPattern1 {0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3};1176 $SyncPattern2 = $SyncPattern1[0].$SyncPattern1[1].chr(ord($SyncPattern1[2]) | 0x02).$SyncPattern1[3]; 1141 1177 if ($SyncPattern2 === $SyncPattern1) { 1142 $SyncPattern2 = $SyncPattern1 {0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) & 0xFD).$SyncPattern1{3};1178 $SyncPattern2 = $SyncPattern1[0].$SyncPattern1[1].chr(ord($SyncPattern1[2]) & 0xFD).$SyncPattern1[3]; 1143 1179 } 1144 1180 … … 1207 1243 } 1208 1244 1245 /** 1246 * @return bool 1247 */ 1209 1248 public function getOnlyMPEGaudioInfoBruteForce() { 1210 1249 $MPEGaudioHeaderDecodeCache = array(); … … 1242 1281 break; 1243 1282 } 1244 if ($head4 {0}!= "\xFF") {1283 if ($head4[0] != "\xFF") { 1245 1284 for ($i = 1; $i < 4; $i++) { 1246 if ($head4 {$i}== "\xFF") {1285 if ($head4[$i] == "\xFF") { 1247 1286 $this->fseek($i - 4, SEEK_CUR); 1248 1287 continue 2; … … 1276 1315 $this->fseek($MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR); 1277 1316 $next4 = $this->fread(4); 1278 if ($next4 {0}== "\xFF") {1317 if ($next4[0] == "\xFF") { 1279 1318 if (!isset($MPEGaudioHeaderDecodeCache[$next4])) { 1280 1319 $MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4); … … 1354 1393 } 1355 1394 1356 1395 /** 1396 * @param int $avdataoffset 1397 * @param bool $BitrateHistogram 1398 * 1399 * @return bool 1400 */ 1357 1401 public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) { 1358 1402 // looks for synch, decodes MPEG audio header … … 1364 1408 static $MPEGaudioBitrateLookup; 1365 1409 if (empty($MPEGaudioVersionLookup)) { 1366 $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); 1367 $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); 1368 $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); 1369 1410 $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); 1411 $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); 1412 $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); 1370 1413 } 1371 1414 … … 1417 1460 } 1418 1461 1419 if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected 1462 if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // synch detected 1463 $FirstFrameAVDataOffset = null; 1420 1464 if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) { 1421 1465 $FirstFrameThisfileInfo = $info; … … 1441 1485 break; 1442 1486 } 1443 if (isset($FirstFrameThisfileInfo ['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) {1487 if (isset($FirstFrameThisfileInfo) && isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) { 1444 1488 if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) { 1445 1489 // If there is garbage data between a valid VBR header frame and a sequence … … 1511 1555 $buffer_4k = $this->fread(4096); 1512 1556 for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) { 1513 if (($buffer_4k {$j} == "\xFF") && ($buffer_4k{($j + 1)}> "\xE0")) { // synch detected1557 if (($buffer_4k[$j] == "\xFF") && ($buffer_4k[($j + 1)] > "\xE0")) { // synch detected 1514 1558 if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) { 1515 1559 $calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength']; … … 1523 1567 } 1524 1568 $synchstartoffset = $scan_start_offset[$current_segment]; 1525 while ( $this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) {1569 while (($synchstartoffset < $info['avdataend']) && $this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) { 1526 1570 $FastMode = true; 1527 1571 $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']]; … … 1634 1678 } 1635 1679 1636 1680 /** 1681 * @return array 1682 */ 1637 1683 public static function MPEGaudioVersionArray() { 1638 1684 static $MPEGaudioVersion = array('2.5', false, '2', '1'); … … 1640 1686 } 1641 1687 1688 /** 1689 * @return array 1690 */ 1642 1691 public static function MPEGaudioLayerArray() { 1643 1692 static $MPEGaudioLayer = array(false, 3, 2, 1); … … 1645 1694 } 1646 1695 1696 /** 1697 * @return array 1698 */ 1647 1699 public static function MPEGaudioBitrateArray() { 1648 1700 static $MPEGaudioBitrate; … … 1664 1716 } 1665 1717 1718 /** 1719 * @return array 1720 */ 1666 1721 public static function MPEGaudioFrequencyArray() { 1667 1722 static $MPEGaudioFrequency; … … 1676 1731 } 1677 1732 1733 /** 1734 * @return array 1735 */ 1678 1736 public static function MPEGaudioChannelModeArray() { 1679 1737 static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono'); … … 1681 1739 } 1682 1740 1741 /** 1742 * @return array 1743 */ 1683 1744 public static function MPEGaudioModeExtensionArray() { 1684 1745 static $MPEGaudioModeExtension; … … 1693 1754 } 1694 1755 1756 /** 1757 * @return array 1758 */ 1695 1759 public static function MPEGaudioEmphasisArray() { 1696 1760 static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17'); … … 1698 1762 } 1699 1763 1764 /** 1765 * @param string $head4 1766 * @param bool $allowBitrate15 1767 * 1768 * @return bool 1769 */ 1700 1770 public static function MPEGaudioHeaderBytesValid($head4, $allowBitrate15=false) { 1701 1771 return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15); 1702 1772 } 1703 1773 1774 /** 1775 * @param array $rawarray 1776 * @param bool $echoerrors 1777 * @param bool $allowBitrate15 1778 * 1779 * @return bool 1780 */ 1704 1781 public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) { 1705 1782 if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) { … … 1774 1851 } 1775 1852 1853 /** 1854 * @param string $Header4Bytes 1855 * 1856 * @return array|false 1857 */ 1776 1858 public static function MPEGaudioHeaderDecode($Header4Bytes) { 1777 1859 // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM … … 1795 1877 1796 1878 $MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4; 1797 $MPEGrawHeader['version'] = (ord($Header4Bytes {1}) & 0x18) >> 3; // BB1798 $MPEGrawHeader['layer'] = (ord($Header4Bytes {1}) & 0x06) >> 1; // CC1799 $MPEGrawHeader['protection'] = (ord($Header4Bytes {1}) & 0x01); // D1800 $MPEGrawHeader['bitrate'] = (ord($Header4Bytes {2}) & 0xF0) >> 4; // EEEE1801 $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes {2}) & 0x0C) >> 2; // FF1802 $MPEGrawHeader['padding'] = (ord($Header4Bytes {2}) & 0x02) >> 1; // G1803 $MPEGrawHeader['private'] = (ord($Header4Bytes {2}) & 0x01); // H1804 $MPEGrawHeader['channelmode'] = (ord($Header4Bytes {3}) & 0xC0) >> 6; // II1805 $MPEGrawHeader['modeextension'] = (ord($Header4Bytes {3}) & 0x30) >> 4; // JJ1806 $MPEGrawHeader['copyright'] = (ord($Header4Bytes {3}) & 0x08) >> 3; // K1807 $MPEGrawHeader['original'] = (ord($Header4Bytes {3}) & 0x04) >> 2; // L1808 $MPEGrawHeader['emphasis'] = (ord($Header4Bytes {3}) & 0x03); // MM1879 $MPEGrawHeader['version'] = (ord($Header4Bytes[1]) & 0x18) >> 3; // BB 1880 $MPEGrawHeader['layer'] = (ord($Header4Bytes[1]) & 0x06) >> 1; // CC 1881 $MPEGrawHeader['protection'] = (ord($Header4Bytes[1]) & 0x01); // D 1882 $MPEGrawHeader['bitrate'] = (ord($Header4Bytes[2]) & 0xF0) >> 4; // EEEE 1883 $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes[2]) & 0x0C) >> 2; // FF 1884 $MPEGrawHeader['padding'] = (ord($Header4Bytes[2]) & 0x02) >> 1; // G 1885 $MPEGrawHeader['private'] = (ord($Header4Bytes[2]) & 0x01); // H 1886 $MPEGrawHeader['channelmode'] = (ord($Header4Bytes[3]) & 0xC0) >> 6; // II 1887 $MPEGrawHeader['modeextension'] = (ord($Header4Bytes[3]) & 0x30) >> 4; // JJ 1888 $MPEGrawHeader['copyright'] = (ord($Header4Bytes[3]) & 0x08) >> 3; // K 1889 $MPEGrawHeader['original'] = (ord($Header4Bytes[3]) & 0x04) >> 2; // L 1890 $MPEGrawHeader['emphasis'] = (ord($Header4Bytes[3]) & 0x03); // MM 1809 1891 1810 1892 return $MPEGrawHeader; 1811 1893 } 1812 1894 1895 /** 1896 * @param int|string $bitrate 1897 * @param string $version 1898 * @param string $layer 1899 * @param bool $padding 1900 * @param int $samplerate 1901 * 1902 * @return int|false 1903 */ 1813 1904 public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate) { 1814 1905 static $AudioFrameLengthCache = array(); … … 1872 1963 } 1873 1964 1965 /** 1966 * @param float|int $bit_rate 1967 * 1968 * @return int|float|string 1969 */ 1874 1970 public static function ClosestStandardMP3Bitrate($bit_rate) { 1875 1971 static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000); … … 1892 1988 } 1893 1989 1990 /** 1991 * @param string $version 1992 * @param string $channelmode 1993 * 1994 * @return int 1995 */ 1894 1996 public static function XingVBRidOffset($version, $channelmode) { 1895 1997 static $XingVBRidOffsetCache = array(); 1896 if (empty($XingVBRidOffset )) {1897 $XingVBRidOffset = array (1998 if (empty($XingVBRidOffsetCache)) { 1999 $XingVBRidOffsetCache = array ( 1898 2000 '1' => array ('mono' => 0x15, // 4 + 17 = 21 1899 2001 'stereo' => 0x24, // 4 + 32 = 36 … … 1915 2017 ); 1916 2018 } 1917 return $XingVBRidOffset[$version][$channelmode]; 1918 } 1919 2019 return $XingVBRidOffsetCache[$version][$channelmode]; 2020 } 2021 2022 /** 2023 * @param int $VBRmethodID 2024 * 2025 * @return string 2026 */ 1920 2027 public static function LAMEvbrMethodLookup($VBRmethodID) { 1921 2028 static $LAMEvbrMethodLookup = array( … … 1934 2041 } 1935 2042 2043 /** 2044 * @param int $StereoModeID 2045 * 2046 * @return string 2047 */ 1936 2048 public static function LAMEmiscStereoModeLookup($StereoModeID) { 1937 2049 static $LAMEmiscStereoModeLookup = array( … … 1948 2060 } 1949 2061 2062 /** 2063 * @param int $SourceSampleFrequencyID 2064 * 2065 * @return string 2066 */ 1950 2067 public static function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID) { 1951 2068 static $LAMEmiscSourceSampleFrequencyLookup = array( … … 1958 2075 } 1959 2076 2077 /** 2078 * @param int $SurroundInfoID 2079 * 2080 * @return string 2081 */ 1960 2082 public static function LAMEsurroundInfoLookup($SurroundInfoID) { 1961 2083 static $LAMEsurroundInfoLookup = array( … … 1968 2090 } 1969 2091 2092 /** 2093 * @param array $LAMEtag 2094 * 2095 * @return string 2096 */ 1970 2097 public static function LAMEpresetUsedLookup($LAMEtag) { 1971 2098
Note: See TracChangeset
for help on using the changeset viewer.