Changeset 52254
- Timestamp:
- 11/26/2021 03:04:10 AM (3 years ago)
- Location:
- trunk/src
- Files:
-
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/includes/media.php
r52245 r52254 3559 3559 } 3560 3560 3561 $id3 = new getID3(); 3561 $id3 = new getID3(); 3562 // Required to get the `created_timestamp` value. 3563 $id3->options_audiovideo_quicktime_ReturnAtomData = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName 3564 3562 3565 $data = $id3->analyze( $file ); 3563 3566 … … 3670 3673 } 3671 3674 3672 $id3 = new getID3(); 3675 $id3 = new getID3(); 3676 // Required to get the `created_timestamp` value. 3677 $id3->options_audiovideo_quicktime_ReturnAtomData = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName 3678 3673 3679 $data = $id3->analyze( $file ); 3674 3680 -
trunk/src/wp-includes/ID3/getid3.lib.php
r51901 r52254 243 243 * ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic 244 244 * 245 * @link http ://www.psc.edu/general/software/packages/ieee/ieee.html245 * @link https://web.archive.org/web/20120325162206/http://www.psc.edu/general/software/packages/ieee/ieee.php 246 246 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html 247 247 * … … 295 295 if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) { 296 296 // Not a Number 297 $floatvalue = false;297 $floatvalue = NAN; 298 298 } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) { 299 299 if ($signbit == '1') { 300 $floatvalue = '-infinity';300 $floatvalue = -INF; 301 301 } else { 302 $floatvalue = '+infinity';302 $floatvalue = INF; 303 303 } 304 304 } elseif (($exponent == 0) && ($fraction == 0)) { … … 428 428 */ 429 429 public static function Dec2Bin($number) { 430 if (!is_numeric($number)) { 431 // https://github.com/JamesHeinrich/getID3/issues/299 432 trigger_error('TypeError: Dec2Bin(): Argument #1 ($number) must be numeric, '.gettype($number).' given', E_USER_WARNING); 433 return ''; 434 } 435 $bytes = array(); 430 436 while ($number >= 256) { 431 $bytes[] = ( ($number / 256) - (floor($number / 256))) * 256;437 $bytes[] = (int) (($number / 256) - (floor($number / 256))) * 256; 432 438 $number = floor($number / 256); 433 439 } 434 $bytes[] = $number;440 $bytes[] = (int) $number; 435 441 $binstring = ''; 436 for ($i = 0; $i < count($bytes); $i++) {437 $binstring = (($i == count($bytes) - 1) ? decbin($byte s[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;442 foreach ($bytes as $i => $byte) { 443 $binstring = (($i == count($bytes) - 1) ? decbin($byte) : str_pad(decbin($byte), 8, '0', STR_PAD_LEFT)).$binstring; 438 444 } 439 445 return $binstring; … … 666 672 // $foo['path']['to']['my'] = 'file.txt'; 667 673 $ArrayPath = ltrim($ArrayPath, $Separator); 674 $ReturnedArray = array(); 668 675 if (($pos = strpos($ArrayPath, $Separator)) !== false) { 669 676 $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value); … … 1539 1546 // Copy all entries from ['tags'] into common ['comments'] 1540 1547 if (!empty($ThisFileInfo['tags'])) { 1541 if (isset($ThisFileInfo['tags']['id3v1'])) { 1542 // bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings 1543 $ID3v1 = $ThisFileInfo['tags']['id3v1']; 1544 unset($ThisFileInfo['tags']['id3v1']); 1545 $ThisFileInfo['tags']['id3v1'] = $ID3v1; 1546 unset($ID3v1); 1548 1549 // Some tag types can only support limited character sets and may contain data in non-standard encoding (usually ID3v1) 1550 // and/or poorly-transliterated tag values that are also in tag formats that do support full-range character sets 1551 // To make the output more user-friendly, process the potentially-problematic tag formats last to enhance the chance that 1552 // the first entries in [comments] are the most correct and the "bad" ones (if any) come later. 1553 // https://github.com/JamesHeinrich/getID3/issues/338 1554 $processLastTagTypes = array('id3v1','riff'); 1555 foreach ($processLastTagTypes as $processLastTagType) { 1556 if (isset($ThisFileInfo['tags'][$processLastTagType])) { 1557 // bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings 1558 $temp = $ThisFileInfo['tags'][$processLastTagType]; 1559 unset($ThisFileInfo['tags'][$processLastTagType]); 1560 $ThisFileInfo['tags'][$processLastTagType] = $temp; 1561 unset($temp); 1562 } 1547 1563 } 1548 1564 foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) { … … 1563 1579 break 2; 1564 1580 } 1565 } 1566 if (function_exists('mb_convert_encoding')) { 1567 if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) { 1568 // value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1. 1569 // As an example, Foobar2000 will do this if you tag a file with Chinese or Arabic or Cyrillic or something that doesn't fit into ISO-8859-1 the ID3v1 will consist of mostly "?" characters, one per multibyte unrepresentable character 1570 break 2; 1581 1582 if (function_exists('mb_convert_encoding')) { 1583 if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) { 1584 // value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1. 1585 // As an example, Foobar2000 will do this if you tag a file with Chinese or Arabic or Cyrillic or something that doesn't fit into ISO-8859-1 the ID3v1 will consist of mostly "?" characters, one per multibyte unrepresentable character 1586 break 2; 1587 } 1571 1588 } 1572 1589 } … … 1574 1591 } elseif (!is_array($value)) { 1575 1592 1576 $newvaluelength = strlen(trim($value)); 1593 $newvaluelength = strlen(trim($value)); 1594 $newvaluelengthMB = mb_strlen(trim($value)); 1577 1595 foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { 1578 $oldvaluelength = strlen(trim($existingvalue)); 1596 $oldvaluelength = strlen(trim($existingvalue)); 1597 $oldvaluelengthMB = mb_strlen(trim($existingvalue)); 1598 if (($newvaluelengthMB == $oldvaluelengthMB) && ($existingvalue == getid3_lib::iconv_fallback('UTF-8', 'ASCII', $value))) { 1599 // https://github.com/JamesHeinrich/getID3/issues/338 1600 // check for tags containing extended characters that may have been forced into limited-character storage (e.g. UTF8 values into ASCII) 1601 // which will usually display unrepresentable characters as "?" 1602 $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value); 1603 break; 1604 } 1579 1605 if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) { 1580 1606 $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value); … … 1602 1628 1603 1629 // attempt to standardize spelling of returned keys 1604 $StandardizeFieldNames = array( 1605 'tracknumber' => 'track_number', 1606 'track' => 'track_number', 1607 ); 1608 foreach ($StandardizeFieldNames as $badkey => $goodkey) { 1609 if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) { 1610 $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey]; 1611 unset($ThisFileInfo['comments'][$badkey]); 1630 if (!empty($ThisFileInfo['comments'])) { 1631 $StandardizeFieldNames = array( 1632 'tracknumber' => 'track_number', 1633 'track' => 'track_number', 1634 ); 1635 foreach ($StandardizeFieldNames as $badkey => $goodkey) { 1636 if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) { 1637 $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey]; 1638 unset($ThisFileInfo['comments'][$badkey]); 1639 } 1612 1640 } 1613 1641 } … … 1735 1763 */ 1736 1764 public static function getFileSizeSyscall($path) { 1765 $commandline = null; 1737 1766 $filesize = false; 1738 1767 … … 1796 1825 * @return string 1797 1826 */ 1798 public static function mb_basename($path, $suffix = null) {1827 public static function mb_basename($path, $suffix = '') { 1799 1828 $splited = preg_split('#/#', rtrim($path, '/ ')); 1800 1829 return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1); -
trunk/src/wp-includes/ID3/getid3.php
r51901 r52254 17 17 if (!defined('GETID3_INCLUDEPATH')) { 18 18 define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR); 19 }20 // Workaround Bug #39923 (https://bugs.php.net/bug.php?id=39923)21 if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {22 define('IMG_JPG', IMAGETYPE_JPEG);23 19 } 24 20 if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE … … 58 54 $basedir .= DIRECTORY_SEPARATOR; 59 55 } 60 if ( preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) {56 if (strpos($temp_dir, $basedir) === 0) { 61 57 $found_valid_tempdir = true; 62 58 break; … … 215 211 public $option_fread_buffer_size = 32768; 216 212 213 214 215 // module-specific options 216 217 /** archive.rar 218 * if true use PHP RarArchive extension, if false (non-extension parsing not yet written in getID3) 219 * 220 * @var bool 221 */ 222 public $options_archive_rar_use_php_rar_extension = true; 223 224 /** archive.gzip 225 * Optional file list - disable for speed. 226 * Decode gzipped files, if possible, and parse recursively (.tar.gz for example). 227 * 228 * @var bool 229 */ 230 public $options_archive_gzip_parse_contents = false; 231 232 /** audio.midi 233 * if false only parse most basic information, much faster for some files but may be inaccurate 234 * 235 * @var bool 236 */ 237 public $options_audio_midi_scanwholefile = true; 238 239 /** audio.mp3 240 * Forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, 241 * unrecommended, but may provide data from otherwise-unusable files. 242 * 243 * @var bool 244 */ 245 public $options_audio_mp3_allow_bruteforce = false; 246 247 /** audio.mp3 248 * number of frames to scan to determine if MPEG-audio sequence is valid 249 * Lower this number to 5-20 for faster scanning 250 * Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams 251 * 252 * @var int 253 */ 254 public $options_audio_mp3_mp3_valid_check_frames = 50; 255 256 /** audio.wavpack 257 * Avoid scanning all frames (break after finding ID_RIFF_HEADER and ID_CONFIG_BLOCK, 258 * significantly faster for very large files but other data may be missed 259 * 260 * @var bool 261 */ 262 public $options_audio_wavpack_quick_parsing = false; 263 264 /** audio-video.flv 265 * Break out of the loop if too many frames have been scanned; only scan this 266 * many if meta frame does not contain useful duration. 267 * 268 * @var int 269 */ 270 public $options_audiovideo_flv_max_frames = 100000; 271 272 /** audio-video.matroska 273 * If true, do not return information about CLUSTER chunks, since there's a lot of them 274 * and they're not usually useful [default: TRUE]. 275 * 276 * @var bool 277 */ 278 public $options_audiovideo_matroska_hide_clusters = true; 279 280 /** audio-video.matroska 281 * True to parse the whole file, not only header [default: FALSE]. 282 * 283 * @var bool 284 */ 285 public $options_audiovideo_matroska_parse_whole_file = false; 286 287 /** audio-video.quicktime 288 * return all parsed data from all atoms if true, otherwise just returned parsed metadata 289 * 290 * @var bool 291 */ 292 public $options_audiovideo_quicktime_ReturnAtomData = false; 293 294 /** audio-video.quicktime 295 * return all parsed data from all atoms if true, otherwise just returned parsed metadata 296 * 297 * @var bool 298 */ 299 public $options_audiovideo_quicktime_ParseAllPossibleAtoms = false; 300 301 /** audio-video.swf 302 * return all parsed tags if true, otherwise do not return tags not parsed by getID3 303 * 304 * @var bool 305 */ 306 public $options_audiovideo_swf_ReturnAllTagData = false; 307 308 /** graphic.bmp 309 * return BMP palette 310 * 311 * @var bool 312 */ 313 public $options_graphic_bmp_ExtractPalette = false; 314 315 /** graphic.bmp 316 * return image data 317 * 318 * @var bool 319 */ 320 public $options_graphic_bmp_ExtractData = false; 321 322 /** graphic.png 323 * If data chunk is larger than this do not read it completely (getID3 only needs the first 324 * few dozen bytes for parsing). 325 * 326 * @var int 327 */ 328 public $options_graphic_png_max_data_bytes = 10000000; 329 330 /** misc.pdf 331 * return full details of PDF Cross-Reference Table (XREF) 332 * 333 * @var bool 334 */ 335 public $options_misc_pdf_returnXREF = false; 336 337 /** misc.torrent 338 * Assume all .torrent files are less than 1MB and just read entire thing into memory for easy processing. 339 * Override this value if you need to process files larger than 1MB 340 * 341 * @var int 342 */ 343 public $options_misc_torrent_max_torrent_filesize = 1048576; 344 345 346 217 347 // Public variables 218 348 … … 258 388 protected $startup_warning = ''; 259 389 260 const VERSION = '1.9.2 0-202006061653';390 const VERSION = '1.9.21-202109171300'; 261 391 const FREAD_BUFFER_SIZE = 32768; 262 392 … … 638 768 } 639 769 $class = new $class_name($this); 770 771 // set module-specific options 772 foreach (get_object_vars($this) as $getid3_object_vars_key => $getid3_object_vars_value) { 773 if (preg_match('#^options_([^_]+)_([^_]+)_(.+)$#i', $getid3_object_vars_key, $matches)) { 774 list($dummy, $GOVgroup, $GOVmodule, $GOVsetting) = $matches; 775 $GOVgroup = (($GOVgroup == 'audiovideo') ? 'audio-video' : $GOVgroup); // variable names can only contain 0-9a-z_ so standardize here 776 if (($GOVgroup == $determined_format['group']) && ($GOVmodule == $determined_format['module'])) { 777 $class->$GOVsetting = $getid3_object_vars_value; 778 } 779 } 780 } 781 640 782 $class->Analyze(); 641 783 unset($class); … … 1352 1494 'module' => 'msoffice', 1353 1495 'mime_type' => 'application/octet-stream', 1496 'fail_id3' => 'ERROR', 1497 'fail_ape' => 'ERROR', 1498 ), 1499 1500 // TORRENT - .torrent 1501 'torrent' => array( 1502 'pattern' => '^(d8\\:announce|d7\\:comment)', 1503 'group' => 'misc', 1504 'module' => 'torrent', 1505 'mime_type' => 'application/x-bittorrent', 1354 1506 'fail_id3' => 'ERROR', 1355 1507 'fail_ape' => 'ERROR', … … 1490 1642 $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed! 1491 1643 } 1492 if ( $value) {1644 if (isset($value) && $value !== "") { 1493 1645 if (!is_numeric($key)) { 1494 1646 $this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value; … … 2097 2249 break; 2098 2250 } 2099 return 0; 2100 } else { 2101 $pos = $bytes; 2102 if ($whence == SEEK_CUR) { 2103 $pos = $this->ftell() + $bytes; 2104 } elseif ($whence == SEEK_END) { 2105 $pos = $this->getid3->info['filesize'] + $bytes; 2106 } 2107 if (!getid3_lib::intValueSupported($pos)) { 2108 throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10); 2109 } 2110 } 2111 return fseek($this->getid3->fp, $bytes, $whence); 2251 return 0; // fseek returns 0 on success 2252 } 2253 2254 $pos = $bytes; 2255 if ($whence == SEEK_CUR) { 2256 $pos = $this->ftell() + $bytes; 2257 } elseif ($whence == SEEK_END) { 2258 $pos = $this->getid3->info['filesize'] + $bytes; 2259 } 2260 if (!getid3_lib::intValueSupported($pos)) { 2261 throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10); 2262 } 2263 2264 // https://github.com/JamesHeinrich/getID3/issues/327 2265 $result = fseek($this->getid3->fp, $bytes, $whence); 2266 if ($result !== 0) { // fseek returns 0 on success 2267 throw new getid3_exception('cannot fseek('.$pos.'). resource/stream does not appear to support seeking', 10); 2268 } 2269 return $result; 2112 2270 } 2113 2271 … … 2225 2383 */ 2226 2384 public function saveAttachment($name, $offset, $length, $image_mime=null) { 2385 $fp_dest = null; 2386 $dest = null; 2227 2387 try { 2228 2388 -
trunk/src/wp-includes/ID3/module.audio-video.asf.php
r51901 r52254 94 94 $thisfile_asf_streambitratepropertiesobject = array(); 95 95 $thisfile_asf_codeclistobject = array(); 96 $StreamPropertiesObjectData = array(); 96 97 97 98 for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) { … … 284 285 $offset += 2; 285 286 if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) { 286 $this->warning('header_extension_object.reserved_2 ('. getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"');287 $this->warning('header_extension_object.reserved_2 ('.$thisfile_asf_headerextensionobject['reserved_2'].') does not match expected value of "6"'); 287 288 //return false; 288 289 break; … … 536 537 $offset += 2; 537 538 if ($thisfile_asf_markerobject['reserved_2'] != 0) { 538 $this->warning('marker_object.reserved_2 ('. getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"');539 $this->warning('marker_object.reserved_2 ('.$thisfile_asf_markerobject['reserved_2'].') does not match expected value of "0"'); 539 540 break; 540 541 } … … 1194 1195 $offset += 2; 1195 1196 if ($thisfile_asf_dataobject['reserved'] != 0x0101) { 1196 $this->warning('data_object.reserved ( '.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"');1197 $this->warning('data_object.reserved (0x'.sprintf('%04X', $thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"'); 1197 1198 //return false; 1198 1199 break; -
trunk/src/wp-includes/ID3/module.audio-video.flv.php
r51901 r52254 162 162 163 163 $FLVvideoHeader = $this->fread(11); 164 $PictureSizeEnc = array(); 164 165 165 166 if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) { -
trunk/src/wp-includes/ID3/module.audio-video.matroska.php
r51901 r52254 225 225 * @var bool 226 226 */ 227 public static$hide_clusters = true;227 public $hide_clusters = true; 228 228 229 229 /** … … 232 232 * @var bool 233 233 */ 234 public static$parse_whole_file = false;234 public $parse_whole_file = false; 235 235 236 236 /* … … 587 587 588 588 while ($this->getEBMLelement($element_data, $top_element['end'])) { 589 if ($element_data['id'] != EBML_ID_CLUSTER || ! self::$hide_clusters) { // collect clusters only if required589 if ($element_data['id'] != EBML_ID_CLUSTER || !$this->hide_clusters) { // collect clusters only if required 590 590 $info['matroska']['segments'][] = $element_data; 591 591 } … … 619 619 break; 620 620 } 621 if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || ! self::$hide_clusters) { // collect clusters only if required621 if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !$this->hide_clusters) { // collect clusters only if required 622 622 $info['matroska']['seek'][] = $seek_entry; 623 623 } … … 906 906 907 907 case EBML_ID_CUES: // A top-level element to speed seeking access. All entries are local to the segment. Should be mandatory for non "live" streams. 908 if ( self::$hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway908 if ($this->hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway 909 909 $this->current_offset = $element_data['end']; 910 910 break; … … 1247 1247 $this->current_offset = $subelement['end']; 1248 1248 } 1249 if (! self::$hide_clusters) {1249 if (!$this->hide_clusters) { 1250 1250 $info['matroska']['cluster'][] = $cluster_entry; 1251 1251 } 1252 1252 1253 1253 // check to see if all the data we need exists already, if so, break out of the loop 1254 if (! self::$parse_whole_file) {1254 if (!$this->parse_whole_file) { 1255 1255 if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { 1256 1256 if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) { -
trunk/src/wp-includes/ID3/module.audio-video.quicktime.php
r51901 r52254 25 25 { 26 26 27 public $ReturnAtomData = true; 27 /** audio-video.quicktime 28 * return all parsed data from all atoms if true, otherwise just returned parsed metadata 29 * 30 * @var bool 31 */ 32 public $ReturnAtomData = false; 33 34 /** audio-video.quicktime 35 * return all parsed data from all atoms if true, otherwise just returned parsed metadata 36 * 37 * @var bool 38 */ 28 39 public $ParseAllPossibleAtoms = false; 29 40 … … 171 182 } 172 183 173 if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {184 if (!isset($info['bitrate']) && !empty($info['playtime_seconds'])) { 174 185 $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; 175 186 } … … 561 572 $atom_structure['data'] = substr($boxdata, 8); 562 573 if ($atomname == 'covr') { 563 // not a foolproof check, but better than nothing 564 if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) { 565 $atom_structure['image_mime'] = 'image/jpeg'; 566 } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) { 567 $atom_structure['image_mime'] = 'image/png'; 568 } elseif (preg_match('#^GIF#', $atom_structure['data'])) { 569 $atom_structure['image_mime'] = 'image/gif'; 574 if (!empty($atom_structure['data'])) { 575 $atom_structure['image_mime'] = 'image/unknown'; // provide default MIME type to ensure array keys exist 576 if (function_exists('getimagesizefromstring') && ($getimagesize = getimagesizefromstring($atom_structure['data'])) && !empty($getimagesize['mime'])) { 577 $atom_structure['image_mime'] = $getimagesize['mime']; 578 } else { 579 // if getimagesizefromstring is not available, or fails for some reason, fall back to simple detection of common image formats 580 $ImageFormatSignatures = array( 581 'image/jpeg' => "\xFF\xD8\xFF", 582 'image/png' => "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 583 'image/gif' => 'GIF', 584 ); 585 foreach ($ImageFormatSignatures as $mime => $image_format_signature) { 586 if (substr($atom_structure['data'], 0, strlen($image_format_signature)) == $image_format_signature) { 587 $atom_structure['image_mime'] = $mime; 588 break; 589 } 590 } 591 } 592 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover'); 593 } else { 594 $this->warning('Unknown empty "covr" image at offset '.$baseoffset); 570 595 } 571 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');572 596 } 573 597 break; … … 729 753 $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag']; 730 754 731 $ptv_lookup[0] = 'normal'; 732 $ptv_lookup[1] = 'double'; 733 $ptv_lookup[2] = 'half'; 734 $ptv_lookup[3] = 'full'; 735 $ptv_lookup[4] = 'current'; 755 $ptv_lookup = array( 756 0 => 'normal', 757 1 => 'double', 758 2 => 'half', 759 3 => 'full', 760 4 => 'current' 761 ); 736 762 if (isset($ptv_lookup[$atom_structure['display_size_raw']])) { 737 763 $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; … … 909 935 $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2)); 910 936 911 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (( $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');937 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (((int) $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color'); 912 938 $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']); 913 939 … … 915 941 $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; 916 942 $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); 917 $info['quicktime']['video']['codec'] = (( $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);943 $info['quicktime']['video']['codec'] = (((int) $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']); 918 944 $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth']; 919 945 $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name']; … … 1599 1625 1600 1626 case 'NCDT': 1601 // http ://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html1627 // https://exiftool.org/TagNames/Nikon.html 1602 1628 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 1603 1629 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms); … … 1605 1631 case 'NCTH': // Nikon Camera THumbnail image 1606 1632 case 'NCVW': // Nikon Camera preVieW image 1607 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1633 case 'NCM1': // Nikon Camera preview iMage 1 1634 case 'NCM2': // Nikon Camera preview iMage 2 1635 // https://exiftool.org/TagNames/Nikon.html 1608 1636 if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) { 1637 $descriptions = array( 1638 'NCTH' => 'Nikon Camera Thumbnail Image', 1639 'NCVW' => 'Nikon Camera Preview Image', 1640 'NCM1' => 'Nikon Camera Preview Image 1', 1641 'NCM2' => 'Nikon Camera Preview Image 2', 1642 ); 1609 1643 $atom_structure['data'] = $atom_data; 1610 1644 $atom_structure['image_mime'] = 'image/jpeg'; 1611 $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image')); 1612 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']); 1613 } 1614 break; 1615 case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG 1616 $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data); 1617 break; 1618 case 'NCHD': // Nikon:MakerNoteVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1619 case 'NCDB': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1620 case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html 1645 $atom_structure['description'] = isset($descriptions[$atomname]) ? $descriptions[$atomname] : 'Nikon preview image'; 1646 $info['quicktime']['comments']['picture'][] = array( 1647 'image_mime' => $atom_structure['image_mime'], 1648 'data' => $atom_data, 1649 'description' => $atom_structure['description'] 1650 ); 1651 } 1652 break; 1653 case 'NCTG': // Nikon - https://exiftool.org/TagNames/Nikon.html#NCTG 1654 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.nikon-nctg.php', __FILE__, true); 1655 $nikonNCTG = new getid3_tag_nikon_nctg($this->getid3); 1656 1657 $atom_structure['data'] = $nikonNCTG->parse($atom_data); 1658 break; 1659 case 'NCHD': // Nikon:MakerNoteVersion - https://exiftool.org/TagNames/Nikon.html 1660 $makerNoteVersion = ''; 1661 for ($i = 0, $iMax = strlen($atom_data); $i < $iMax; ++$i) { 1662 if (ord($atom_data[$i]) >= 0x00 && ord($atom_data[$i]) <= 0x1F) { 1663 $makerNoteVersion .= ' '.ord($atom_data[$i]); 1664 } else { 1665 $makerNoteVersion .= $atom_data[$i]; 1666 } 1667 } 1668 $makerNoteVersion = rtrim($makerNoteVersion, "\x00"); 1669 $atom_structure['data'] = array( 1670 'MakerNoteVersion' => $makerNoteVersion 1671 ); 1672 break; 1673 case 'NCDB': // Nikon - https://exiftool.org/TagNames/Nikon.html 1674 case 'CNCV': // Canon:CompressorVersion - https://exiftool.org/TagNames/Canon.html 1621 1675 $atom_structure['data'] = $atom_data; 1622 1676 break; … … 1625 1679 // some kind of metacontainer, may contain a big data dump such as: 1626 1680 // mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4 1627 // http ://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt1681 // https://xhelmboyx.tripod.com/formats/qti-layout.txt 1628 1682 1629 1683 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); … … 1722 1776 'debug_list' => '', // Used to debug variables stored as comma delimited strings 1723 1777 ); 1778 $debug_structure = array(); 1724 1779 $debug_structure['debug_items'] = array(); 1725 1780 // Can start loop here to decode all sensor data in 32 Byte chunks: … … 2040 2095 */ 2041 2096 public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { 2042 $atom_structure = false;2097 $atom_structure = array(); 2043 2098 $subatomoffset = 0; 2044 2099 $subatomcounter = 0; … … 2058 2113 continue; 2059 2114 } 2060 return $atom_structure;2115 break; 2061 2116 } 2062 2117 if (strlen($subatomdata) < ($subatomsize - 8)) { … … 2064 2119 // this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large 2065 2120 // so we passed in the start of a following atom incorrectly? 2066 return $atom_structure;2121 break; 2067 2122 } 2068 2123 $atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms); 2069 2124 $subatomoffset += $subatomsize; 2070 2125 } 2126 2127 if (empty($atom_structure)) { 2128 return false; 2129 } 2130 2071 2131 return $atom_structure; 2072 2132 } … … 2553 2613 if (empty($QuicktimeContentRatingLookup)) { 2554 2614 $QuicktimeContentRatingLookup[0] = 'None'; 2615 $QuicktimeContentRatingLookup[1] = 'Explicit'; 2555 2616 $QuicktimeContentRatingLookup[2] = 'Clean'; 2556 $QuicktimeContentRatingLookup[4] = 'Explicit ';2617 $QuicktimeContentRatingLookup[4] = 'Explicit (old)'; 2557 2618 } 2558 2619 return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid'); … … 2605 2666 } 2606 2667 return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid'); 2607 }2608 2609 /**2610 * @param string $atom_data2611 *2612 * @return array2613 */2614 public function QuicktimeParseNikonNCTG($atom_data) {2615 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG2616 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D51002617 // Data is stored as records of:2618 // * 4 bytes record type2619 // * 2 bytes size of data field type:2620 // 0x0001 = flag (size field *= 1-byte)2621 // 0x0002 = char (size field *= 1-byte)2622 // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB2623 // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD2624 // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together2625 // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????2626 // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????2627 // * 2 bytes data size field2628 // * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")2629 // all integers are stored BigEndian2630 2631 $NCTGtagName = array(2632 0x00000001 => 'Make',2633 0x00000002 => 'Model',2634 0x00000003 => 'Software',2635 0x00000011 => 'CreateDate',2636 0x00000012 => 'DateTimeOriginal',2637 0x00000013 => 'FrameCount',2638 0x00000016 => 'FrameRate',2639 0x00000022 => 'FrameWidth',2640 0x00000023 => 'FrameHeight',2641 0x00000032 => 'AudioChannels',2642 0x00000033 => 'AudioBitsPerSample',2643 0x00000034 => 'AudioSampleRate',2644 0x02000001 => 'MakerNoteVersion',2645 0x02000005 => 'WhiteBalance',2646 0x0200000b => 'WhiteBalanceFineTune',2647 0x0200001e => 'ColorSpace',2648 0x02000023 => 'PictureControlData',2649 0x02000024 => 'WorldTime',2650 0x02000032 => 'UnknownInfo',2651 0x02000083 => 'LensType',2652 0x02000084 => 'Lens',2653 );2654 2655 $offset = 0;2656 $data = null;2657 $datalength = strlen($atom_data);2658 $parsed = array();2659 while ($offset < $datalength) {2660 $record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4;2661 $data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;2662 $data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;2663 switch ($data_size_type) {2664 case 0x0001: // 0x0001 = flag (size field *= 1-byte)2665 $data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));2666 $offset += ($data_size * 1);2667 break;2668 case 0x0002: // 0x0002 = char (size field *= 1-byte)2669 $data = substr($atom_data, $offset, $data_size * 1);2670 $offset += ($data_size * 1);2671 $data = rtrim($data, "\x00");2672 break;2673 case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB2674 $data = '';2675 for ($i = $data_size - 1; $i >= 0; $i--) {2676 $data .= substr($atom_data, $offset + ($i * 2), 2);2677 }2678 $data = getid3_lib::BigEndian2Int($data);2679 $offset += ($data_size * 2);2680 break;2681 case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD2682 $data = '';2683 for ($i = $data_size - 1; $i >= 0; $i--) {2684 $data .= substr($atom_data, $offset + ($i * 4), 4);2685 }2686 $data = getid3_lib::BigEndian2Int($data);2687 $offset += ($data_size * 4);2688 break;2689 case 0x0005: // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together2690 $data = array();2691 for ($i = 0; $i < $data_size; $i++) {2692 $numerator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));2693 $denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));2694 if ($denomninator == 0) {2695 $data[$i] = false;2696 } else {2697 $data[$i] = (double) $numerator / $denomninator;2698 }2699 }2700 $offset += (8 * $data_size);2701 if (count($data) == 1) {2702 $data = $data[0];2703 }2704 break;2705 case 0x0007: // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????2706 $data = substr($atom_data, $offset, $data_size * 1);2707 $offset += ($data_size * 1);2708 break;2709 case 0x0008: // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????2710 $data = substr($atom_data, $offset, $data_size * 2);2711 $offset += ($data_size * 2);2712 break;2713 default:2714 echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';2715 break 2;2716 }2717 2718 switch ($record_type) {2719 case 0x00000011: // CreateDate2720 case 0x00000012: // DateTimeOriginal2721 $data = strtotime($data);2722 break;2723 case 0x0200001e: // ColorSpace2724 switch ($data) {2725 case 1:2726 $data = 'sRGB';2727 break;2728 case 2:2729 $data = 'Adobe RGB';2730 break;2731 }2732 break;2733 case 0x02000023: // PictureControlData2734 $PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');2735 $FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange', 0x83=>'red', 0x84=>'green', 0xff=>'n/a');2736 $ToningEffect = array(0x80=>'b&w', 0x81=>'sepia', 0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a');2737 $data = array(2738 'PictureControlVersion' => substr($data, 0, 4),2739 'PictureControlName' => rtrim(substr($data, 4, 20), "\x00"),2740 'PictureControlBase' => rtrim(substr($data, 24, 20), "\x00"),2741 //'?' => substr($data, 44, 4),2742 'PictureControlAdjust' => $PictureControlAdjust[ord(substr($data, 48, 1))],2743 'PictureControlQuickAdjust' => ord(substr($data, 49, 1)),2744 'Sharpness' => ord(substr($data, 50, 1)),2745 'Contrast' => ord(substr($data, 51, 1)),2746 'Brightness' => ord(substr($data, 52, 1)),2747 'Saturation' => ord(substr($data, 53, 1)),2748 'HueAdjustment' => ord(substr($data, 54, 1)),2749 'FilterEffect' => $FilterEffect[ord(substr($data, 55, 1))],2750 'ToningEffect' => $ToningEffect[ord(substr($data, 56, 1))],2751 'ToningSaturation' => ord(substr($data, 57, 1)),2752 );2753 break;2754 case 0x02000024: // WorldTime2755 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime2756 // timezone is stored as offset from GMT in minutes2757 $timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2));2758 if ($timezone & 0x8000) {2759 $timezone = 0 - (0x10000 - $timezone);2760 }2761 $timezone /= 60;2762 2763 $dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));2764 switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {2765 case 2:2766 $datedisplayformat = 'D/M/Y'; break;2767 case 1:2768 $datedisplayformat = 'M/D/Y'; break;2769 case 0:2770 default:2771 $datedisplayformat = 'Y/M/D'; break;2772 }2773 2774 $data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);2775 break;2776 case 0x02000083: // LensType2777 $data = array(2778 //'_' => $data,2779 'mf' => (bool) ($data & 0x01),2780 'd' => (bool) ($data & 0x02),2781 'g' => (bool) ($data & 0x04),2782 'vr' => (bool) ($data & 0x08),2783 );2784 break;2785 }2786 $tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));2787 $parsed[$tag_name] = $data;2788 }2789 return $parsed;2790 2668 } 2791 2669 -
trunk/src/wp-includes/ID3/module.audio-video.riff.php
r51901 r52254 57 57 $thisfile_riff_WAVE = array(); 58 58 59 $Original = array(); 59 60 $Original['avdataoffset'] = $info['avdataoffset']; 60 61 $Original['avdataend'] = $info['avdataend']; … … 297 298 $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0]; 298 299 299 $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256)); 300 $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32)); 301 $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32)); 300 $thisfile_riff_WAVE_bext_0['title'] = substr($thisfile_riff_WAVE_bext_0['data'], 0, 256); 301 $thisfile_riff_WAVE_bext_0['author'] = substr($thisfile_riff_WAVE_bext_0['data'], 256, 32); 302 $thisfile_riff_WAVE_bext_0['reference'] = substr($thisfile_riff_WAVE_bext_0['data'], 288, 32); 303 foreach (array('title','author','reference') as $bext_key) { 304 // Some software (notably Logic Pro) may not blank existing data before writing a null-terminated string to the offsets 305 // assigned for text fields, resulting in a null-terminated string (or possibly just a single null) followed by garbage 306 // Keep only string as far as first null byte, discard rest of fixed-width data 307 // https://github.com/JamesHeinrich/getID3/issues/263 308 $null_terminator_offset = strpos($thisfile_riff_WAVE_bext_0[$bext_key], "\x00"); 309 $thisfile_riff_WAVE_bext_0[$bext_key] = substr($thisfile_riff_WAVE_bext_0[$bext_key], 0, $null_terminator_offset); 310 } 311 302 312 $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10); 303 313 $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8); … … 308 318 if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) { 309 319 if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) { 320 $bext_timestamp = array(); 310 321 list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date; 311 322 list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time; … … 452 463 } 453 464 454 465 if (isset($thisfile_riff_WAVE['guan'][0]['data'])) { 466 // shortcut 467 $thisfile_riff_WAVE_guan_0 = &$thisfile_riff_WAVE['guan'][0]; 468 if (!empty($thisfile_riff_WAVE_guan_0['data']) && (substr($thisfile_riff_WAVE_guan_0['data'], 0, 14) == 'GUANO|Version:')) { 469 $thisfile_riff['guano'] = array(); 470 foreach (explode("\n", $thisfile_riff_WAVE_guan_0['data']) as $line) { 471 if ($line) { 472 @list($key, $value) = explode(':', $line, 2); 473 if (substr($value, 0, 3) == '[{"') { 474 if ($decoded = @json_decode($value, true)) { 475 if (!empty($decoded) && (count($decoded) == 1)) { 476 $value = $decoded[0]; 477 } else { 478 $value = $decoded; 479 } 480 } 481 } 482 $thisfile_riff['guano'] = array_merge_recursive($thisfile_riff['guano'], getid3_lib::CreateDeepArray($key, '|', $value)); 483 } 484 } 485 486 // https://www.wildlifeacoustics.com/SCHEMA/GUANO.html 487 foreach ($thisfile_riff['guano'] as $key => $value) { 488 switch ($key) { 489 case 'Loc Position': 490 if (preg_match('#^([\\+\\-]?[0-9]+\\.[0-9]+) ([\\+\\-]?[0-9]+\\.[0-9]+)$#', $value, $matches)) { 491 list($dummy, $latitude, $longitude) = $matches; 492 $thisfile_riff['comments']['gps_latitude'][0] = floatval($latitude); 493 $thisfile_riff['comments']['gps_longitude'][0] = floatval($longitude); 494 $thisfile_riff['guano'][$key] = floatval($latitude).' '.floatval($longitude); 495 } 496 break; 497 case 'Loc Elevation': // Elevation/altitude above mean sea level in meters 498 $thisfile_riff['comments']['gps_altitude'][0] = floatval($value); 499 $thisfile_riff['guano'][$key] = (float) $value; 500 break; 501 case 'Filter HP': // High-pass filter frequency in kHz 502 case 'Filter LP': // Low-pass filter frequency in kHz 503 case 'Humidity': // Relative humidity as a percentage 504 case 'Length': // Recording length in seconds 505 case 'Loc Accuracy': // Estimated Position Error in meters 506 case 'Temperature Ext': // External temperature in degrees Celsius outside the recorder's housing 507 case 'Temperature Int': // Internal temperature in degrees Celsius inside the recorder's housing 508 $thisfile_riff['guano'][$key] = (float) $value; 509 break; 510 case 'Samplerate': // Recording sample rate, Hz 511 case 'TE': // Time-expansion factor. If not specified, then 1 (no time-expansion a.k.a. direct-recording) is assumed. 512 $thisfile_riff['guano'][$key] = (int) $value; 513 break; 514 } 515 } 516 517 } else { 518 $this->warning('RIFF.guan data not in expected format'); 519 } 520 } 455 521 456 522 if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) { … … 734 800 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) { 735 801 if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) { 802 $thisfile_riff_raw_strf_strhfccType_streamindex = null; 736 803 for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) { 737 804 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) { … … 1070 1137 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); 1071 1138 $getid3_temp = new getID3(); 1072 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1139 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1073 1140 $getid3_id3v2 = new getid3_id3v2($getid3_temp); 1074 1141 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8; … … 1173 1240 1174 1241 $getid3_temp = new getID3(); 1175 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1242 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1176 1243 $getid3_mpeg = new getid3_mpeg($getid3_temp); 1177 1244 $getid3_mpeg->Analyze(); … … 1259 1326 1260 1327 $getid3_temp = new getID3(); 1261 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1328 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1262 1329 $getid3_id3v2 = new getid3_id3v2($getid3_temp); 1263 1330 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8; … … 1515 1582 $RIFFchunk = false; 1516 1583 $FoundAllChunksWeNeed = false; 1584 $LISTchunkParent = null; 1585 $LISTchunkMaxOffset = null; 1586 $AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77" 1517 1587 1518 1588 try { … … 1558 1628 if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) { 1559 1629 $getid3_temp = new getID3(); 1560 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1630 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1561 1631 $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; 1562 1632 $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; … … 1576 1646 } 1577 1647 1578 } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) { 1579 1648 } elseif (strpos($FirstFourBytes, $AC3syncwordBytes) === 0) { 1580 1649 // AC3 1581 1650 $getid3_temp = new getID3(); 1582 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1651 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1583 1652 $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; 1584 1653 $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; … … 1641 1710 if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) { 1642 1711 $getid3_temp = new getID3(); 1643 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1712 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1644 1713 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1645 1714 $getid3_temp->info['avdataend'] = $info['avdataend']; … … 1653 1722 } 1654 1723 1655 } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) {1724 } elseif (($isRegularAC3 = (substr($testData, 0, 2) == $AC3syncwordBytes)) || substr($testData, 8, 2) == strrev($AC3syncwordBytes)) { 1656 1725 1657 1726 // This is probably AC-3 data 1658 1727 $getid3_temp = new getID3(); 1659 1728 if ($isRegularAC3) { 1660 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1729 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1661 1730 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1662 1731 $getid3_temp->info['avdataend'] = $info['avdataend']; … … 1674 1743 $ac3_data .= substr($testData, 8 + $i + 0, 1); 1675 1744 } 1745 $getid3_ac3->getid3->info['avdataoffset'] = 0; 1746 $getid3_ac3->getid3->info['avdataend'] = strlen($ac3_data); 1676 1747 $getid3_ac3->AnalyzeString($ac3_data); 1677 1748 } … … 1692 1763 // This is probably DTS data 1693 1764 $getid3_temp = new getID3(); 1694 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1765 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1695 1766 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1696 1767 $getid3_dts = new getid3_dts($getid3_temp); … … 1733 1804 case 'MEXT': 1734 1805 case 'DISP': 1806 case 'wamd': 1807 case 'guan': 1735 1808 // always read data in 1736 1809 case 'JUNK': … … 2077 2150 public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) { 2078 2151 2152 $parsed = array(); 2079 2153 $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure 2080 2154 $parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels -
trunk/src/wp-includes/ID3/module.audio.flac.php
r51901 r52254 403 403 $info = &$this->getid3->info; 404 404 405 $picture = array(); 405 406 $picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4)); 406 407 $picture['picturetype'] = self::pictureTypeLookup($picture['typeid']); -
trunk/src/wp-includes/ID3/module.audio.mp3.php
r51901 r52254 19 19 } 20 20 21 // number of frames to scan to determine if MPEG-audio sequence is valid22 // Lower this number to 5-20 for faster scanning23 // Increase this number to 50+ for most accurate detection of valid VBR/CBR24 // mpeg-audio streams25 define('GETID3_MP3_VALID_CHECK_FRAMES', 35);26 27 21 28 22 class getid3_mp3 extends getid3_handler … … 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 42 * @return bool 40 43 */ … … 56 59 } 57 60 61 $CurrentDataLAMEversionString = null; 58 62 if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) { 59 63 … … 122 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 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 134 $info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString; 125 135 } … … 296 306 297 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 309 } else { 300 310 $encoder_options = strtoupper($info['audio']['bitrate_mode']); … … 489 499 $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray; 490 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 502 return false; 493 503 } … … 723 733 $thisfile_mpeg_audio_lame['long_version'] = substr($headerstring, $VBRidOffset + 120, 20); 724 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']); 726 if (preg_match('#^LAME([0-9\\.a-z]+)#', $thisfile_mpeg_audio_lame['long_version'], $matches)) { 735 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 739 $thisfile_mpeg_audio_lame['short_version'] = $matches[0]; 728 740 $thisfile_mpeg_audio_lame['numeric_version'] = $matches[1]; 729 741 } 730 foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) { 731 $thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number); 732 } 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)); 742 if (strlen($thisfile_mpeg_audio_lame['numeric_version']) > 0) { 743 foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) { 744 $thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number); 787 745 } 788 if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) { 789 unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']); 790 } else { 791 $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']); 746 //if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') { 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 748 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 Type840 $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 // ignore853 } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate854 $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];855 }856 857 // bytes $B1-$B3 Encoder delays858 $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 Misc863 $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 Gain874 $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 info879 $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 out890 $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';891 }892 893 // bytes $B8-$BB MusicLength894 $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 MusicCRC898 $thisfile_mpeg_audio_lame['music_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));899 900 // bytes $BE-$BF CRC-16 of Info Tag901 $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));902 903 904 // LAME CBR905 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 } … … 1009 1022 if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) { 1010 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 … … 1131 1160 $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false); 1132 1161 1133 for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) { 1134 // check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch 1162 $info['mp3_validity_check_bitrates'] = array(); 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 1165 if (($nextframetestoffset + 4) >= $info['avdataend']) { 1136 1166 // end of file … … 1140 1170 $nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); 1141 1171 if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) { 1172 getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][$nextframetestarray['mpeg']['audio']['bitrate']]); 1142 1173 if ($ScanAsCBR) { 1143 1174 // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header … … 1274 1305 $LongMPEGpaddingLookup = array(); 1275 1306 $LongMPEGfrequencyLookup = array(); 1307 $Distribution = array(); 1276 1308 $Distribution['bitrate'] = array(); 1277 1309 $Distribution['frequency'] = array(); … … 1434 1466 $sync_seek_buffer_size = strlen($header); 1435 1467 $SynchSeekOffset = 0; 1468 $SyncSeekAttempts = 0; 1469 $SyncSeekAttemptsMax = 1000; 1470 $FirstFrameThisfileInfo = null; 1436 1471 while ($SynchSeekOffset < $sync_seek_buffer_size) { 1437 1472 if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) { … … 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 1527 $FirstFrameAVDataOffset = null; 1476 1528 if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) { … … 1512 1564 $info = $dummy; 1513 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 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 } … … 1559 1611 for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) { 1560 1612 $frames_scanned_this_segment = 0; 1613 $scan_start_offset = array(); 1561 1614 if ($this->ftell() >= $info['avdataend']) { 1562 1615 break; … … 1888 1941 } 1889 1942 1943 $MPEGrawHeader = array(); 1890 1944 $MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4; 1891 1945 $MPEGrawHeader['version'] = (ord($Header4Bytes[1]) & 0x18) >> 3; // BB -
trunk/src/wp-includes/ID3/module.audio.ogg.php
r51901 r52254 530 530 public function ParseOggPageHeader() { 531 531 // http://xiph.org/ogg/vorbis/doc/framing.html 532 $oggheader = array(); 532 533 $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file 533 534 … … 681 682 $VorbisCommentPage++; 682 683 683 $oggpageinfo = $this->ParseOggPageHeader(); 684 $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; 685 686 // First, save what we haven't read yet 687 $AsYetUnusedData = substr($commentdata, $commentdataoffset); 688 689 // Then take that data off the end 690 $commentdata = substr($commentdata, 0, $commentdataoffset); 691 692 // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct 693 $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); 694 $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); 695 696 // Finally, stick the unused data back on the end 697 $commentdata .= $AsYetUnusedData; 698 699 //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); 700 if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) { 701 $this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell()); 684 if ($oggpageinfo = $this->ParseOggPageHeader()) { 685 $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; 686 687 // First, save what we haven't read yet 688 $AsYetUnusedData = substr($commentdata, $commentdataoffset); 689 690 // Then take that data off the end 691 $commentdata = substr($commentdata, 0, $commentdataoffset); 692 693 // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct 694 $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); 695 $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); 696 697 // Finally, stick the unused data back on the end 698 $commentdata .= $AsYetUnusedData; 699 700 //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); 701 if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) { 702 $this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell()); 703 break; 704 } 705 $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1); 706 if ($readlength <= 0) { 707 $this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell()); 708 break; 709 } 710 $commentdata .= $this->fread($readlength); 711 712 //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset']; 713 } else { 714 $this->warning('failed to ParseOggPageHeader() at offset '.$this->ftell()); 702 715 break; 703 716 } 704 $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);705 if ($readlength <= 0) {706 $this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());707 break;708 }709 $commentdata .= $this->fread($readlength);710 711 //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];712 717 } 713 718 $ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset; -
trunk/src/wp-includes/ID3/module.tag.apetag.php
r51901 r52254 361 361 362 362 // shortcut 363 $headerfooterinfo = array(); 363 364 $headerfooterinfo['raw'] = array(); 364 365 $headerfooterinfo_raw = &$headerfooterinfo['raw']; … … 390 391 // All are set to zero on creation and ignored on reading." 391 392 // http://wiki.hydrogenaud.io/index.php?title=Ape_Tags_Flags 393 $flags = array(); 392 394 $flags['header'] = (bool) ($rawflagint & 0x80000000); 393 395 $flags['footer'] = (bool) ($rawflagint & 0x40000000); -
trunk/src/wp-includes/ID3/module.tag.id3v1.php
r51901 r52254 32 32 } 33 33 34 $this->fseek(-256, SEEK_END); 35 $preid3v1 = $this->fread(128); 36 $id3v1tag = $this->fread(128); 34 if($info['filesize'] < 256) { 35 $this->fseek(-128, SEEK_END); 36 $preid3v1 = ''; 37 $id3v1tag = $this->fread(128); 38 } else { 39 $this->fseek(-256, SEEK_END); 40 $preid3v1 = $this->fread(128); 41 $id3v1tag = $this->fread(128); 42 } 43 37 44 38 45 if (substr($id3v1tag, 0, 3) == 'TAG') { … … 40 47 $info['avdataend'] = $info['filesize'] - 128; 41 48 49 $ParsedID3v1 = array(); 42 50 $ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30)); 43 51 $ParsedID3v1['artist'] = $this->cutfield(substr($id3v1tag, 33, 30)); … … 298 306 146 => 'JPop', 299 307 147 => 'Synthpop', 308 148 => 'Abstract', 309 149 => 'Art Rock', 310 150 => 'Baroque', 311 151 => 'Bhangra', 312 152 => 'Big Beat', 313 153 => 'Breakbeat', 314 154 => 'Chillout', 315 155 => 'Downtempo', 316 156 => 'Dub', 317 157 => 'EBM', 318 158 => 'Eclectic', 319 159 => 'Electro', 320 160 => 'Electroclash', 321 161 => 'Emo', 322 162 => 'Experimental', 323 163 => 'Garage', 324 164 => 'Global', 325 165 => 'IDM', 326 166 => 'Illbient', 327 167 => 'Industro-Goth', 328 168 => 'Jam Band', 329 169 => 'Krautrock', 330 170 => 'Leftfield', 331 171 => 'Lounge', 332 172 => 'Math Rock', 333 173 => 'New Romantic', 334 174 => 'Nu-Breakz', 335 175 => 'Post-Punk', 336 176 => 'Post-Rock', 337 177 => 'Psytrance', 338 178 => 'Shoegaze', 339 179 => 'Space Rock', 340 180 => 'Trop Rock', 341 181 => 'World Music', 342 182 => 'Neoclassical', 343 183 => 'Audiobook', 344 184 => 'Audio Theatre', 345 185 => 'Neue Deutsche Welle', 346 186 => 'Podcast', 347 187 => 'Indie-Rock', 348 188 => 'G-Funk', 349 189 => 'Dubstep', 350 190 => 'Garage Rock', 351 191 => 'Psybient', 300 352 301 353 255 => 'Unknown', -
trunk/src/wp-includes/ID3/module.tag.id3v2.php
r51901 r52254 346 346 if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) { 347 347 348 unset($parsedFrame);348 $parsedFrame = array(); 349 349 $parsedFrame['frame_name'] = $frame_name; 350 350 $parsedFrame['frame_flags_raw'] = $frame_flags; … … 979 979 980 980 } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription 981 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) { 981 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription 982 982 // There may be more than one 'Unsynchronised lyrics/text transcription' frame 983 983 // in each tag, but only one with the same language and content descriptor. … … 995 995 $frame_textencoding_terminator = "\x00"; 996 996 } 997 $frame_language = substr($parsedFrame['data'], $frame_offset, 3); 998 $frame_offset += 3; 999 $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); 1000 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 1001 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 1002 } 1003 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1004 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 1005 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); 1006 $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator); 1007 1008 $parsedFrame['encodingid'] = $frame_textencoding; 1009 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); 1010 1011 $parsedFrame['language'] = $frame_language; 1012 $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); 1013 if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { 1014 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); 997 if (strlen($parsedFrame['data']) >= (4 + strlen($frame_textencoding_terminator))) { // shouldn't be an issue but badly-written files have been spotted in the wild with not only no contents but also missing the required language field, see https://github.com/JamesHeinrich/getID3/issues/315 998 $frame_language = substr($parsedFrame['data'], $frame_offset, 3); 999 $frame_offset += 3; 1000 $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); 1001 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 1002 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 1003 } 1004 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1005 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 1006 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); 1007 $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator); 1008 1009 $parsedFrame['encodingid'] = $frame_textencoding; 1010 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); 1011 1012 $parsedFrame['language'] = $frame_language; 1013 $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); 1014 if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { 1015 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); 1016 } 1017 } else { 1018 $this->warning('Invalid data in frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset']); 1015 1019 } 1016 1020 unset($parsedFrame['data']); … … 1371 1375 } 1372 1376 1377 $frame_imagetype = null; 1378 $frame_mimetype = null; 1373 1379 if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) { 1374 1380 $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3); … … 1957 1963 $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4)); 1958 1964 $frame_offset += 4; 1959 $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2)); 1960 $frame_offset += 2; 1961 $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2)); 1962 $frame_offset += 2; 1963 $parsedFrame['raw']['track']['name'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3)); 1964 $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3)); 1965 $parsedFrame['raw']['track']['signbit'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1)); 1966 $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9)); 1967 $parsedFrame['raw']['album']['name'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3)); 1968 $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3)); 1969 $parsedFrame['raw']['album']['signbit'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1)); 1970 $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9)); 1965 foreach (array('track','album') as $rgad_entry_type) { 1966 $rg_adjustment_word = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); 1967 $frame_offset += 2; 1968 $parsedFrame['raw'][$rgad_entry_type]['name'] = ($rg_adjustment_word & 0xE000) >> 13; 1969 $parsedFrame['raw'][$rgad_entry_type]['originator'] = ($rg_adjustment_word & 0x1C00) >> 10; 1970 $parsedFrame['raw'][$rgad_entry_type]['signbit'] = ($rg_adjustment_word & 0x0200) >> 9; 1971 $parsedFrame['raw'][$rgad_entry_type]['adjustment'] = ($rg_adjustment_word & 0x0100); 1972 } 1971 1973 $parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']); 1972 1974 $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']); … … 2445 2447 TND Dinars 2446 2448 TOP Pa'anga 2447 TRL Liras 2449 TRL Liras (old) 2450 TRY Liras 2448 2451 TTD Dollars 2449 2452 TVD Tuvalu Dollars … … 2646 2649 TOP Tonga 2647 2650 TRL Turkey 2651 TRY Turkey 2648 2652 TTD Trinidad and Tobago 2649 2653 TVD Tuvalu -
trunk/src/wp-includes/ID3/module.tag.lyrics3.php
r51901 r52254 34 34 35 35 $this->fseek((0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size] 36 $lyrics3offset = null; 37 $lyrics3version = null; 38 $lyrics3size = null; 36 39 $lyrics3_id3v1 = $this->fread(128 + 9 + 6); 37 40 $lyrics3lsz = (int) substr($lyrics3_id3v1, 0, 6); // Lyrics3size -
trunk/src/wp-includes/ID3/readme.txt
r51901 r52254 626 626 * http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header 627 627 * http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf 628 * https://fileformats.fandom.com/wiki/Torrent_file
Note: See TracChangeset
for help on using the changeset viewer.